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

Reply via email to