mirror of
https://github.com/sqlalchemy/sqlalchemy.git
synced 2026-05-28 03:26:01 -04:00
772374735d
tested using pycodestyle version 2.2.0 Fixes: #3885 Change-Id: I5df43adc3aefe318f9eeab72a078247a548ec566 Pull-request: https://github.com/zzzeek/sqlalchemy/pull/343
342 lines
10 KiB
Python
342 lines
10 KiB
Python
from sqlalchemy.testing import fixtures
|
|
from ..orm._fixtures import FixtureTest
|
|
from sqlalchemy.ext.automap import automap_base
|
|
from sqlalchemy.orm import relationship, interfaces, configure_mappers
|
|
from sqlalchemy.ext.automap import generate_relationship
|
|
from sqlalchemy.testing.mock import Mock, patch
|
|
from sqlalchemy import String, Integer, ForeignKey
|
|
from sqlalchemy import testing
|
|
from sqlalchemy.testing.schema import Table, Column
|
|
|
|
|
|
class AutomapTest(fixtures.MappedTest):
|
|
@classmethod
|
|
def define_tables(cls, metadata):
|
|
FixtureTest.define_tables(metadata)
|
|
|
|
def test_relationship_o2m_default(self):
|
|
Base = automap_base(metadata=self.metadata)
|
|
Base.prepare()
|
|
|
|
User = Base.classes.users
|
|
Address = Base.classes.addresses
|
|
|
|
a1 = Address(email_address='e1')
|
|
u1 = User(name='u1', addresses_collection=[a1])
|
|
assert a1.users is u1
|
|
|
|
def test_relationship_explicit_override_o2m(self):
|
|
Base = automap_base(metadata=self.metadata)
|
|
prop = relationship("addresses", collection_class=set)
|
|
|
|
class User(Base):
|
|
__tablename__ = 'users'
|
|
|
|
addresses_collection = prop
|
|
|
|
Base.prepare()
|
|
assert User.addresses_collection.property is prop
|
|
Address = Base.classes.addresses
|
|
|
|
a1 = Address(email_address='e1')
|
|
u1 = User(name='u1', addresses_collection=set([a1]))
|
|
assert a1.user is u1
|
|
|
|
def test_relationship_explicit_override_m2o(self):
|
|
Base = automap_base(metadata=self.metadata)
|
|
|
|
prop = relationship("users")
|
|
|
|
class Address(Base):
|
|
__tablename__ = 'addresses'
|
|
|
|
users = prop
|
|
|
|
Base.prepare()
|
|
User = Base.classes.users
|
|
|
|
assert Address.users.property is prop
|
|
a1 = Address(email_address='e1')
|
|
u1 = User(name='u1', address_collection=[a1])
|
|
assert a1.users is u1
|
|
|
|
def test_relationship_self_referential(self):
|
|
Base = automap_base(metadata=self.metadata)
|
|
Base.prepare()
|
|
|
|
Node = Base.classes.nodes
|
|
|
|
n1 = Node()
|
|
n2 = Node()
|
|
n1.nodes_collection.append(n2)
|
|
assert n2.nodes is n1
|
|
|
|
def test_prepare_accepts_optional_schema_arg(self):
|
|
"""
|
|
The underlying reflect call accepts an optional schema argument.
|
|
This is for determining which database schema to load.
|
|
This test verifies that prepare can accept an optiona schema argument
|
|
and pass it to reflect.
|
|
"""
|
|
Base = automap_base(metadata=self.metadata)
|
|
engine_mock = Mock()
|
|
with patch.object(Base.metadata, "reflect") as reflect_mock:
|
|
Base.prepare(engine_mock, reflect=True, schema="some_schema")
|
|
reflect_mock.assert_called_once_with(
|
|
engine_mock,
|
|
schema="some_schema",
|
|
extend_existing=True,
|
|
autoload_replace=False,
|
|
)
|
|
|
|
def test_prepare_defaults_to_no_schema(self):
|
|
"""
|
|
The underlying reflect call accepts an optional schema argument.
|
|
This is for determining which database schema to load.
|
|
This test verifies that prepare passes a default None if no schema is
|
|
provided.
|
|
"""
|
|
Base = automap_base(metadata=self.metadata)
|
|
engine_mock = Mock()
|
|
with patch.object(Base.metadata, "reflect") as reflect_mock:
|
|
Base.prepare(engine_mock, reflect=True)
|
|
reflect_mock.assert_called_once_with(
|
|
engine_mock,
|
|
schema=None,
|
|
extend_existing=True,
|
|
autoload_replace=False,
|
|
)
|
|
|
|
def test_naming_schemes(self):
|
|
Base = automap_base(metadata=self.metadata)
|
|
|
|
def classname_for_table(base, tablename, table):
|
|
return str("cls_" + tablename)
|
|
|
|
def name_for_scalar_relationship(
|
|
base, local_cls, referred_cls, constraint):
|
|
return "scalar_" + referred_cls.__name__
|
|
|
|
def name_for_collection_relationship(
|
|
base, local_cls, referred_cls, constraint):
|
|
return "coll_" + referred_cls.__name__
|
|
|
|
Base.prepare(
|
|
classname_for_table=classname_for_table,
|
|
name_for_scalar_relationship=name_for_scalar_relationship,
|
|
name_for_collection_relationship=name_for_collection_relationship
|
|
)
|
|
|
|
User = Base.classes.cls_users
|
|
Address = Base.classes.cls_addresses
|
|
|
|
u1 = User()
|
|
a1 = Address()
|
|
u1.coll_cls_addresses.append(a1)
|
|
assert a1.scalar_cls_users is u1
|
|
|
|
def test_relationship_m2m(self):
|
|
Base = automap_base(metadata=self.metadata)
|
|
|
|
Base.prepare()
|
|
|
|
Order, Item = Base.classes.orders, Base.classes['items']
|
|
|
|
o1 = Order()
|
|
i1 = Item()
|
|
o1.items_collection.append(i1)
|
|
assert o1 in i1.orders_collection
|
|
|
|
def test_relationship_explicit_override_forwards_m2m(self):
|
|
Base = automap_base(metadata=self.metadata)
|
|
|
|
class Order(Base):
|
|
__tablename__ = 'orders'
|
|
|
|
items_collection = relationship(
|
|
"items",
|
|
secondary="order_items",
|
|
collection_class=set)
|
|
Base.prepare()
|
|
|
|
Item = Base.classes['items']
|
|
|
|
o1 = Order()
|
|
i1 = Item()
|
|
o1.items_collection.add(i1)
|
|
|
|
# it is 'order_collection' because the class name is
|
|
# "Order" !
|
|
assert isinstance(i1.order_collection, list)
|
|
assert o1 in i1.order_collection
|
|
|
|
def test_relationship_pass_params(self):
|
|
Base = automap_base(metadata=self.metadata)
|
|
|
|
mock = Mock()
|
|
|
|
def _gen_relationship(
|
|
base, direction, return_fn, attrname,
|
|
local_cls, referred_cls, **kw):
|
|
mock(base, direction, attrname)
|
|
return generate_relationship(
|
|
base, direction, return_fn,
|
|
attrname, local_cls, referred_cls, **kw)
|
|
|
|
Base.prepare(generate_relationship=_gen_relationship)
|
|
assert set(tuple(c[1]) for c in mock.mock_calls).issuperset([
|
|
(Base, interfaces.MANYTOONE, "nodes"),
|
|
(Base, interfaces.MANYTOMANY, "keywords_collection"),
|
|
(Base, interfaces.MANYTOMANY, "items_collection"),
|
|
(Base, interfaces.MANYTOONE, "users"),
|
|
(Base, interfaces.ONETOMANY, "addresses_collection"),
|
|
])
|
|
|
|
|
|
class CascadeTest(fixtures.MappedTest):
|
|
@classmethod
|
|
def define_tables(cls, metadata):
|
|
Table(
|
|
"a", metadata,
|
|
Column('id', Integer, primary_key=True)
|
|
)
|
|
Table(
|
|
"b", metadata,
|
|
Column('id', Integer, primary_key=True),
|
|
Column('aid', ForeignKey('a.id'), nullable=True)
|
|
)
|
|
Table(
|
|
"c", metadata,
|
|
Column('id', Integer, primary_key=True),
|
|
Column('aid', ForeignKey('a.id'), nullable=False)
|
|
)
|
|
Table(
|
|
"d", metadata,
|
|
Column('id', Integer, primary_key=True),
|
|
Column(
|
|
'aid', ForeignKey('a.id', ondelete="cascade"), nullable=False)
|
|
)
|
|
Table(
|
|
"e", metadata,
|
|
Column('id', Integer, primary_key=True),
|
|
Column(
|
|
'aid', ForeignKey('a.id', ondelete="set null"),
|
|
nullable=True)
|
|
)
|
|
|
|
def test_o2m_relationship_cascade(self):
|
|
Base = automap_base(metadata=self.metadata)
|
|
Base.prepare()
|
|
|
|
configure_mappers()
|
|
|
|
b_rel = Base.classes.a.b_collection
|
|
assert not b_rel.property.cascade.delete
|
|
assert not b_rel.property.cascade.delete_orphan
|
|
assert not b_rel.property.passive_deletes
|
|
|
|
assert b_rel.property.cascade.save_update
|
|
|
|
c_rel = Base.classes.a.c_collection
|
|
assert c_rel.property.cascade.delete
|
|
assert c_rel.property.cascade.delete_orphan
|
|
assert not c_rel.property.passive_deletes
|
|
|
|
assert c_rel.property.cascade.save_update
|
|
|
|
d_rel = Base.classes.a.d_collection
|
|
assert d_rel.property.cascade.delete
|
|
assert d_rel.property.cascade.delete_orphan
|
|
assert d_rel.property.passive_deletes
|
|
|
|
assert d_rel.property.cascade.save_update
|
|
|
|
e_rel = Base.classes.a.e_collection
|
|
assert not e_rel.property.cascade.delete
|
|
assert not e_rel.property.cascade.delete_orphan
|
|
assert e_rel.property.passive_deletes
|
|
|
|
assert e_rel.property.cascade.save_update
|
|
|
|
|
|
class AutomapInhTest(fixtures.MappedTest):
|
|
@classmethod
|
|
def define_tables(cls, metadata):
|
|
Table(
|
|
'single', metadata,
|
|
Column('id', Integer, primary_key=True),
|
|
Column('type', String(10)),
|
|
test_needs_fk=True
|
|
)
|
|
|
|
Table(
|
|
'joined_base', metadata,
|
|
Column('id', Integer, primary_key=True),
|
|
Column('type', String(10)),
|
|
test_needs_fk=True
|
|
)
|
|
|
|
Table(
|
|
'joined_inh', metadata,
|
|
Column(
|
|
'id', Integer,
|
|
ForeignKey('joined_base.id'), primary_key=True),
|
|
test_needs_fk=True
|
|
)
|
|
|
|
FixtureTest.define_tables(metadata)
|
|
|
|
def test_single_inheritance_reflect(self):
|
|
Base = automap_base()
|
|
|
|
class Single(Base):
|
|
__tablename__ = 'single'
|
|
|
|
type = Column(String)
|
|
|
|
__mapper_args__ = {
|
|
"polymorphic_identity": "u0",
|
|
"polymorphic_on": type}
|
|
|
|
class SubUser1(Single):
|
|
__mapper_args__ = {"polymorphic_identity": "u1"}
|
|
|
|
class SubUser2(Single):
|
|
__mapper_args__ = {"polymorphic_identity": "u2"}
|
|
|
|
Base.prepare(engine=testing.db, reflect=True)
|
|
|
|
assert SubUser2.__mapper__.inherits is Single.__mapper__
|
|
|
|
def test_joined_inheritance_reflect(self):
|
|
Base = automap_base()
|
|
|
|
class Joined(Base):
|
|
__tablename__ = 'joined_base'
|
|
|
|
type = Column(String)
|
|
|
|
__mapper_args__ = {
|
|
"polymorphic_identity": "u0",
|
|
"polymorphic_on": type}
|
|
|
|
class SubJoined(Joined):
|
|
__tablename__ = 'joined_inh'
|
|
__mapper_args__ = {"polymorphic_identity": "u1"}
|
|
|
|
Base.prepare(engine=testing.db, reflect=True)
|
|
|
|
assert SubJoined.__mapper__.inherits is Joined.__mapper__
|
|
|
|
assert not Joined.__mapper__.relationships
|
|
assert not SubJoined.__mapper__.relationships
|
|
|
|
def test_conditional_relationship(self):
|
|
Base = automap_base()
|
|
|
|
def _gen_relationship(*arg, **kw):
|
|
return None
|
|
Base.prepare(
|
|
engine=testing.db, reflect=True,
|
|
generate_relationship=_gen_relationship)
|