]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
- Adjustments to the enhanced garbage collection on
authorMike Bayer <mike_mp@zzzcomputing.com>
Tue, 11 Nov 2008 01:52:42 +0000 (01:52 +0000)
committerMike Bayer <mike_mp@zzzcomputing.com>
Tue, 11 Nov 2008 01:52:42 +0000 (01:52 +0000)
InstanceState to better guard against errors due
to lost state.

CHANGES
lib/sqlalchemy/orm/attributes.py
test/orm/attributes.py

diff --git a/CHANGES b/CHANGES
index a05bfa4557b2ca1d37b226e780488a880c7ad4df..ecb85e60ef59e00648da67c78b7be6a8acfbc49a 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -26,6 +26,10 @@ CHANGES
     - 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]
index e80392d0ccde775bbed7f982f249fbd5822a96a9..662ea05d3c5b73354fdd5865e00921dda2a7f348 100644 (file)
@@ -799,7 +799,6 @@ class InstanceState(object):
     runid = None
     expired_attributes = EMPTY_SET
     insert_order = None
-    dict = None
     
     def __init__(self, obj, manager):
         self.class_ = obj.__class__
@@ -820,15 +819,23 @@ class InstanceState(object):
     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
@@ -969,9 +976,6 @@ class InstanceState(object):
             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:
index 3fe2294c493627ea73c9a5eee9c88b8662ca96dd..e2484d17d45df9a325e380137ab67b795277a107 100644 (file)
@@ -7,6 +7,7 @@ from sqlalchemy import exc as sa_exc
 from testlib import *
 from testlib.testing import eq_
 from orm import _base
+import gc
 
 # global for pickling tests
 MyTest = None
@@ -102,7 +103,23 @@ class AttributesTest(_base.ORMTest):
         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