]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
Accommodate for same base class multiple times in inherits list
authorMike Bayer <mike_mp@zzzcomputing.com>
Sun, 27 Sep 2020 15:44:58 +0000 (11:44 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Sun, 27 Sep 2020 15:45:49 +0000 (11:45 -0400)
Improved declarative inheritance scanning to not get tripped up when the
same base class appears multiple times in the base inheritance list.

Fixes: #4699
Change-Id: I932e735cd2e2c1efa935936c84219924225d10f1

doc/build/changelog/unreleased_14/4699.rst [new file with mode: 0644]
lib/sqlalchemy/orm/decl_base.py
test/orm/declarative/test_mixin.py

diff --git a/doc/build/changelog/unreleased_14/4699.rst b/doc/build/changelog/unreleased_14/4699.rst
new file mode 100644 (file)
index 0000000..e1e1442
--- /dev/null
@@ -0,0 +1,7 @@
+.. change::
+    :tags: bug, orm
+    :tickets: 4699
+
+    Improved declarative inheritance scanning to not get tripped up when the
+    same base class appears multiple times in the base inheritance list.
+
index b9c890429e4f055ac607448b7d49536f6736da76..644e4aff63a8e2ab40bc0fbef9f51a11e9bb5283 100644 (file)
@@ -677,7 +677,8 @@ class _ClassScanMapperConfig(_MapperConfig):
                 ) is not None and not _get_immediate_cls_attr(
                     c, "_sa_decl_prepare_nocascade", strict=True
                 ):
-                    inherits_search.append(c)
+                    if c not in inherits_search:
+                        inherits_search.append(c)
 
             if inherits_search:
                 if len(inherits_search) > 1:
index eed918572895cedd066a9653d91cdd6f755be8bf..bc36ee9624fd68b60544f0c0ffd2b84df3227af0 100644 (file)
@@ -218,6 +218,31 @@ class DeclarativeMixinTest(DeclarativeTestBase):
         eq_(MyModelA.__table__.c.foo.type.__class__, String)
         eq_(MyModelB.__table__.c.foo.type.__class__, Integer)
 
+    def test_same_base_multiple_times(self):
+        class User(Base):
+            __tablename__ = "user"
+
+            id = Column(Integer, primary_key=True)
+            name = Column(String)
+            surname = Column(String)
+
+        class SpecialUser(User):
+            __abstract__ = True
+
+        class ConvenienceStuff(User):
+            __abstract__ = True
+
+            def fullname(self):
+                return self.name + " " + self.surname
+
+        class Manager(SpecialUser, ConvenienceStuff, User):
+            __tablename__ = "manager"
+
+            id = Column(Integer, ForeignKey("user.id"), primary_key=True)
+            title = Column(String)
+
+        eq_(Manager.__table__.name, "manager")
+
     def test_not_allowed(self):
         class MyMixin:
             foo = Column(Integer, ForeignKey("bar.id"))