diff options
| author | mike bayer <mike_mp@zzzcomputing.com> | 2021-02-01 23:13:42 +0000 |
|---|---|---|
| committer | Gerrit Code Review <gerrit@bbpush.zzzcomputing.com> | 2021-02-01 23:13:42 +0000 |
| commit | 45c8fe6c0a755aa7a777dd0c12f97bb52dcc00a7 (patch) | |
| tree | 2420ca661194e1d7cbac87854c970b45d1ba490f /test | |
| parent | e917041d1e5d6349372a80222e6d9e32cfa07082 (diff) | |
| parent | 5ec5b0a6c7b618bba7926e21f77be9557973860f (diff) | |
| download | sqlalchemy-45c8fe6c0a755aa7a777dd0c12f97bb52dcc00a7.tar.gz | |
Merge "reorganize mapper compile/teardown under registry"
Diffstat (limited to 'test')
| -rw-r--r-- | test/aaa_profiling/test_memusage.py | 4 | ||||
| -rw-r--r-- | test/ext/declarative/test_inheritance.py | 4 | ||||
| -rw-r--r-- | test/orm/declarative/test_basic.py | 6 | ||||
| -rw-r--r-- | test/orm/test_events.py | 37 | ||||
| -rw-r--r-- | test/orm/test_mapper.py | 196 |
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() |
