From d84ae4f75468fea6b3345c1275d6a472d0cf7c5f Mon Sep 17 00:00:00 2001 From: Mike Bayer Date: Tue, 9 Apr 2013 14:21:40 -0400 Subject: [PATCH] Fixed indirect regression regarding :func:`.has_inherited_table`, where since it considers the current class' ``__table__``, was sensitive to when it was called. This is 0.7's behavior also, but in 0.7 things tended to "work out" within events like ``__mapper_args__()``. :func:`.has_inherited_table` now only considers superclasses, so should return the same answer regarding the current class no matter when it's called (obviously assuming the state of the superclass). [ticket:2656] --- doc/build/changelog/changelog_08.rst | 13 +++++++ lib/sqlalchemy/ext/declarative/api.py | 2 +- test/ext/declarative/test_inheritance.py | 43 +++++++++++++++++++++++- 3 files changed, 56 insertions(+), 2 deletions(-) diff --git a/doc/build/changelog/changelog_08.rst b/doc/build/changelog/changelog_08.rst index 503b8932bc..cbc8490957 100644 --- a/doc/build/changelog/changelog_08.rst +++ b/doc/build/changelog/changelog_08.rst @@ -6,6 +6,19 @@ .. changelog:: :version: 0.8.1 + .. change:: + :tags: bug, orm, declarative + :tickets: 2656 + + Fixed indirect regression regarding :func:`.has_inherited_table`, + where since it considers the current class' ``__table__``, was + sensitive to when it was called. This is 0.7's behavior also, + but in 0.7 things tended to "work out" within events like + ``__mapper_args__()``. :func:`.has_inherited_table` now only + considers superclasses, so should return the same answer + regarding the current class no matter when it's called + (obviously assuming the state of the superclass). + .. change:: :tags: bug, orm :tickets: 2699 diff --git a/lib/sqlalchemy/ext/declarative/api.py b/lib/sqlalchemy/ext/declarative/api.py index af77919a7f..6f3ffddc72 100644 --- a/lib/sqlalchemy/ext/declarative/api.py +++ b/lib/sqlalchemy/ext/declarative/api.py @@ -38,7 +38,7 @@ def has_inherited_table(cls): """Given a class, return True if any of the classes it inherits from has a mapped table, otherwise return False. """ - for class_ in cls.__mro__: + for class_ in cls.__mro__[1:]: if getattr(class_, '__table__', None) is not None: return True return False diff --git a/test/ext/declarative/test_inheritance.py b/test/ext/declarative/test_inheritance.py index ab78cc3e2e..f0372e8eea 100644 --- a/test/ext/declarative/test_inheritance.py +++ b/test/ext/declarative/test_inheritance.py @@ -14,7 +14,8 @@ from sqlalchemy.orm import relationship, create_session, class_mapper, \ Session from sqlalchemy.testing import eq_ from sqlalchemy.util import classproperty -from sqlalchemy.ext.declarative import declared_attr, AbstractConcreteBase, ConcreteBase +from sqlalchemy.ext.declarative import declared_attr, AbstractConcreteBase, \ + ConcreteBase, has_inherited_table from sqlalchemy.testing import fixtures Base = None @@ -1112,6 +1113,46 @@ class ConcreteInhTest(_RemoveListeners, DeclarativeTestBase): 'concrete':True} self._roundtrip(Employee, Manager, Engineer, Boss) + + def test_has_inherited_table_doesnt_consider_base(self): + class A(Base): + __tablename__ = 'a' + id = Column(Integer, primary_key=True) + + assert not has_inherited_table(A) + + class B(A): + __tablename__ = 'b' + id = Column(Integer, ForeignKey('a.id'), primary_key=True) + + assert has_inherited_table(B) + + def test_has_inherited_table_in_mapper_args(self): + class Test(Base): + __tablename__ = 'test' + id = Column(Integer, primary_key=True) + type = Column(String(20)) + + @declared_attr + def __mapper_args__(cls): + if not has_inherited_table(cls): + ret = { + 'polymorphic_identity': 'default', + 'polymorphic_on': cls.type, + } + else: + ret = {'polymorphic_identity': cls.__name__} + return ret + + class PolyTest(Test): + __tablename__ = 'poly_test' + id = Column(Integer, ForeignKey(Test.id), primary_key=True) + + configure_mappers() + + assert Test.__mapper__.polymorphic_on is Test.__table__.c.type + assert PolyTest.__mapper__.polymorphic_on is Test.__table__.c.type + def test_ok_to_override_type_from_abstract(self): class Employee(AbstractConcreteBase, Base, fixtures.ComparableEntity): pass -- 2.47.2