summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authormike bayer <mike_mp@zzzcomputing.com>2021-02-01 23:13:42 +0000
committerGerrit Code Review <gerrit@bbpush.zzzcomputing.com>2021-02-01 23:13:42 +0000
commit45c8fe6c0a755aa7a777dd0c12f97bb52dcc00a7 (patch)
tree2420ca661194e1d7cbac87854c970b45d1ba490f /test
parente917041d1e5d6349372a80222e6d9e32cfa07082 (diff)
parent5ec5b0a6c7b618bba7926e21f77be9557973860f (diff)
downloadsqlalchemy-45c8fe6c0a755aa7a777dd0c12f97bb52dcc00a7.tar.gz
Merge "reorganize mapper compile/teardown under registry"
Diffstat (limited to 'test')
-rw-r--r--test/aaa_profiling/test_memusage.py4
-rw-r--r--test/ext/declarative/test_inheritance.py4
-rw-r--r--test/orm/declarative/test_basic.py6
-rw-r--r--test/orm/test_events.py37
-rw-r--r--test/orm/test_mapper.py196
5 files changed, 224 insertions, 23 deletions
diff --git a/test/aaa_profiling/test_memusage.py b/test/aaa_profiling/test_memusage.py
index a41a8b9f1..dd709965b 100644
--- a/test/aaa_profiling/test_memusage.py
+++ b/test/aaa_profiling/test_memusage.py
@@ -27,7 +27,6 @@ from sqlalchemy.orm import selectinload
from sqlalchemy.orm import Session
from sqlalchemy.orm import sessionmaker
from sqlalchemy.orm import subqueryload
-from sqlalchemy.orm.mapper import _mapper_registry
from sqlalchemy.orm.session import _sessions
from sqlalchemy.processors import to_decimal_processor_factory
from sqlalchemy.processors import to_unicode_processor_factory
@@ -237,13 +236,12 @@ def profile_memory(
def assert_no_mappers():
clear_mappers()
gc_collect()
- assert len(_mapper_registry) == 0
class EnsureZeroed(fixtures.ORMTest):
def setup_test(self):
_sessions.clear()
- _mapper_registry.clear()
+ clear_mappers()
# enable query caching, however make the cache small so that
# the tests don't take too long. issues w/ caching include making
diff --git a/test/ext/declarative/test_inheritance.py b/test/ext/declarative/test_inheritance.py
index e25e7cfc2..496b5579d 100644
--- a/test/ext/declarative/test_inheritance.py
+++ b/test/ext/declarative/test_inheritance.py
@@ -227,7 +227,7 @@ class ConcreteInhTest(
Employee,
)
- configure_mappers()
+ Base.registry.configure()
# no subclasses yet.
assert_raises_message(
@@ -257,7 +257,7 @@ class ConcreteInhTest(
Employee,
)
- configure_mappers()
+ Base.registry.configure()
self.assert_compile(
Session().query(Employee),
diff --git a/test/orm/declarative/test_basic.py b/test/orm/declarative/test_basic.py
index 4d9162105..c779d214c 100644
--- a/test/orm/declarative/test_basic.py
+++ b/test/orm/declarative/test_basic.py
@@ -547,8 +547,6 @@ class DeclarativeTest(DeclarativeTestBase):
def test_recompile_on_othermapper(self):
"""declarative version of the same test in mappers.py"""
- from sqlalchemy.orm import mapperlib
-
class User(Base):
__tablename__ = "users"
@@ -565,10 +563,10 @@ class DeclarativeTest(DeclarativeTestBase):
"User", primaryjoin=user_id == User.id, backref="addresses"
)
- assert mapperlib.Mapper._new_mappers is True
+ assert User.__mapper__.registry._new_mappers is True
u = User() # noqa
assert User.addresses
- assert mapperlib.Mapper._new_mappers is False
+ assert User.__mapper__.registry._new_mappers is False
def test_string_dependency_resolution(self):
class User(Base, fixtures.ComparableEntity):
diff --git a/test/orm/test_events.py b/test/orm/test_events.py
index d9caa221d..6ba94096d 100644
--- a/test/orm/test_events.py
+++ b/test/orm/test_events.py
@@ -19,13 +19,13 @@ from sqlalchemy.orm import EXT_SKIP
from sqlalchemy.orm import instrumentation
from sqlalchemy.orm import Mapper
from sqlalchemy.orm import mapper
+from sqlalchemy.orm import mapperlib
from sqlalchemy.orm import query
from sqlalchemy.orm import relationship
from sqlalchemy.orm import selectinload
from sqlalchemy.orm import Session
from sqlalchemy.orm import sessionmaker
from sqlalchemy.orm import subqueryload
-from sqlalchemy.orm.mapper import _mapper_registry
from sqlalchemy.testing import assert_raises
from sqlalchemy.testing import assert_raises_message
from sqlalchemy.testing import AssertsCompiledSQL
@@ -1073,7 +1073,11 @@ class MapperEventsTest(_RemoveListeners, _fixtures.FixtureTest):
canary.mock_calls,
)
- def test_before_mapper_configured_event(self):
+ @testing.combinations((True,), (False,), argnames="create_dependency")
+ @testing.combinations((True,), (False,), argnames="configure_at_once")
+ def test_before_mapper_configured_event(
+ self, create_dependency, configure_at_once
+ ):
"""Test [ticket:4397].
This event is intended to allow a specific mapper to be skipped during
@@ -1088,7 +1092,7 @@ class MapperEventsTest(_RemoveListeners, _fixtures.FixtureTest):
"""
User, users = self.classes.User, self.tables.users
- mapper(User, users)
+ ump = mapper(User, users)
AnotherBase = declarative_base()
@@ -1098,12 +1102,18 @@ class MapperEventsTest(_RemoveListeners, _fixtures.FixtureTest):
__mapper_args__ = dict(
polymorphic_on="species", polymorphic_identity="Animal"
)
+ if create_dependency:
+ user_id = Column("user_id", ForeignKey(users.c.id))
- # Register the first classes and create their Mappers:
- configure_mappers()
+ if not configure_at_once:
+ # Register the first classes and create their Mappers:
+ configure_mappers()
+
+ unconfigured = list(mapperlib._unconfigured_mappers())
+ eq_(0, len(unconfigured))
- unconfigured = [m for m in _mapper_registry if not m.configured]
- eq_(0, len(unconfigured))
+ if create_dependency:
+ ump.add_property("animal", relationship(Animal))
# Declare a subclass, table and mapper, which refers to one that has
# not been loaded yet (Employer), and therefore cannot be configured:
@@ -1111,8 +1121,12 @@ class MapperEventsTest(_RemoveListeners, _fixtures.FixtureTest):
nonexistent = relationship("Nonexistent")
# These new classes should not be configured at this point:
- unconfigured = [m for m in _mapper_registry if not m.configured]
- eq_(1, len(unconfigured))
+ unconfigured = list(mapperlib._unconfigured_mappers())
+
+ if configure_at_once:
+ eq_(3, len(unconfigured))
+ else:
+ eq_(1, len(unconfigured))
# Now try to query User, which is internally consistent. This query
# fails by default because Mammal needs to be configured, and cannot
@@ -1121,7 +1135,10 @@ class MapperEventsTest(_RemoveListeners, _fixtures.FixtureTest):
s = fixture_session()
s.query(User)
- assert_raises(sa.exc.InvalidRequestError, probe)
+ if create_dependency:
+ assert_raises(sa.exc.InvalidRequestError, probe)
+ else:
+ probe()
# If we disable configuring mappers while querying, then it succeeds:
@event.listens_for(
diff --git a/test/orm/test_mapper.py b/test/orm/test_mapper.py
index d182fd2c1..ba4cf2637 100644
--- a/test/orm/test_mapper.py
+++ b/test/orm/test_mapper.py
@@ -15,6 +15,7 @@ from sqlalchemy.orm import aliased
from sqlalchemy.orm import attributes
from sqlalchemy.orm import backref
from sqlalchemy.orm import class_mapper
+from sqlalchemy.orm import clear_mappers
from sqlalchemy.orm import column_property
from sqlalchemy.orm import composite
from sqlalchemy.orm import configure_mappers
@@ -31,8 +32,11 @@ from sqlalchemy.testing import assert_raises
from sqlalchemy.testing import assert_raises_message
from sqlalchemy.testing import AssertsCompiledSQL
from sqlalchemy.testing import eq_
+from sqlalchemy.testing import expect_raises_message
from sqlalchemy.testing import fixtures
from sqlalchemy.testing import is_
+from sqlalchemy.testing import is_false
+from sqlalchemy.testing import is_true
from sqlalchemy.testing import ne_
from sqlalchemy.testing.fixtures import ComparableMixin
from sqlalchemy.testing.fixtures import fixture_session
@@ -304,9 +308,9 @@ class MapperTest(_fixtures.FixtureTest, AssertsCompiledSQL):
self.classes.User,
)
- self.mapper(User, users)
+ mp = self.mapper(User, users)
sa.orm.configure_mappers()
- assert sa.orm.mapperlib.Mapper._new_mappers is False
+ assert mp.registry._new_mappers is False
m = self.mapper(
Address,
@@ -315,10 +319,10 @@ class MapperTest(_fixtures.FixtureTest, AssertsCompiledSQL):
)
assert m.configured is False
- assert sa.orm.mapperlib.Mapper._new_mappers is True
+ assert m.registry._new_mappers is True
User()
assert User.addresses
- assert sa.orm.mapperlib.Mapper._new_mappers is False
+ assert m.registry._new_mappers is False
def test_configure_on_session(self):
User, users = self.classes.User, self.tables.users
@@ -1810,6 +1814,35 @@ class MapperTest(_fixtures.FixtureTest, AssertsCompiledSQL):
self.mapper(Address, addresses)
configure_mappers()
+ @testing.combinations((True,), (False,))
+ def test_registry_configure(self, cascade):
+ User, users = self.classes.User, self.tables.users
+
+ reg1 = registry()
+ ump = reg1.map_imperatively(User, users)
+
+ reg2 = registry()
+ AnotherBase = reg2.generate_base()
+
+ class Animal(AnotherBase):
+ __tablename__ = "animal"
+ species = Column(String(30), primary_key=True)
+ __mapper_args__ = dict(
+ polymorphic_on="species", polymorphic_identity="Animal"
+ )
+ user_id = Column("user_id", ForeignKey(users.c.id))
+
+ ump.add_property("animal", relationship(Animal))
+
+ if cascade:
+ reg1.configure(cascade=True)
+ else:
+ with expect_raises_message(
+ sa.exc.InvalidRequestError,
+ "configure was called with cascade=False",
+ ):
+ reg1.configure()
+
def test_reconstructor(self):
users = self.tables.users
@@ -2810,3 +2843,158 @@ class ComparatorFactoryTest(_fixtures.FixtureTest, AssertsCompiledSQL):
"foobar(users_1.id) = foobar(:foobar_1)",
dialect=default.DefaultDialect(),
)
+
+
+class RegistryConfigDisposeTest(fixtures.TestBase):
+ """test the cascading behavior of registry configure / dispose."""
+
+ @testing.fixture
+ def threeway_fixture(self):
+ reg1 = registry()
+ reg2 = registry()
+ reg3 = registry()
+
+ ab = bc = True
+
+ @reg1.mapped
+ class A(object):
+ __tablename__ = "a"
+ id = Column(Integer, primary_key=True)
+
+ @reg2.mapped
+ class B(object):
+ __tablename__ = "b"
+ id = Column(Integer, primary_key=True)
+ a_id = Column(ForeignKey(A.id))
+
+ @reg3.mapped
+ class C(object):
+ __tablename__ = "c"
+ id = Column(Integer, primary_key=True)
+ b_id = Column(ForeignKey(B.id))
+
+ if ab:
+ A.__mapper__.add_property("b", relationship(B))
+
+ if bc:
+ B.__mapper__.add_property("c", relationship(C))
+
+ yield reg1, reg2, reg3
+
+ clear_mappers()
+
+ @testing.fixture
+ def threeway_configured_fixture(self, threeway_fixture):
+ reg1, reg2, reg3 = threeway_fixture
+ configure_mappers()
+
+ return reg1, reg2, reg3
+
+ @testing.combinations((True,), (False,), argnames="cascade")
+ def test_configure_cascade_on_dependencies(
+ self, threeway_fixture, cascade
+ ):
+ reg1, reg2, reg3 = threeway_fixture
+ A, B, C = (
+ reg1._class_registry["A"],
+ reg2._class_registry["B"],
+ reg3._class_registry["C"],
+ )
+
+ is_(reg3._new_mappers, True)
+ is_(reg2._new_mappers, True)
+ is_(reg1._new_mappers, True)
+
+ if cascade:
+ reg1.configure(cascade=True)
+
+ is_(reg3._new_mappers, False)
+ is_(reg2._new_mappers, False)
+ is_(reg1._new_mappers, False)
+
+ is_true(C.__mapper__.configured)
+ is_true(B.__mapper__.configured)
+ is_true(A.__mapper__.configured)
+ else:
+ with testing.expect_raises_message(
+ sa.exc.InvalidRequestError,
+ "configure was called with cascade=False but additional ",
+ ):
+ reg1.configure()
+
+ @testing.combinations((True,), (False,), argnames="cascade")
+ def test_configure_cascade_not_on_dependents(
+ self, threeway_fixture, cascade
+ ):
+ reg1, reg2, reg3 = threeway_fixture
+ A, B, C = (
+ reg1._class_registry["A"],
+ reg2._class_registry["B"],
+ reg3._class_registry["C"],
+ )
+
+ is_(reg3._new_mappers, True)
+ is_(reg2._new_mappers, True)
+ is_(reg1._new_mappers, True)
+
+ reg3.configure(cascade=cascade)
+
+ is_(reg3._new_mappers, False)
+ is_(reg2._new_mappers, True)
+ is_(reg1._new_mappers, True)
+
+ is_true(C.__mapper__.configured)
+ is_false(B.__mapper__.configured)
+ is_false(A.__mapper__.configured)
+
+ @testing.combinations((True,), (False,), argnames="cascade")
+ def test_dispose_cascade_not_on_dependencies(
+ self, threeway_configured_fixture, cascade
+ ):
+ reg1, reg2, reg3 = threeway_configured_fixture
+ A, B, C = (
+ reg1._class_registry["A"],
+ reg2._class_registry["B"],
+ reg3._class_registry["C"],
+ )
+ am, bm, cm = A.__mapper__, B.__mapper__, C.__mapper__
+
+ reg1.dispose(cascade=cascade)
+
+ eq_(reg3.mappers, {cm})
+ eq_(reg2.mappers, {bm})
+ eq_(reg1.mappers, set())
+
+ is_false(cm._dispose_called)
+ is_false(bm._dispose_called)
+ is_true(am._dispose_called)
+
+ @testing.combinations((True,), (False,), argnames="cascade")
+ def test_clear_cascade_not_on_dependents(
+ self, threeway_configured_fixture, cascade
+ ):
+ reg1, reg2, reg3 = threeway_configured_fixture
+ A, B, C = (
+ reg1._class_registry["A"],
+ reg2._class_registry["B"],
+ reg3._class_registry["C"],
+ )
+ am, bm, cm = A.__mapper__, B.__mapper__, C.__mapper__
+
+ if cascade:
+ reg3.dispose(cascade=True)
+
+ eq_(reg3.mappers, set())
+ eq_(reg2.mappers, set())
+ eq_(reg1.mappers, set())
+
+ is_true(cm._dispose_called)
+ is_true(bm._dispose_called)
+ is_true(am._dispose_called)
+ else:
+ with testing.expect_raises_message(
+ sa.exc.InvalidRequestError,
+ "Registry has dependent registries that are not disposed; "
+ "pass cascade=True to clear these also",
+ ):
+ reg3.dispose()