- global "propigate"->"propagate" change.
- orm
+ - Adjustments to the enhanced garbage collection on
+ InstanceState to better guard against errors due
+ to lost state.
+
- Query.get() returns a more informative
error message when executed against multiple entities.
[ticket:1220]
runid = None
expired_attributes = EMPTY_SET
insert_order = None
- dict = None
def __init__(self, obj, manager):
self.class_ = obj.__class__
def dispose(self):
if self.session_id:
del self.session_id
- del self.dict
del self.obj
+ del self.dict
def _cleanup(self, ref):
self.dispose()
def obj(self):
return None
-
+
+ @util.memoized_property
+ def dict(self):
+ # return a blank dict
+ # if none is available, so that asynchronous gc
+ # doesn't blow up expiration operations in progress
+ # (usually expire_attributes)
+ return {}
+
@property
def sort_key(self):
return self.key and self.key[1] or self.insert_order
if key not in self.committed_state and key not in self.dict)
def expire_attributes(self, attribute_names):
- if self.dict is None:
- return
-
self.expired_attributes = set(self.expired_attributes)
if attribute_names is None:
from testlib import *
from testlib.testing import eq_
from orm import _base
+import gc
# global for pickling tests
MyTest = None
self.assert_(len(o4.mt2) == 1)
self.assert_(o4.mt2[0].a == 'abcde')
self.assert_(o4.mt2[0].b is None)
-
+
+ def test_state_gc(self):
+ """test that InstanceState always has a dict, even after host object gc'ed."""
+
+ class Foo(object):
+ pass
+
+ attributes.register_class(Foo)
+ f = Foo()
+ state = attributes.instance_state(f)
+ f.bar = "foo"
+ assert state.dict == {'bar':'foo', state.manager.STATE_ATTR:state}
+ del f
+ gc.collect()
+ assert state.obj() is None
+ assert state.dict == {}
+
def test_deferred(self):
class Foo(object):pass