From: Mike Bayer Date: Mon, 17 Mar 2025 12:53:00 +0000 (-0400) Subject: remove non_primary parameter X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=5ec437a905d0320a9c3bbca90bb27af327ba3707;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git remove non_primary parameter The "non primary" mapper feature, long deprecated in SQLAlchemy since version 1.3, has been removed. The sole use case for "non primary" mappers was that of using :func:`_orm.relationship` to link to a mapped class against an alternative selectable; this use case is now suited by the :doc:`relationship_aliased_class` feature. Fixes: #12437 Change-Id: I6987da06beb1d88d6f6e9696ce93e7fc340fc0ef --- diff --git a/doc/build/changelog/unreleased_21/12437.rst b/doc/build/changelog/unreleased_21/12437.rst new file mode 100644 index 0000000000..d3aa2092a8 --- /dev/null +++ b/doc/build/changelog/unreleased_21/12437.rst @@ -0,0 +1,11 @@ +.. change:: + :tags: orm, changed + :tickets: 12437 + + The "non primary" mapper feature, long deprecated in SQLAlchemy since + version 1.3, has been removed. The sole use case for "non primary" + mappers was that of using :func:`_orm.relationship` to link to a mapped + class against an alternative selectable; this use case is now suited by the + :doc:`relationship_aliased_class` feature. + + diff --git a/lib/sqlalchemy/ext/mutable.py b/lib/sqlalchemy/ext/mutable.py index 9ead5959be..4e69a548d7 100644 --- a/lib/sqlalchemy/ext/mutable.py +++ b/lib/sqlalchemy/ext/mutable.py @@ -649,8 +649,6 @@ class Mutable(MutableBase): """ def listen_for_type(mapper: Mapper[_O], class_: type) -> None: - if mapper.non_primary: - return for prop in mapper.column_attrs: if isinstance(prop.columns[0].type, sqltype): cls.associate_with_attribute(getattr(class_, prop.key)) @@ -714,8 +712,6 @@ class Mutable(MutableBase): mapper: Mapper[_T], class_: Union[DeclarativeAttributeIntercept, type], ) -> None: - if mapper.non_primary: - return _APPLIED_KEY = "_ext_mutable_listener_applied" for prop in mapper.column_attrs: diff --git a/lib/sqlalchemy/ext/serializer.py b/lib/sqlalchemy/ext/serializer.py index b7032b6595..19078c4450 100644 --- a/lib/sqlalchemy/ext/serializer.py +++ b/lib/sqlalchemy/ext/serializer.py @@ -90,9 +90,9 @@ class Serializer(pickle.Pickler): def persistent_id(self, obj): # print "serializing:", repr(obj) - if isinstance(obj, Mapper) and not obj.non_primary: + if isinstance(obj, Mapper): id_ = "mapper:" + b64encode(pickle.dumps(obj.class_)) - elif isinstance(obj, MapperProperty) and not obj.parent.non_primary: + elif isinstance(obj, MapperProperty): id_ = ( "mapperprop:" + b64encode(pickle.dumps(obj.parent.class_)) diff --git a/lib/sqlalchemy/orm/decl_api.py b/lib/sqlalchemy/orm/decl_api.py index e01ad61362..daafc83f14 100644 --- a/lib/sqlalchemy/orm/decl_api.py +++ b/lib/sqlalchemy/orm/decl_api.py @@ -9,7 +9,6 @@ from __future__ import annotations -import itertools import re import typing from typing import Any @@ -1135,7 +1134,6 @@ class registry: _class_registry: clsregistry._ClsRegistryType _managers: weakref.WeakKeyDictionary[ClassManager[Any], Literal[True]] - _non_primary_mappers: weakref.WeakKeyDictionary[Mapper[Any], Literal[True]] metadata: MetaData constructor: CallableReference[Callable[..., None]] type_annotation_map: _MutableTypeAnnotationMapType @@ -1197,7 +1195,6 @@ class registry: self._class_registry = class_registry self._managers = weakref.WeakKeyDictionary() - self._non_primary_mappers = weakref.WeakKeyDictionary() self.metadata = lcl_metadata self.constructor = constructor self.type_annotation_map = {} @@ -1277,9 +1274,7 @@ class registry: def mappers(self) -> FrozenSet[Mapper[Any]]: """read only collection of all :class:`_orm.Mapper` objects.""" - return frozenset(manager.mapper for manager in self._managers).union( - self._non_primary_mappers - ) + return frozenset(manager.mapper for manager in self._managers) def _set_depends_on(self, registry: RegistryType) -> None: if registry is self: @@ -1335,24 +1330,14 @@ class registry: todo.update(reg._dependencies.difference(done)) def _mappers_to_configure(self) -> Iterator[Mapper[Any]]: - return itertools.chain( - ( - manager.mapper - for manager in list(self._managers) - if manager.is_mapped - and not manager.mapper.configured - and manager.mapper._ready_for_configure - ), - ( - npm - for npm in list(self._non_primary_mappers) - if not npm.configured and npm._ready_for_configure - ), + return ( + manager.mapper + for manager in list(self._managers) + if manager.is_mapped + and not manager.mapper.configured + and manager.mapper._ready_for_configure ) - def _add_non_primary_mapper(self, np_mapper: Mapper[Any]) -> None: - self._non_primary_mappers[np_mapper] = True - def _dispose_cls(self, cls: Type[_O]) -> None: clsregistry._remove_class(cls.__name__, cls, self._class_registry) diff --git a/lib/sqlalchemy/orm/decl_base.py b/lib/sqlalchemy/orm/decl_base.py index a2291d2d75..911de09c83 100644 --- a/lib/sqlalchemy/orm/decl_base.py +++ b/lib/sqlalchemy/orm/decl_base.py @@ -337,22 +337,13 @@ class _MapperConfig: self.properties = util.OrderedDict() self.declared_attr_reg = {} - if not mapper_kw.get("non_primary", False): - instrumentation.register_class( - self.cls, - finalize=False, - registry=registry, - declarative_scan=self, - init_method=registry.constructor, - ) - else: - manager = attributes.opt_manager_of_class(self.cls) - if not manager or not manager.is_mapped: - raise exc.InvalidRequestError( - "Class %s has no primary mapper configured. Configure " - "a primary mapper first before setting up a non primary " - "Mapper." % self.cls - ) + instrumentation.register_class( + self.cls, + finalize=False, + registry=registry, + declarative_scan=self, + init_method=registry.constructor, + ) def set_cls_attribute(self, attrname: str, value: _T) -> _T: manager = instrumentation.manager_of_class(self.cls) @@ -381,10 +372,9 @@ class _ImperativeMapperConfig(_MapperConfig): self.local_table = self.set_cls_attribute("__table__", table) with mapperlib._CONFIGURE_MUTEX: - if not mapper_kw.get("non_primary", False): - clsregistry._add_class( - self.classname, self.cls, registry._class_registry - ) + clsregistry._add_class( + self.classname, self.cls, registry._class_registry + ) self._setup_inheritance(mapper_kw) diff --git a/lib/sqlalchemy/orm/interfaces.py b/lib/sqlalchemy/orm/interfaces.py index 26c2942949..1cedd39102 100644 --- a/lib/sqlalchemy/orm/interfaces.py +++ b/lib/sqlalchemy/orm/interfaces.py @@ -1109,10 +1109,7 @@ class StrategizedProperty(MapperProperty[_T]): self.strategy = self._get_strategy(self.strategy_key) def post_instrument_class(self, mapper: Mapper[Any]) -> None: - if ( - not self.parent.non_primary - and not mapper.class_manager._attr_has_impl(self.key) - ): + if not mapper.class_manager._attr_has_impl(self.key): self.strategy.init_class_attribute(mapper) _all_strategies: collections.defaultdict[ diff --git a/lib/sqlalchemy/orm/mapper.py b/lib/sqlalchemy/orm/mapper.py index 6fb46a2bd8..613ce9aa74 100644 --- a/lib/sqlalchemy/orm/mapper.py +++ b/lib/sqlalchemy/orm/mapper.py @@ -190,23 +190,12 @@ class Mapper( _configure_failed: Any = False _ready_for_configure = False - @util.deprecated_params( - non_primary=( - "1.3", - "The :paramref:`.mapper.non_primary` parameter is deprecated, " - "and will be removed in a future release. The functionality " - "of non primary mappers is now better suited using the " - ":class:`.AliasedClass` construct, which can also be used " - "as the target of a :func:`_orm.relationship` in 1.3.", - ), - ) def __init__( self, class_: Type[_O], local_table: Optional[FromClause] = None, properties: Optional[Mapping[str, MapperProperty[Any]]] = None, primary_key: Optional[Iterable[_ORMColumnExprArgument[Any]]] = None, - non_primary: bool = False, inherits: Optional[Union[Mapper[Any], Type[Any]]] = None, inherit_condition: Optional[_ColumnExpressionArgument[bool]] = None, inherit_foreign_keys: Optional[ @@ -448,18 +437,6 @@ class Mapper( See the change note and example at :ref:`legacy_is_orphan_addition` for more detail on this change. - :param non_primary: Specify that this :class:`_orm.Mapper` - is in addition - to the "primary" mapper, that is, the one used for persistence. - The :class:`_orm.Mapper` created here may be used for ad-hoc - mapping of the class to an alternate selectable, for loading - only. - - .. seealso:: - - :ref:`relationship_aliased_class` - the new pattern that removes - the need for the :paramref:`_orm.Mapper.non_primary` flag. - :param passive_deletes: Indicates DELETE behavior of foreign key columns when a joined-table inheritance entity is being deleted. Defaults to ``False`` for a base mapper; for an inheriting mapper, @@ -734,7 +711,6 @@ class Mapper( ) self._primary_key_argument = util.to_list(primary_key) - self.non_primary = non_primary self.always_refresh = always_refresh @@ -1102,16 +1078,6 @@ class Mapper( """ - non_primary: bool - """Represent ``True`` if this :class:`_orm.Mapper` is a "non-primary" - mapper, e.g. a mapper that is used only to select rows but not for - persistence management. - - This is a *read only* attribute determined during mapper construction. - Behavior is undefined if directly modified. - - """ - polymorphic_on: Optional[KeyedColumnElement[Any]] """The :class:`_schema.Column` or SQL expression specified as the ``polymorphic_on`` argument @@ -1213,14 +1179,6 @@ class Mapper( self.dispatch._update(self.inherits.dispatch) - if self.non_primary != self.inherits.non_primary: - np = not self.non_primary and "primary" or "non-primary" - raise sa_exc.ArgumentError( - "Inheritance of %s mapper for class '%s' is " - "only allowed from a %s mapper" - % (np, self.class_.__name__, np) - ) - if self.single: self.persist_selectable = self.inherits.persist_selectable elif self.local_table is not self.inherits.local_table: @@ -1468,8 +1426,7 @@ class Mapper( self._configure_polymorphic_setter(True) def _configure_class_instrumentation(self): - """If this mapper is to be a primary mapper (i.e. the - non_primary flag is not set), associate this Mapper with the + """Associate this Mapper with the given class and entity name. Subsequent calls to ``class_mapper()`` for the ``class_`` / ``entity`` @@ -1484,21 +1441,6 @@ class Mapper( # this raises as of 2.0. manager = attributes.opt_manager_of_class(self.class_) - if self.non_primary: - if not manager or not manager.is_mapped: - raise sa_exc.InvalidRequestError( - "Class %s has no primary mapper configured. Configure " - "a primary mapper first before setting up a non primary " - "Mapper." % self.class_ - ) - self.class_manager = manager - - assert manager.registry is not None - self.registry = manager.registry - self._identity_class = manager.mapper._identity_class - manager.registry._add_non_primary_mapper(self) - return - if manager is None or not manager.registry: raise sa_exc.InvalidRequestError( "The _mapper() function and Mapper() constructor may not be " @@ -2242,8 +2184,7 @@ class Mapper( self._props[key] = prop - if not self.non_primary: - prop.instrument_class(self) + prop.instrument_class(self) for mapper in self._inheriting_mappers: mapper._adapt_inherited_property(key, prop, init) @@ -2464,7 +2405,6 @@ class Mapper( and self.local_table.description or str(self.local_table) ) - + (self.non_primary and "|non-primary" or "") + ")" ) @@ -2478,9 +2418,8 @@ class Mapper( return "" % (id(self), self.class_.__name__) def __str__(self) -> str: - return "Mapper[%s%s(%s)]" % ( + return "Mapper[%s(%s)]" % ( self.class_.__name__, - self.non_primary and " (non-primary)" or "", ( self.local_table.description if self.local_table is not None @@ -4306,7 +4245,6 @@ def _dispose_registries(registries: Set[_RegistryType], cascade: bool) -> None: else: reg._dispose_manager_and_mapper(manager) - reg._non_primary_mappers.clear() reg._dependents.clear() for dep in reg._dependencies: dep._dependents.discard(reg) diff --git a/lib/sqlalchemy/orm/relationships.py b/lib/sqlalchemy/orm/relationships.py index 608962b2bd..390ea7aee4 100644 --- a/lib/sqlalchemy/orm/relationships.py +++ b/lib/sqlalchemy/orm/relationships.py @@ -1690,7 +1690,6 @@ class RelationshipProperty( return self.entity.mapper def do_init(self) -> None: - self._check_conflicts() self._process_dependent_arguments() self._setup_entity() self._setup_registry_dependencies() @@ -1988,25 +1987,6 @@ class RelationshipProperty( return _resolver(self.parent.class_, self) - def _check_conflicts(self) -> None: - """Test that this relationship is legal, warn about - inheritance conflicts.""" - if self.parent.non_primary and not class_mapper( - self.parent.class_, configure=False - ).has_property(self.key): - raise sa_exc.ArgumentError( - "Attempting to assign a new " - "relationship '%s' to a non-primary mapper on " - "class '%s'. New relationships can only be added " - "to the primary mapper, i.e. the very first mapper " - "created for class '%s' " - % ( - self.key, - self.parent.class_.__name__, - self.parent.class_.__name__, - ) - ) - @property def cascade(self) -> CascadeOptions: """Return the current cascade setting for this @@ -2110,9 +2090,6 @@ class RelationshipProperty( """Interpret the 'backref' instruction to create a :func:`_orm.relationship` complementary to this one.""" - if self.parent.non_primary: - return - resolve_back_populates = self._init_args.back_populates.resolved if self.backref is not None and not resolve_back_populates: diff --git a/test/ext/test_deprecations.py b/test/ext/test_deprecations.py index 653a021579..119e40b358 100644 --- a/test/ext/test_deprecations.py +++ b/test/ext/test_deprecations.py @@ -6,8 +6,6 @@ from sqlalchemy.ext.horizontal_shard import ShardedSession from sqlalchemy.testing import eq_ from sqlalchemy.testing import fixtures from sqlalchemy.testing import mock -from . import test_mutable -from .test_mutable import Foo from ..orm._fixtures import FixtureTest @@ -35,36 +33,6 @@ class AutomapTest(fixtures.MappedTest): ) -class MutableIncludeNonPrimaryTest(test_mutable.MutableWithScalarJSONTest): - @classmethod - def setup_mappers(cls): - foo = cls.tables.foo - - cls.mapper_registry.map_imperatively(Foo, foo) - with testing.expect_deprecated( - "The mapper.non_primary parameter is deprecated" - ): - cls.mapper_registry.map_imperatively( - Foo, foo, non_primary=True, properties={"foo_bar": foo.c.data} - ) - - -class MutableAssocIncludeNonPrimaryTest( - test_mutable.MutableAssociationScalarPickleTest -): - @classmethod - def setup_mappers(cls): - foo = cls.tables.foo - - cls.mapper_registry.map_imperatively(Foo, foo) - with testing.expect_deprecated( - "The mapper.non_primary parameter is deprecated" - ): - cls.mapper_registry.map_imperatively( - Foo, foo, non_primary=True, properties={"foo_bar": foo.c.data} - ) - - class HorizontalShardTest(fixtures.TestBase): def test_query_chooser(self): m1 = mock.Mock() diff --git a/test/orm/test_deprecations.py b/test/orm/test_deprecations.py index fa04a19d3e..211c8c3dc2 100644 --- a/test/orm/test_deprecations.py +++ b/test/orm/test_deprecations.py @@ -25,7 +25,6 @@ from sqlalchemy.orm import attributes from sqlalchemy.orm import clear_mappers from sqlalchemy.orm import collections from sqlalchemy.orm import column_property -from sqlalchemy.orm import configure_mappers from sqlalchemy.orm import contains_alias from sqlalchemy.orm import contains_eager from sqlalchemy.orm import defaultload @@ -44,7 +43,6 @@ from sqlalchemy.orm import strategies from sqlalchemy.orm import subqueryload from sqlalchemy.orm import synonym from sqlalchemy.orm import undefer -from sqlalchemy.orm import with_parent from sqlalchemy.orm import with_polymorphic from sqlalchemy.orm.collections import collection from sqlalchemy.orm.strategy_options import lazyload @@ -1013,294 +1011,6 @@ class InstrumentationTest(fixtures.ORMTest): eq_(Sub._sa_converter(Sub(), 5), "sub_convert") -class NonPrimaryRelationshipLoaderTest(_fixtures.FixtureTest): - run_inserts = "once" - run_deletes = None - - def test_selectload(self): - """tests lazy loading with two relationships simultaneously, - from the same table, using aliases.""" - - users, orders, User, Address, Order, addresses = ( - self.tables.users, - self.tables.orders, - self.classes.User, - self.classes.Address, - self.classes.Order, - self.tables.addresses, - ) - - openorders = sa.alias(orders, "openorders") - closedorders = sa.alias(orders, "closedorders") - - self.mapper_registry.map_imperatively(Address, addresses) - - self.mapper_registry.map_imperatively(Order, orders) - - with testing.expect_deprecated( - "The mapper.non_primary parameter is deprecated" - ): - open_mapper = self.mapper_registry.map_imperatively( - Order, openorders, non_primary=True - ) - closed_mapper = self.mapper_registry.map_imperatively( - Order, closedorders, non_primary=True - ) - self.mapper_registry.map_imperatively( - User, - users, - properties=dict( - addresses=relationship(Address, lazy=True), - open_orders=relationship( - open_mapper, - primaryjoin=sa.and_( - openorders.c.isopen == 1, - users.c.id == openorders.c.user_id, - ), - lazy="select", - ), - closed_orders=relationship( - closed_mapper, - primaryjoin=sa.and_( - closedorders.c.isopen == 0, - users.c.id == closedorders.c.user_id, - ), - lazy="select", - ), - ), - ) - - self._run_double_test(10) - - def test_joinedload(self): - """Eager loading with two relationships simultaneously, - from the same table, using aliases.""" - - users, orders, User, Address, Order, addresses = ( - self.tables.users, - self.tables.orders, - self.classes.User, - self.classes.Address, - self.classes.Order, - self.tables.addresses, - ) - - openorders = sa.alias(orders, "openorders") - closedorders = sa.alias(orders, "closedorders") - - self.mapper_registry.map_imperatively(Address, addresses) - self.mapper_registry.map_imperatively(Order, orders) - - with testing.expect_deprecated( - "The mapper.non_primary parameter is deprecated" - ): - open_mapper = self.mapper_registry.map_imperatively( - Order, openorders, non_primary=True - ) - closed_mapper = self.mapper_registry.map_imperatively( - Order, closedorders, non_primary=True - ) - - self.mapper_registry.map_imperatively( - User, - users, - properties=dict( - addresses=relationship( - Address, lazy="joined", order_by=addresses.c.id - ), - open_orders=relationship( - open_mapper, - primaryjoin=sa.and_( - openorders.c.isopen == 1, - users.c.id == openorders.c.user_id, - ), - lazy="joined", - order_by=openorders.c.id, - ), - closed_orders=relationship( - closed_mapper, - primaryjoin=sa.and_( - closedorders.c.isopen == 0, - users.c.id == closedorders.c.user_id, - ), - lazy="joined", - order_by=closedorders.c.id, - ), - ), - ) - self._run_double_test(1) - - def test_selectin(self): - users, orders, User, Address, Order, addresses = ( - self.tables.users, - self.tables.orders, - self.classes.User, - self.classes.Address, - self.classes.Order, - self.tables.addresses, - ) - - openorders = sa.alias(orders, "openorders") - closedorders = sa.alias(orders, "closedorders") - - self.mapper_registry.map_imperatively(Address, addresses) - self.mapper_registry.map_imperatively(Order, orders) - - with testing.expect_deprecated( - "The mapper.non_primary parameter is deprecated" - ): - open_mapper = self.mapper_registry.map_imperatively( - Order, openorders, non_primary=True - ) - closed_mapper = self.mapper_registry.map_imperatively( - Order, closedorders, non_primary=True - ) - - self.mapper_registry.map_imperatively( - User, - users, - properties=dict( - addresses=relationship( - Address, lazy="selectin", order_by=addresses.c.id - ), - open_orders=relationship( - open_mapper, - primaryjoin=sa.and_( - openorders.c.isopen == 1, - users.c.id == openorders.c.user_id, - ), - lazy="selectin", - order_by=openorders.c.id, - ), - closed_orders=relationship( - closed_mapper, - primaryjoin=sa.and_( - closedorders.c.isopen == 0, - users.c.id == closedorders.c.user_id, - ), - lazy="selectin", - order_by=closedorders.c.id, - ), - ), - ) - - self._run_double_test(4) - - def test_subqueryload(self): - users, orders, User, Address, Order, addresses = ( - self.tables.users, - self.tables.orders, - self.classes.User, - self.classes.Address, - self.classes.Order, - self.tables.addresses, - ) - - openorders = sa.alias(orders, "openorders") - closedorders = sa.alias(orders, "closedorders") - - self.mapper_registry.map_imperatively(Address, addresses) - self.mapper_registry.map_imperatively(Order, orders) - - with testing.expect_deprecated( - "The mapper.non_primary parameter is deprecated" - ): - open_mapper = self.mapper_registry.map_imperatively( - Order, openorders, non_primary=True - ) - closed_mapper = self.mapper_registry.map_imperatively( - Order, closedorders, non_primary=True - ) - - self.mapper_registry.map_imperatively( - User, - users, - properties=dict( - addresses=relationship( - Address, lazy="subquery", order_by=addresses.c.id - ), - open_orders=relationship( - open_mapper, - primaryjoin=sa.and_( - openorders.c.isopen == 1, - users.c.id == openorders.c.user_id, - ), - lazy="subquery", - order_by=openorders.c.id, - ), - closed_orders=relationship( - closed_mapper, - primaryjoin=sa.and_( - closedorders.c.isopen == 0, - users.c.id == closedorders.c.user_id, - ), - lazy="subquery", - order_by=closedorders.c.id, - ), - ), - ) - - self._run_double_test(4) - - def _run_double_test(self, count): - User, Address, Order, Item = self.classes( - "User", "Address", "Order", "Item" - ) - q = fixture_session().query(User).order_by(User.id) - - def go(): - eq_( - [ - User( - id=7, - addresses=[Address(id=1)], - open_orders=[Order(id=3)], - closed_orders=[Order(id=1), Order(id=5)], - ), - User( - id=8, - addresses=[ - Address(id=2), - Address(id=3), - Address(id=4), - ], - open_orders=[], - closed_orders=[], - ), - User( - id=9, - addresses=[Address(id=5)], - open_orders=[Order(id=4)], - closed_orders=[Order(id=2)], - ), - User(id=10), - ], - q.all(), - ) - - self.assert_sql_count(testing.db, go, count) - - sess = fixture_session() - user = sess.get(User, 7) - - closed_mapper = User.closed_orders.entity - open_mapper = User.open_orders.entity - eq_( - [Order(id=1), Order(id=5)], - fixture_session() - .query(closed_mapper) - .filter(with_parent(user, User.closed_orders)) - .all(), - ) - eq_( - [Order(id=3)], - fixture_session() - .query(open_mapper) - .filter(with_parent(user, User.open_orders)) - .all(), - ) - - class ViewonlyFlagWarningTest(fixtures.MappedTest): """test for #4993. @@ -1357,157 +1067,6 @@ class ViewonlyFlagWarningTest(fixtures.MappedTest): eq_(getattr(rel, flag), value) -class NonPrimaryMapperTest(_fixtures.FixtureTest, AssertsCompiledSQL): - __dialect__ = "default" - - def teardown_test(self): - clear_mappers() - - def test_non_primary_identity_class(self): - User = self.classes.User - users, addresses = self.tables.users, self.tables.addresses - - class AddressUser(User): - pass - - self.mapper_registry.map_imperatively( - User, users, polymorphic_identity="user" - ) - m2 = self.mapper_registry.map_imperatively( - AddressUser, - addresses, - inherits=User, - polymorphic_identity="address", - properties={"address_id": addresses.c.id}, - ) - with testing.expect_deprecated( - "The mapper.non_primary parameter is deprecated" - ): - m3 = self.mapper_registry.map_imperatively( - AddressUser, addresses, non_primary=True - ) - assert m3._identity_class is m2._identity_class - eq_( - m2.identity_key_from_instance(AddressUser()), - m3.identity_key_from_instance(AddressUser()), - ) - - def test_illegal_non_primary(self): - users, Address, addresses, User = ( - self.tables.users, - self.classes.Address, - self.tables.addresses, - self.classes.User, - ) - - self.mapper_registry.map_imperatively(User, users) - self.mapper_registry.map_imperatively(Address, addresses) - with testing.expect_deprecated( - "The mapper.non_primary parameter is deprecated" - ): - m = self.mapper_registry.map_imperatively( # noqa: F841 - User, - users, - non_primary=True, - properties={"addresses": relationship(Address)}, - ) - assert_raises_message( - sa.exc.ArgumentError, - "Attempting to assign a new relationship 'addresses' " - "to a non-primary mapper on class 'User'", - configure_mappers, - ) - - def test_illegal_non_primary_2(self): - User, users = self.classes.User, self.tables.users - - assert_raises_message( - sa.exc.InvalidRequestError, - "Configure a primary mapper first", - self.mapper_registry.map_imperatively, - User, - users, - non_primary=True, - ) - - def test_illegal_non_primary_3(self): - users, addresses = self.tables.users, self.tables.addresses - - class Base: - pass - - class Sub(Base): - pass - - self.mapper_registry.map_imperatively(Base, users) - assert_raises_message( - sa.exc.InvalidRequestError, - "Configure a primary mapper first", - self.mapper_registry.map_imperatively, - Sub, - addresses, - non_primary=True, - ) - - def test_illegal_non_primary_legacy(self, registry): - users, Address, addresses, User = ( - self.tables.users, - self.classes.Address, - self.tables.addresses, - self.classes.User, - ) - - registry.map_imperatively(User, users) - registry.map_imperatively(Address, addresses) - with testing.expect_deprecated( - "The mapper.non_primary parameter is deprecated" - ): - m = registry.map_imperatively( # noqa: F841 - User, - users, - non_primary=True, - properties={"addresses": relationship(Address)}, - ) - assert_raises_message( - sa.exc.ArgumentError, - "Attempting to assign a new relationship 'addresses' " - "to a non-primary mapper on class 'User'", - configure_mappers, - ) - - def test_illegal_non_primary_2_legacy(self, registry): - User, users = self.classes.User, self.tables.users - - assert_raises_message( - sa.exc.InvalidRequestError, - "Configure a primary mapper first", - registry.map_imperatively, - User, - users, - non_primary=True, - ) - - def test_illegal_non_primary_3_legacy(self, registry): - users, addresses = self.tables.users, self.tables.addresses - - class Base: - pass - - class Sub(Base): - pass - - registry.map_imperatively(Base, users) - - assert_raises_message( - sa.exc.InvalidRequestError, - "Configure a primary mapper first", - registry.map_imperatively, - Sub, - addresses, - non_primary=True, - ) - - class InstancesTest(QueryTest, AssertsCompiledSQL): @testing.fails( "ORM refactor not allowing this yet, "