diff options
-rw-r--r-- | doc/build/changelog/changelog_10.rst | 15 | ||||
-rw-r--r-- | lib/sqlalchemy/ext/declarative/api.py | 15 | ||||
-rw-r--r-- | test/ext/declarative/test_mixin.py | 33 |
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() |