]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
- Simplified the sweep of instrumentation in strategies._register_attribute
authorMike Bayer <mike_mp@zzzcomputing.com>
Sun, 2 Aug 2009 17:51:33 +0000 (17:51 +0000)
committerMike Bayer <mike_mp@zzzcomputing.com>
Sun, 2 Aug 2009 17:51:33 +0000 (17:51 +0000)
- Improved support for MapperProperty objects overriding
that of an inherited mapper for non-concrete
inheritance setups - attribute extensions won't randomly
collide with each other.  [ticket:1488]

- Added AttributeExtension to sqlalchemy.orm.__all__

CHANGES
lib/sqlalchemy/orm/__init__.py
lib/sqlalchemy/orm/mapper.py
lib/sqlalchemy/orm/strategies.py
test/orm/test_mapper.py

diff --git a/CHANGES b/CHANGES
index 8abf88dffd9acd40e4032177df118caa40c55069..447577f9de9ab3aeb235e46667fb73d484846c96 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -31,6 +31,13 @@ CHANGES
       inheritance attributes which were based on 
       column_property() or similar would fail to evaluate.
       [ticket:1480]
+    
+    - Improved support for MapperProperty objects overriding
+      that of an inherited mapper for non-concrete 
+      inheritance setups - attribute extensions won't randomly
+      collide with each other.  [ticket:1488]
+    
+    - Added AttributeExtension to sqlalchemy.orm.__all__
       
     - Improved error message when query() is called with
       a non-SQL /entity expression. [ticket:1476]
index 4c4ec8513cea5874fc96cd08ccd6ba371ae22bb7..2a20b05ef8430f05c370ae9b637bd28337fe51c5 100644 (file)
@@ -26,6 +26,7 @@ from sqlalchemy.orm.interfaces import (
      MapperExtension,
      PropComparator,
      SessionExtension,
+     AttributeExtension,
      )
 from sqlalchemy.orm.util import (
      AliasedClass as aliased,
@@ -61,6 +62,7 @@ __all__ = (
     'EXT_STOP',
     'InstrumentationManager',
     'MapperExtension',
+    'AttributeExtension',
     'Validator',
     'PropComparator',
     'Query',
index d53faacf711ee04610a25e37b7a4dae521c49d01..078056a01c4272bdedac424871ce655ab163bad4 100644 (file)
@@ -649,6 +649,9 @@ class Mapper(object):
                         return self
 
                     # initialize properties on all mappers
+                    # note that _mapper_registry is unordered, which 
+                    # may randomly conceal/reveal issues related to 
+                    # the order of mapper compilation
                     for mapper in list(_mapper_registry):
                         if getattr(mapper, '_compile_failed', False):
                             raise sa_exc.InvalidRequestError("One or more mappers failed to compile.  Exception was probably "
index 1da2231a3af325f1d66b9e608ebed74d5d59c131..f739fb1dd0ac44c603b77c35bf905f6308d19587 100644 (file)
@@ -45,9 +45,10 @@ def _register_attribute(strategy, mapper, useobject,
     
     if useobject:
         attribute_ext.append(sessionlib.UOWEventHandler(prop.key))
-
+    
     for m in mapper.polymorphic_iterator():
-        if (m is prop.parent or not m.concrete) and m.has_property(prop.key):
+        if prop is m._props.get(prop.key):
+            
             attributes.register_attribute_impl(
                 m.class_, 
                 prop.key, 
index edde2a7565dd04ed28988bab248ed4ee1e24d177..13913578a55b8c0d2d0de07628bbea0a5f830031 100644 (file)
@@ -2219,6 +2219,64 @@ class NoLoadTest(_fixtures.FixtureTest):
             )
 
 
+class AttributeExtensionTest(_base.MappedTest):
+    @classmethod
+    def define_tables(cls, metadata):
+        Table('t1', 
+            metadata,
+            Column('id', Integer, primary_key=True),
+            Column('type', String(40)),
+            Column('data', String(50))
+            
+        )
+
+    @testing.resolve_artifact_names
+    def test_cascading_extensions(self):
+        ext_msg = []
+        
+        class Ex1(sa.orm.AttributeExtension):
+            def set(self, state, value, oldvalue, initiator):
+                ext_msg.append("Ex1 %r" % value)
+                return "ex1" + value
+                
+        class Ex2(sa.orm.AttributeExtension):
+            def set(self, state, value, oldvalue, initiator):
+                ext_msg.append("Ex2 %r" % value)
+                return "ex2" + value
+        
+        class A(_base.BasicEntity):
+            pass
+        class B(A):
+            pass
+        class C(B):
+            pass
+            
+        mapper(A, t1, polymorphic_on=t1.c.type, polymorphic_identity='a', properties={
+            'data':column_property(t1.c.data, extension=Ex1())
+        })
+        mapper(B, polymorphic_identity='b', inherits=A)
+        mc = mapper(C, polymorphic_identity='c', inherits=B, properties={
+            'data':column_property(t1.c.data, extension=Ex2())
+        })
+        
+        a1 = A(data='a1')
+        b1 = B(data='b1')
+        c1 = C(data='c1')
+        
+        eq_(a1.data, 'ex1a1')
+        eq_(b1.data, 'ex1b1')
+        eq_(c1.data, 'ex2c1')
+        
+        a1.data = 'a2'
+        b1.data='b2'
+        c1.data = 'c2'
+        eq_(a1.data, 'ex1a2')
+        eq_(b1.data, 'ex1b2')
+        eq_(c1.data, 'ex2c2')
+        
+        eq_(ext_msg, ["Ex1 'a1'", "Ex1 'b1'", "Ex2 'c1'", "Ex1 'a2'", "Ex1 'b2'", "Ex2 'c2'"])
+        
+    
 class MapperExtensionTest(_fixtures.FixtureTest):
     run_inserts = None