]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
- Loosened some restrictions that were added to ``@declared_attr``
authorMike Bayer <mike_mp@zzzcomputing.com>
Wed, 18 Mar 2015 22:57:13 +0000 (18:57 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Wed, 18 Mar 2015 22:57:13 +0000 (18:57 -0400)
objects, such that they were prevented from being called outside
of the declarative process; this is related to the enhancements
of #3150 which allow ``@declared_attr`` to return a value that is
cached based on the current class as it's being configured.
The exception raise has been removed, and the behavior changed
so that outside of the declarative process, the function decorated by
``@declared_attr`` is called every time just like a regular
``@property``, without using any caching, as none is available
at this stage.
fixes #3331

doc/build/changelog/changelog_10.rst
lib/sqlalchemy/ext/declarative/api.py
test/ext/declarative/test_mixin.py

index 6d8aa67da892171162e1a86b293777ae2a41577c..70f31f5e65f0346788be6c9f3ce0c14718429eb2 100644 (file)
 .. changelog::
     :version: 1.0.0b2
 
+    .. change::
+        :tags: change, ext, declarative
+        :tickets: 3331
+
+        Loosened some restrictions that were added to ``@declared_attr``
+        objects, such that they were prevented from being called outside
+        of the declarative process; this is related to the enhancements
+        of #3150 which allow ``@declared_attr`` to return a value that is
+        cached based on the current class as it's being configured.
+        The exception raise has been removed, and the behavior changed
+        so that outside of the declarative process, the function decorated by
+        ``@declared_attr`` is called every time just like a regular
+        ``@property``, without using any caching, as none is available
+        at this stage.
+
     .. change::
         :tags: bug, engine
         :tickets: 3330, 3329
index 048533b92cf67dc59b50f57ac632a248b24d7070..713ea0aba3ac173d74a8fd31de7bd21998239a65 100644 (file)
@@ -175,15 +175,12 @@ class declared_attr(interfaces._MappedAttribute, property):
                 "non-mapped class %s" %
                 (desc.fget.__name__, cls.__name__))
             return desc.fget(cls)
-        try:
-            reg = manager.info['declared_attr_reg']
-        except KeyError:
-            raise exc.InvalidRequestError(
-                "@declared_attr called outside of the "
-                "declarative mapping process; is declarative_base() being "
-                "used correctly?")
-
-        if desc in reg:
+
+        reg = manager.info.get('declared_attr_reg', None)
+
+        if reg is None:
+            return desc.fget(cls)
+        elif desc in reg:
             return reg[desc]
         else:
             reg[desc] = obj = desc.fget(cls)
index 5cefe8d4767bc2de93ce2b846ac48ee559494d95..45b881671064268a62c80172add6dd6995cba4b9 100644 (file)
@@ -1392,6 +1392,39 @@ class DeclaredAttrTest(DeclarativeTestBase, testing.AssertsCompiledSQL):
             getattr, Mixin, "my_prop"
         )
 
+    def test_non_decl_access(self):
+        counter = mock.Mock()
+
+        class Mixin(object):
+            @declared_attr
+            def __tablename__(cls):
+                counter(cls)
+                return "foo"
+
+        class Foo(Mixin, Base):
+            id = Column(Integer, primary_key=True)
+
+            @declared_attr
+            def x(cls):
+                cls.__tablename__
+
+            @declared_attr
+            def y(cls):
+                cls.__tablename__
+
+        eq_(
+            counter.mock_calls,
+            [mock.call(Foo)]
+        )
+
+        eq_(Foo.__tablename__, 'foo')
+        eq_(Foo.__tablename__, 'foo')
+
+        eq_(
+            counter.mock_calls,
+            [mock.call(Foo), mock.call(Foo), mock.call(Foo)]
+        )
+
     def test_property_noncascade(self):
         counter = mock.Mock()