]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
- Fixed @on_reconsitute hook for subclasses
authorMike Bayer <mike_mp@zzzcomputing.com>
Fri, 8 Aug 2008 05:13:23 +0000 (05:13 +0000)
committerMike Bayer <mike_mp@zzzcomputing.com>
Fri, 8 Aug 2008 05:13:23 +0000 (05:13 +0000)
which inherit from a base class.
[ticket:1129]

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

diff --git a/CHANGES b/CHANGES
index a5258ceacffd04cea161dd3db5bb52d1c35a465b..30b0baae5d907ac1a0bd812412b5ca31eee9010a 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -21,6 +21,10 @@ CHANGES
       list of entities.  In particular scalar subqueries
       should not "leak" their inner FROM objects out
       into the enclosing query.
+    
+    - Fixed @on_reconsitute hook for subclasses 
+      which inherit from a base class.
+      [ticket:1129]
       
 - sql
     - Temporarily rolled back the "ORDER BY" enhancement
index 5904247596ee5a74571fc012266425ce88093f76..ee05625a91c21b9b602d1c51a9da0e99267b9aa5 100644 (file)
@@ -26,6 +26,7 @@ from sqlalchemy import util
 from sqlalchemy.util import EMPTY_SET
 from sqlalchemy.orm import interfaces, collections, exc
 import sqlalchemy.exceptions as sa_exc
+import types
 
 # lazy imports
 _entity_info = None
@@ -1055,9 +1056,15 @@ class ClassManager(dict):
         self._instantiable = False
         self.events = self.event_registry_factory()
 
-        for meth in class_.__dict__.values():
-            if hasattr(meth, '_sa_reconstitute'):
-                self.events.add_listener('on_load', meth)
+        # TODO: generalize (and document the rationalization for) this traversal.
+        # TODO: figure out why getattr(cls, key) for all attributes
+        # causes test failures
+        for cls in class_.__mro__[0:-1]:
+            for key, meth in cls.__dict__.iteritems():
+                if isinstance(meth, types.FunctionType) and \
+                    hasattr(meth, '__sa_reconstitute__') and \
+                    hasattr(getattr(class_, key), '__sa_reconstitute__'):
+                    self.events.add_listener('on_load', meth)
 
     def instantiable(self, boolean):
         # experiment, probably won't stay in this form
@@ -1473,7 +1480,7 @@ def on_reconstitute(fn):
     to MapperExtension.on_reconstitute().
 
     """
-    fn._sa_reconstitute = True
+    fn.__sa_reconstitute__ = True
     return fn
     
     
index 732e65fb73ebde6d63feb9cef81ac4cf4ac3ac7a..06f4f3dadffe165ad1da0cfab3c3861cef9c30ad 100644 (file)
@@ -618,6 +618,7 @@ class Mapper(object):
             cls = object.__getattribute__(self, 'class_')
             clskey = object.__getattribute__(self, 'key')
 
+            # ugly hack
             if key.startswith('__') and key != '__clause_element__':
                 return object.__getattribute__(self, key)
 
index eba9a942236a389fd96d6400292e54393c1a267d..5f224955e7041554d86c6fd8a953158354834a24 100644 (file)
@@ -315,5 +315,20 @@ class ReconstituteTest(testing.TestBase):
         s._run_on_load(m)
         assert recon == ['go']
 
+    def test_inheritance(self):
+        recon = []
+        class MyBaseClass(object):
+            @attributes.on_reconstitute
+            def recon(self):
+                recon.append('go')
+        
+        class MySubClass(MyBaseClass):
+            pass
+        attributes.register_class(MySubClass)
+        m = attributes.manager_of_class(MySubClass).new_instance()
+        s = attributes.instance_state(m)
+        s._run_on_load(m)
+        assert recon == ['go']
+
 if __name__ == '__main__':
     testing.main()