]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
- Mutable collection passed to the "extension" attribute
authorMike Bayer <mike_mp@zzzcomputing.com>
Fri, 23 Oct 2009 19:46:36 +0000 (19:46 +0000)
committerMike Bayer <mike_mp@zzzcomputing.com>
Fri, 23 Oct 2009 19:46:36 +0000 (19:46 +0000)
of relation(), column_property() etc. will not be mutated
or shared among multiple instrumentation calls, preventing
duplicate extensions, such as backref populators,
from being inserted into the list.
[ticket:1585]

CHANGES
lib/sqlalchemy/orm/properties.py
lib/sqlalchemy/orm/strategies.py
test/orm/test_mapper.py

diff --git a/CHANGES b/CHANGES
index fb16947b28d3267ff2daebd578eba67c04a3b534..09214ce19ce7b48dce5c73571b37365c351fa2c9 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -23,6 +23,13 @@ CHANGES
       by contains_eager() out of individual instance states.
       [ticket:1553]
 
+    - Mutable collection passed to the "extension" attribute
+      of relation(), column_property() etc. will not be mutated
+      or shared among multiple instrumentation calls, preventing
+      duplicate extensions, such as backref populators,
+      from being inserted into the list.
+      [ticket:1585]
+      
 - sql
     - Fixed the "numeric" paramstyle, which apparently is the
       default paramstyle used by Informixdb.
index 0fa32f73f64e1317b817563263a5781f18bce394..3453342a87cd9d524a3eb912c4d6910cdbf0fe85 100644 (file)
@@ -1019,7 +1019,7 @@ class RelationProperty(StrategizedProperty):
         # primary property handler, set up class attributes
         if self.is_primary():
             if self.back_populates:
-                self.extension = util.to_list(self.extension) or []
+                self.extension = list(util.to_list(self.extension, default=[]))
                 self.extension.append(attributes.GenericBackrefExtension(self.back_populates))
                 self._add_reverse_property(self.back_populates)
             
index 38073811b3835ba4e3a081216ea438b08db9fa01..68669a1502716bf68b5306e58c45fbcaed5ecc37 100644 (file)
@@ -32,7 +32,7 @@ def _register_attribute(strategy, mapper, useobject,
 ):
 
     prop = strategy.parent_property
-    attribute_ext = util.to_list(prop.extension) or []
+    attribute_ext = list(util.to_list(prop.extension, default=[]))
         
     if useobject and prop.single_parent:
         attribute_ext.append(_SingleParentValidator(prop))
index 5cf20beb9641b5bb0bf4fbab7dff41bbfa125e88..4ba05daed2abce36e5f32266f964035dc83400f7 100644 (file)
@@ -8,7 +8,7 @@ from sqlalchemy.test.schema import Table
 from sqlalchemy.test.schema import Column
 from sqlalchemy.engine import default
 from sqlalchemy.orm import mapper, relation, backref, create_session, class_mapper, compile_mappers, reconstructor, validates, aliased
-from sqlalchemy.orm import defer, deferred, synonym, attributes, column_property, composite, relation, dynamic_loader, comparable_property
+from sqlalchemy.orm import defer, deferred, synonym, attributes, column_property, composite, relation, dynamic_loader, comparable_property,AttributeExtension
 from sqlalchemy.test.testing import eq_, AssertsCompiledSQL
 from test.orm import _base, _fixtures
 from sqlalchemy.test.assertsql import AllOf, CompiledSQL
@@ -259,6 +259,28 @@ class MapperTest(_fixtures.FixtureTest):
         mapper(Foo, addresses, inherits=User)
         assert getattr(Foo().__class__, 'name').impl is not None
 
+    @testing.resolve_artifact_names
+    def test_extension_collection_frozen(self):
+        class Foo(User):pass
+        m = mapper(User, users)
+        mapper(Order, orders)
+        compile_mappers()
+        mapper(Foo, addresses, inherits=User)
+        ext_list = [AttributeExtension()]
+        m.add_property('somename', column_property(users.c.name, extension=ext_list))
+        m.add_property('orders', relation(Order, extension=ext_list, backref='user'))
+        assert len(ext_list) == 1
+
+        assert Foo.orders.impl.extensions is User.orders.impl.extensions
+        assert Foo.orders.impl.extensions is not ext_list
+        
+        compile_mappers()
+        assert len(User.somename.impl.extensions) == 1
+        assert len(Foo.somename.impl.extensions) == 1
+        assert len(Foo.orders.impl.extensions) == 3
+        assert len(User.orders.impl.extensions) == 3
+        
+
     @testing.resolve_artifact_names
     def test_compile_on_get_props_1(self):
         m =mapper(User, users)