]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
- Fixed shared state bug interfering with ScopedSession.mapper's
authorJason Kirtland <jek@discorporate.us>
Sat, 27 Sep 2008 18:11:40 +0000 (18:11 +0000)
committerJason Kirtland <jek@discorporate.us>
Sat, 27 Sep 2008 18:11:40 +0000 (18:11 +0000)
  ability to apply default __init__ implementations on object
  subclasses.

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

diff --git a/CHANGES b/CHANGES
index abd018871c088d5ee60db876f15898f0478b6968..73590bcd5d85658387e845af823142ef527c8b44 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -7,36 +7,38 @@ CHANGES
 0.5.0rc2
 ========
 - orm
-    - Fixed bug involving read/write relation()s that 
-      contain literal or other non-column expressions 
-      within their primaryjoin condition equated
-      to a foreign key column.
-      
-    - "non-batch" mode in mapper(), a feature which allows
-      mapper extension methods to be called as each instance
-      is updated/inserted, now honors the insert order
-      of the objects given. 
-      
-    - fixed RLock-related bug in mapper which could deadlock
-      upon reentrant mapper compile() calls, something that
-      occurs when using declarative constructs inside of
-      ForeignKey objects.
+    - Fixed bug involving read/write relation()s that contain
+      literal or other non-column expressions within their
+      primaryjoin condition equated to a foreign key column.
+
+    - "non-batch" mode in mapper(), a feature which allows mapper
+      extension methods to be called as each instance is
+      updated/inserted, now honors the insert order of the objects
+      given.
+
+    - Fixed RLock-related bug in mapper which could deadlock upon
+      reentrant mapper compile() calls, something that occurs when
+      using declarative constructs inside of ForeignKey objects.
 
     - ScopedSession.query_property now accepts a query_cls factory,
       overriding the session's configured query_cls.
 
+    - Fixed shared state bug interfering with ScopedSession.mapper's
+      ability to apply default __init__ implementations on object
+      subclasses.
+
 - sql
-    - column.in_(someselect) can now be used as 
-      a columns-clause expression without the subquery
-      bleeding into the FROM clause [ticket:1074]
+    - column.in_(someselect) can now be used as a columns-clause
+      expression without the subquery bleeding into the FROM clause
+      [ticket:1074]
 
 - sqlite
-    - Overhauled SQLite date/time bind/result processing
-      to use regular expressions and format strings, rather
-      than strptime/strftime, to generically support
-      pre-1900 dates, dates with microseconds.  [ticket:968]
+    - Overhauled SQLite date/time bind/result processing to use
+      regular expressions and format strings, rather than
+      strptime/strftime, to generically support pre-1900 dates,
+      dates with microseconds.  [ticket:968]
+
 
-    
 0.5.0rc1
 ========
 
index 5dd17a2898fe2ea06577b395d4bc5a632526d056..b557e0232e92bb42c3b79afaf45fd758d864e80f 100644 (file)
@@ -142,7 +142,7 @@ class _ScopedExt(MapperExtension):
         self.context = context
         self.validate = validate
         self.save_on_init = save_on_init
-        self.set_kwargs_on_init = None
+        self.set_kwargs_on_init = True
 
     def validating(self):
         return _ScopedExt(self.context, validate=True)
@@ -162,26 +162,23 @@ class _ScopedExt(MapperExtension):
         if not 'query' in class_.__dict__:
             class_.query = query()
 
-        if self.set_kwargs_on_init is None:
-            self.set_kwargs_on_init = class_.__init__ is object.__init__
-        if self.set_kwargs_on_init:
-            def __init__(self, **kwargs):
-                pass
-            class_.__init__ = __init__
+        if self.set_kwargs_on_init and class_.__init__ is object.__init__:
+            class_.__init__ = self._default__init__(mapper)
 
-    def init_instance(self, mapper, class_, oldinit, instance, args, kwargs):
-        if self.save_on_init:
-            session = kwargs.pop('_sa_session', None)
-
-        if self.set_kwargs_on_init:
+    def _default__init__(ext, mapper):
+        def __init__(self, **kwargs):
             for key, value in kwargs.items():
-                if self.validate:
+                if ext.validate:
                     if not mapper.get_property(key, resolve_synonyms=False,
                                                raiseerr=False):
                         raise sa_exc.ArgumentError(
                             "Invalid __init__ argument: '%s'" % key)
-                setattr(instance, key, value)
-            kwargs.clear()
+                setattr(self, key, value)
+        return __init__
+
+    def init_instance(self, mapper, class_, oldinit, instance, args, kwargs):
+        if self.save_on_init:
+            session = kwargs.pop('_sa_session', None)
 
         if self.save_on_init:
             session = session or self.context.registry()
index 32e0dedb0e56e9201544e98af6e037214cc088fc..eea855490d003387d5c442200350989d4cbade1f 100644 (file)
@@ -131,6 +131,36 @@ class ScopedMapperTest(_ScopedTest):
         Session.mapper(Baz, table2, extension=ext)
         assert hasattr(Baz, 'query')
 
+    @testing.resolve_artifact_names
+    def test_default_constructor_state_not_shared(self):
+        scope = scoped_session(sa.orm.sessionmaker())
+
+        class A(object):
+            pass
+        class B(object):
+            def __init__(self):
+                pass
+
+        scope.mapper(A, table1)
+        scope.mapper(B, table2)
+
+        A(foo='bar')
+        self.assertRaises(TypeError, B, foo='bar')
+
+        scope = scoped_session(sa.orm.sessionmaker())
+
+        class C(object):
+            def __init__(self):
+                pass
+        class D(object):
+            pass
+
+        scope.mapper(C, table1)
+        scope.mapper(D, table2)
+
+        self.assertRaises(TypeError, C, foo='bar')
+        D(foo='bar')
+
     @testing.resolve_artifact_names
     def test_validating_constructor(self):
         s2 = SomeObject(someid=12)