summaryrefslogtreecommitdiff
path: root/test/ext
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2018-08-17 11:37:30 -0400
committerMike Bayer <mike_mp@zzzcomputing.com>2018-08-17 11:42:31 -0400
commit4c931b2ec7e0f09ac8c3ebe28c794f5858d54efb (patch)
tree9c7e96955068a63d10f760748e69ed3ac7e3b742 /test/ext
parent9a5be7bb92de692c13215ea9b336c831400d5a5e (diff)
downloadsqlalchemy-4c931b2ec7e0f09ac8c3ebe28c794f5858d54efb.tar.gz
Accommodate for classically mapped base classes in declarative
Fixed issue in previously untested use case, allowing a declarative mapped class to inherit from a classically-mapped class outside of the declarative base, including that it accommodates for unmapped intermediate classes. An unmapped intermediate class may specify ``__abstract__``, which is now interpreted correctly, or the intermediate class can remain unmarked, and the classically mapped base class will be detected within the hierarchy regardless. In order to anticipate existing scenarios which may be mixing in classical mappings into existing declarative hierarchies, an error is now raised if multiple mapped bases are detected for a given class. Fixes: #4321 Change-Id: I8604ecfd170d2589d9d1b1c87ba303762071fc30
Diffstat (limited to 'test/ext')
-rw-r--r--test/ext/declarative/test_inheritance.py93
1 files changed, 91 insertions, 2 deletions
diff --git a/test/ext/declarative/test_inheritance.py b/test/ext/declarative/test_inheritance.py
index 7ced8ec15..c310b725f 100644
--- a/test/ext/declarative/test_inheritance.py
+++ b/test/ext/declarative/test_inheritance.py
@@ -1,5 +1,5 @@
-from sqlalchemy.testing import eq_, assert_raises, \
+from sqlalchemy.testing import eq_, le_, assert_raises, \
assert_raises_message, is_, is_true, is_false
from sqlalchemy.ext import declarative as decl
import sqlalchemy as sa
@@ -8,7 +8,7 @@ from sqlalchemy import Integer, String, ForeignKey
from sqlalchemy.testing.schema import Table, Column
from sqlalchemy.orm import relationship, create_session, class_mapper, \
configure_mappers, clear_mappers, \
- polymorphic_union, deferred, Session
+ polymorphic_union, deferred, Session, mapper
from sqlalchemy.ext.declarative import declared_attr, AbstractConcreteBase, \
ConcreteBase, has_inherited_table
from sqlalchemy.testing import fixtures, mock
@@ -290,6 +290,95 @@ class DeclarativeInheritanceTest(DeclarativeTestBase):
assert class_mapper(Engineer).inherits is class_mapper(Person)
+ def test_intermediate_abstract_class_on_classical(self):
+ class Person(object):
+ pass
+
+ person_table = Table('people', Base.metadata,
+ Column('id', Integer, primary_key=True),
+ Column('kind', String(50)))
+
+ mapper(Person, person_table,
+ polymorphic_on='kind', polymorphic_identity='person')
+
+ class SpecialPerson(Person):
+ __abstract__ = True
+
+ class Manager(SpecialPerson, Base):
+ __tablename__ = 'managers'
+ id = Column(Integer, ForeignKey(Person.id), primary_key=True)
+ __mapper_args__ = {
+ 'polymorphic_identity': 'manager'
+ }
+
+ from sqlalchemy import inspect
+ assert inspect(Manager).inherits is inspect(Person)
+
+ eq_(set(class_mapper(Person).class_manager), {'id', 'kind'})
+ eq_(set(class_mapper(Manager).class_manager), {'id', 'kind'})
+
+ def test_intermediate_unmapped_class_on_classical(self):
+ class Person(object):
+ pass
+
+ person_table = Table('people', Base.metadata,
+ Column('id', Integer, primary_key=True),
+ Column('kind', String(50)))
+
+ mapper(Person, person_table,
+ polymorphic_on='kind', polymorphic_identity='person')
+
+ class SpecialPerson(Person):
+ pass
+
+ class Manager(SpecialPerson, Base):
+ __tablename__ = 'managers'
+ id = Column(Integer, ForeignKey(Person.id), primary_key=True)
+ __mapper_args__ = {
+ 'polymorphic_identity': 'manager'
+ }
+
+ from sqlalchemy import inspect
+ assert inspect(Manager).inherits is inspect(Person)
+
+ eq_(set(class_mapper(Person).class_manager), {'id', 'kind'})
+ eq_(set(class_mapper(Manager).class_manager), {'id', 'kind'})
+
+ def test_class_w_invalid_multiple_bases(self):
+ class Person(object):
+ pass
+
+ person_table = Table('people', Base.metadata,
+ Column('id', Integer, primary_key=True),
+ Column('kind', String(50)))
+
+ mapper(Person, person_table,
+ polymorphic_on='kind', polymorphic_identity='person')
+
+ class DeclPerson(Base):
+ __tablename__ = 'decl_people'
+ id = Column(Integer, primary_key=True)
+ kind = Column(String(50))
+
+ class SpecialPerson(Person):
+ pass
+
+ def go():
+ class Manager(SpecialPerson, DeclPerson):
+ __tablename__ = 'managers'
+ id = Column(Integer,
+ ForeignKey(DeclPerson.id), primary_key=True)
+ __mapper_args__ = {
+ 'polymorphic_identity': 'manager'
+ }
+
+ assert_raises_message(
+ sa.exc.InvalidRequestError,
+ r"Class .*Manager.* has multiple mapped "
+ r"bases: \[.*Person.*DeclPerson.*\]",
+ go
+ )
+
def test_with_undefined_foreignkey(self):
class Parent(Base):