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 -~----------~----~----~----~------~----~------~--~---