[sqlalchemy] Re: Readonly objects/protecting objects from modifications

2008-01-18 Thread klaus

Hi all,
it's only now that I came across this interesting discussion.

I tried similar things but what I wanted to protect was my cached
data. And session.merge(obj, dont_load=True) triggers these
AssertionErrors. :-(

So I went for a MapperExtension instead. The after_update method can
still prevent changes from being committed to the database. This
solution is not very elegant, however.

Best regards
Klaus


On 22 Dez. 2007, 17:03, Michael Bayer [EMAIL PROTECTED]
wrote:
 On Dec 22, 2007, at 12:34 AM, Andreas Jung wrote:





  --On 21. Dezember 2007 16:33:34 -0500 Michael Bayer [EMAIL PROTECTED]
   wrote:

  On Dec 21, 2007, at 3:13 PM, Rick Morrison wrote:

  I think the only way something like this should be done is as a test
  fixture which decorates classes during unit tests.It would be
  fairly clumsy to have in production code.

  If you have coworkers who write broken code, the way you solve that
  is
  by having unit tests which will fail when the coworkers in question
  do
  something theyre not supposed to.   If other people are writing code
  that sets attrbutes its not supposed to and breaks things, you need
  more tests to catch those conditions.  If youre putting code into
  production that hasnt been tested, then you need a build process,
  automated testing, etc.There is definitely a best practice here
  and test driven development is it.

  With all respect, this is not a useful answer. Even with tests
  (unittests and weeks of manual tests) I had the case that a simple
  programming error
  (of my own) produced a data disaster after some weeks. There is no
  100% test coverage. Tests don't solve all problems. There is
  sometimes the need for a better security belt.

 I am certainly suggesting a fixture that detects illegal assignments
 to attributes.  That it be limited to just unit tests is only a
 suggestion.To establish this functionality regardless of
 environment, like Rick said just create properties which prohibit
 assignment.  Create mappers like this:

 class AttrGetter(object):
  def __init__(self, name):
  self.name = name
  def __get__(self, instance, name):
  if instance is None:
  return self
  return getattr(instance, '_' + name)
  def __set__(self, instance, value):
  raise AssertionError(Sets are not allowed)
  def __delete__(self, instance):
  raise AssertionError(Deletes are not allowed)

 class MyClass(object):
 somecolumn = AttrGetter('somecolumn')
  someothercolumn = AttrGetter('someothercolumn')

 mapper(MyClass, sometable, properties={
 '_somecolumn':sometable.c.somecolumn,
 '_someothercolumn':sometable.c.someothercolumn

 })

 To automate the above process with no modifications to source code,
 create an instrumented mapper() function which applies the above
 recipe to all table columns:

 from sqlalchemy.orm import mapper as _mapper
 def mapper(cls, table, **kwargs):
  attrs = {}
  for c in table.c:
  attrs['_' + c.key] = c
  setattr(cls, c.key, AttrGetter(c.key))
  properties = kwargs.setdefault('properties', {})
  properties.update(attrs)
  return _mapper(cls, table, **kwargs)

 Hope this helps.
--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
sqlalchemy group.
To post to this group, send email to sqlalchemy@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en
-~--~~~~--~~--~--~---



[sqlalchemy] Re: Readonly objects/protecting objects from modifications

2007-12-22 Thread Michael Bayer


On Dec 22, 2007, at 12:34 AM, Andreas Jung wrote:



 --On 21. Dezember 2007 16:33:34 -0500 Michael Bayer [EMAIL PROTECTED] 
  wrote:


 On Dec 21, 2007, at 3:13 PM, Rick Morrison wrote:



 I think the only way something like this should be done is as a test
 fixture which decorates classes during unit tests.It would be
 fairly clumsy to have in production code.

 If you have coworkers who write broken code, the way you solve that  
 is
 by having unit tests which will fail when the coworkers in question  
 do
 something theyre not supposed to.   If other people are writing code
 that sets attrbutes its not supposed to and breaks things, you need
 more tests to catch those conditions.  If youre putting code into
 production that hasnt been tested, then you need a build process,
 automated testing, etc.There is definitely a best practice here
 and test driven development is it.

 With all respect, this is not a useful answer. Even with tests  
 (unittests and weeks of manual tests) I had the case that a simple  
 programming error
 (of my own) produced a data disaster after some weeks. There is no  
 100% test coverage. Tests don't solve all problems. There is  
 sometimes the need for a better security belt.


I am certainly suggesting a fixture that detects illegal assignments  
to attributes.  That it be limited to just unit tests is only a  
suggestion.To establish this functionality regardless of  
environment, like Rick said just create properties which prohibit  
assignment.  Create mappers like this:

class AttrGetter(object):
 def __init__(self, name):
 self.name = name
 def __get__(self, instance, name):
 if instance is None:
 return self
 return getattr(instance, '_' + name)
 def __set__(self, instance, value):
 raise AssertionError(Sets are not allowed)
 def __delete__(self, instance):
 raise AssertionError(Deletes are not allowed)

class MyClass(object):
somecolumn = AttrGetter('somecolumn')
 someothercolumn = AttrGetter('someothercolumn')

mapper(MyClass, sometable, properties={
'_somecolumn':sometable.c.somecolumn,
'_someothercolumn':sometable.c.someothercolumn
})

To automate the above process with no modifications to source code,  
create an instrumented mapper() function which applies the above  
recipe to all table columns:

from sqlalchemy.orm import mapper as _mapper
def mapper(cls, table, **kwargs):
 attrs = {}
 for c in table.c:
 attrs['_' + c.key] = c
 setattr(cls, c.key, AttrGetter(c.key))
 properties = kwargs.setdefault('properties', {})
 properties.update(attrs)
 return _mapper(cls, table, **kwargs)


Hope this helps.

--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
sqlalchemy group.
To post to this group, send email to sqlalchemy@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en
-~--~~~~--~~--~--~---



[sqlalchemy] Re: Readonly objects/protecting objects from modifications

2007-12-21 Thread Rick Morrison
Something like this is available on a roll-your-own basis via Python
properties along with some mapper tricks:


http://www.sqlalchemy.org/docs/04/mappers.html#advdatamapping_mapper_overriding

I would be +1 for such a feature implemented on mapped instances, could be
useful for detecting those hard-to-find bugs, but I can't think of a nice
and simple API for it. For mapped instances via Query(), it  could be an
.option(), but I can't see a good way for its use on relation()s. Also not
sure if such a feature would throw an exception on attribute setting, or
whether it ought to simply be ingored during a flush (OIOW, have it's
dirty flag locked down to False)

--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
sqlalchemy group.
To post to this group, send email to sqlalchemy@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en
-~--~~~~--~~--~--~---



[sqlalchemy] Re: Readonly objects/protecting objects from modifications

2007-12-21 Thread sdobrev

i have such thing implemented externaly but it is definitely not nice (read: 
tricky and underground) - replacing the __dict__ with something handmade 
that does what i say as i say if i say. that's dbcook's reflector for my 
static_type structures; look in dbcook/usage/static_type if interested. and 
it is now broken with the latest instance_state handling mechanism.

another, similar or not, feature i needed while doing dbcook, was a 
readonly/loadonly mapper; i.e. a mapper for a sort-of intermediate 
base-class which should not have its own instances; only subclasses may have 
instances/DB-footprint. That i made via MapperExt, throwing at 
before_insert/update/delete.

Rick Morrison wrote:
 Something like this is available on a roll-your-own basis via Python
 properties along with some mapper tricks:
 
 
 http://www.sqlalchemy.org/docs/04/mappers.html#advdatamapping_mapper_overriding
 
 I would be +1 for such a feature implemented on mapped instances, could be
 useful for detecting those hard-to-find bugs, but I can't think of a nice
 and simple API for it. For mapped instances via Query(), it  could be an
 .option(), but I can't see a good way for its use on relation()s. Also not
 sure if such a feature would throw an exception on attribute setting, or
 whether it ought to simply be ingored during a flush (OIOW, have it's
 dirty flag locked down to False)


--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
sqlalchemy group.
To post to this group, send email to sqlalchemy@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en
-~--~~~~--~~--~--~---



[sqlalchemy] Re: Readonly objects/protecting objects from modifications

2007-12-21 Thread Michael Bayer

On Dec 21, 2007, at 3:13 PM, Rick Morrison wrote:

 Something like this is available on a roll-your-own basis via Python  
 properties along with some mapper tricks:


 http://www.sqlalchemy.org/docs/04/mappers.html#advdatamapping_mapper_overriding

 I would be +1 for such a feature implemented on mapped instances,  
 could be useful for detecting those hard-to-find bugs, but I can't  
 think of a nice and simple API for it. For mapped instances via  
 Query(), it  could be an .option(), but I can't see a good way for  
 its use on relation()s. Also not sure if such a feature would throw  
 an exception on attribute setting, or whether it ought to simply be  
 ingored during a flush (OIOW, have it's dirty flag locked down to  
 False)



I think the only way something like this should be done is as a test  
fixture which decorates classes during unit tests.It would be  
fairly clumsy to have in production code.

If you have coworkers who write broken code, the way you solve that is  
by having unit tests which will fail when the coworkers in question do  
something theyre not supposed to.   If other people are writing code  
that sets attrbutes its not supposed to and breaks things, you need  
more tests to catch those conditions.  If youre putting code into  
production that hasnt been tested, then you need a build process,  
automated testing, etc.There is definitely a best practice here  
and test driven development is it.
--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
sqlalchemy group.
To post to this group, send email to sqlalchemy@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en
-~--~~~~--~~--~--~---