summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/build/changelog/changelog_10.rst15
-rw-r--r--lib/sqlalchemy/ext/declarative/api.py15
-rw-r--r--test/ext/declarative/test_mixin.py33
3 files changed, 54 insertions, 9 deletions
diff --git a/doc/build/changelog/changelog_10.rst b/doc/build/changelog/changelog_10.rst
index 6d8aa67da..70f31f5e6 100644
--- a/doc/build/changelog/changelog_10.rst
+++ b/doc/build/changelog/changelog_10.rst
@@ -19,6 +19,21 @@
: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
diff --git a/lib/sqlalchemy/ext/declarative/api.py b/lib/sqlalchemy/ext/declarative/api.py
index 048533b92..713ea0aba 100644
--- a/lib/sqlalchemy/ext/declarative/api.py
+++ b/lib/sqlalchemy/ext/declarative/api.py
@@ -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)
diff --git a/test/ext/declarative/test_mixin.py b/test/ext/declarative/test_mixin.py
index 5cefe8d47..45b881671 100644
--- a/test/ext/declarative/test_mixin.py
+++ b/test/ext/declarative/test_mixin.py
@@ -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()