On May 17, 2007, at 5:31 PM, Catherine wrote:
>
> I noticed an issue that - well, I honestly don't know whether to call
> it a "bug" or not. I need to talk it out with somebody who
> understands SQLA better.
>
> When I retrieve an instance, then alter its attributes by manipulating
> its __dict__, the instance doesn't get "dirtied", and the changes
> won't be sent to the database when I flush the session.
a lot more than that breaks, in fact.
>
> I can work around the problem pretty easily, like this:
> exec(operation, employee.__dict__)
> employee._state['modified'] = True
>
> That change to ._state normally happens in
> InstrumentedAttribute.__set__ in sqlalchemy/orm/attributes.py (line
> 263), which gets called for "instance.attribute = newvalue", but not
> for "instance.__dict__['attribute'] = newvalue".
well _state is a private attribute which isnt guaranteed to stay that
way in future versions.
>
> I'm wondering if I should just sit on this workaround personally, or
> dig into figuring out how to modify SQLA so it will always work for
> __dict__ manipulation.
>
> So - is direct manipulation of the __dict__ something that SQLA should
> support, or would that fall in the realm of "you are getting weird on
> us, you're on your own"? I guess that double-underscore sort of
> implies "you're on your own", but __dict__ manipulation doesn't seem
> overly exotic in practice.
the entire method of attribute instrumentation is via property
objects added to your classes (in fact they are instances of
InstrumentedAttribute). the __dict__ is how to get at the instance
attributes while bypassing the attribute instrumentation entirely.
while the "_state" hack works right now, and there is an additional
way it might work which would be to set the "mutable_scalars" flag to
True on all the InstrumentedAttribute objects (thereby ignoring the
_state flag), both of those methods still break all the cascade
functionality and backref functionality, and will also return the
wrong list set of deltas in the case of un-lazyloaded attributes that
get set directly via __dict__. i.e. the attributes package is
largely event-based and theres no event listening on __dict__
directly. a rewrite would involve replacing the __dict__ of all
instances with a custom dictionary that does everything, something i
understand is a Python no-no (and also makes the instrumentation that
much more opaque, since theres no "bypass" level anymore).
the cleanest solution of all is just to replace your call to:
myinstance.__dict__
with a proxying dict:
class MyDict(dict):
def __init__(self, obj):
self.obj = obj
def __getitem__(self, key):
return getattr(self.obj, key)
def __setitem__(self, key, value):
setattr(self.obj, key, value)
def keys(self):
return self.obj.__dict__.keys()
# etc ..
MyDict(myinstance)
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups
"sqlalchemy" group.
To post to this group, send email to [email protected]
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
-~----------~----~----~----~------~----~------~--~---