]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
Check more specifically for hybrid attr and not mapped property
authorMike Bayer <mike_mp@zzzcomputing.com>
Fri, 19 Oct 2018 21:10:42 +0000 (17:10 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Fri, 19 Oct 2018 21:12:26 +0000 (17:12 -0400)
Fixed regression caused by :ticket:`4326` in version 1.2.12 where using
:class:`.declared_attr` with a mixin in conjunction with
:func:`.orm.synonym` would fail to map the synonym properly to an inherited
subclass.

Fixes: #4350
Change-Id: Ib2a9b6a125a2ac7c7ff80201746b7f10e5596226

doc/build/changelog/unreleased_12/4350.rst [new file with mode: 0644]
lib/sqlalchemy/ext/declarative/base.py
test/ext/declarative/test_mixin.py

diff --git a/doc/build/changelog/unreleased_12/4350.rst b/doc/build/changelog/unreleased_12/4350.rst
new file mode 100644 (file)
index 0000000..d3216a5
--- /dev/null
@@ -0,0 +1,8 @@
+.. change::
+   :tags: bug, orm, declarative
+   :tickets: 4350
+
+   Fixed regression caused by :ticket:`4326` in version 1.2.12 where using
+   :class:`.declared_attr` with a mixin in conjunction with
+   :func:`.orm.synonym` would fail to map the synonym properly to an inherited
+   subclass.
index 9e15582d6f7c5a4935427b8ef52e39fd392a5328..a6642364dc19bf0bb251f09565e7b49f6a4be1eb 100644 (file)
@@ -295,7 +295,8 @@ class _MapperConfig(object):
                             # produces nested proxies, so we are only
                             # looking one level deep right now.
                             if isinstance(ret, InspectionAttr) and \
-                                    ret._is_internal_proxy:
+                                    ret._is_internal_proxy and not isinstance(
+                                        ret.original_property, MapperProperty):
                                 ret = ret.descriptor
 
                             dict_[name] = column_copies[obj] = ret
index 6f95bed60f4aed97f658e5f6fe01da3ad4d8e629..fa8c36656cecf6b754e59813f36a719540b55833 100644 (file)
@@ -7,7 +7,7 @@ from sqlalchemy import Integer, String, ForeignKey, select, func
 from sqlalchemy.testing.schema import Table, Column
 from sqlalchemy.orm import relationship, create_session, class_mapper, \
     configure_mappers, clear_mappers, \
-    deferred, column_property, Session, base as orm_base
+    deferred, column_property, Session, base as orm_base, synonym
 from sqlalchemy.util import classproperty
 from sqlalchemy.ext.declarative import declared_attr, declarative_base
 from sqlalchemy.orm import events as orm_events
@@ -1252,7 +1252,9 @@ class DeclarativeMixinTest(DeclarativeTestBase):
         assert isinstance(SomeAbstract.__dict__['some_attr'], declared_attr)
 
 
-class DeclarativeMixinPropertyTest(DeclarativeTestBase):
+class DeclarativeMixinPropertyTest(
+    DeclarativeTestBase,
+    testing.AssertsCompiledSQL):
 
     def test_column_property(self):
 
@@ -1371,6 +1373,53 @@ class DeclarativeMixinPropertyTest(DeclarativeTestBase):
             d1.all_orm_descriptors['hp2'],
         )
 
+    def test_correct_for_proxies_doesnt_impact_synonyms(self):
+        from sqlalchemy import inspect
+
+        class Mixin(object):
+            @declared_attr
+            def data_syn(cls):
+                return synonym('data')
+
+        class Base(declarative_base(), Mixin):
+            __tablename__ = 'test'
+            id = Column(String, primary_key=True)
+            data = Column(String)
+            type = Column(String)
+            __mapper_args__ = {
+                'polymorphic_on': type,
+                'polymorphic_identity': 'base'
+            }
+
+        class Derived(Base):
+            __mapper_args__ = {
+                'polymorphic_identity': 'derived'
+            }
+
+        assert Base.data_syn._is_internal_proxy
+        assert Derived.data_syn._is_internal_proxy
+
+        b1 = inspect(Base)
+        d1 = inspect(Derived)
+        is_(
+            b1.attrs['data_syn'],
+            d1.attrs['data_syn'],
+        )
+
+        s = Session()
+        self.assert_compile(
+            s.query(Base.data_syn).filter(Base.data_syn == 'foo'),
+            'SELECT test.data AS test_data FROM test WHERE test.data = :data_1',
+            dialect='default'
+        )
+        self.assert_compile(
+            s.query(Derived.data_syn).filter(Derived.data_syn == 'foo'),
+            'SELECT test.data AS test_data FROM test WHERE test.data = '
+            ':data_1 AND test.type IN (:type_1)',
+            dialect='default',
+            checkparams={"type_1": "derived", "data_1": "foo"}
+        )
+
     def test_column_in_mapper_args(self):
 
         class MyMixin(object):