[sqlalchemy] Re: Readonly objects/protecting objects from modifications
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
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
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
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
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 -~--~~~~--~~--~--~---