From 92aa35e7fc737de58c25d6c22bf1c48f6c4c714b Mon Sep 17 00:00:00 2001 From: Mike Bayer Date: Wed, 20 Oct 2021 12:50:53 -0400 Subject: [PATCH] deprecation warnings: strings in loader options, join, with_parent Repairs one in-library deprecation warning regarding mapper propagation of options raises maxfail to 250, as 25 is too low when we are trying to address many errors at once. the 25 was originally due to the fact that our fixtures would be broken after that many failures in most cases, which today should not be the case nearly as often. Change-Id: I26affddf42e2cae2aaf9561633e9b8cd431eb189 --- lib/sqlalchemy/ext/associationproxy.py | 19 +- lib/sqlalchemy/orm/mapper.py | 10 +- lib/sqlalchemy/orm/strategy_options.py | 3 +- lib/sqlalchemy/testing/warnings.py | 8 - setup.cfg | 2 +- test/ext/test_associationproxy.py | 10 +- test/ext/test_horizontal_shard.py | 2 +- test/orm/inheritance/test_assorted_poly.py | 12 +- test/orm/inheritance/test_basic.py | 2 +- test/orm/inheritance/test_polymorphic_rel.py | 64 +- test/orm/inheritance/test_relationship.py | 23 +- test/orm/inheritance/test_single.py | 6 +- test/orm/test_ac_relationships.py | 8 +- test/orm/test_assorted_eager.py | 26 +- test/orm/test_cache_key.py | 44 +- test/orm/test_composites.py | 4 +- test/orm/test_default_strategies.py | 96 +- test/orm/test_deferred.py | 135 +- test/orm/test_deprecations.py | 1343 +++++++++++++++++- test/orm/test_eager_relations.py | 20 +- test/orm/test_expire.py | 10 +- test/orm/test_froms.py | 180 +-- test/orm/test_generative.py | 10 +- test/orm/test_joins.py | 11 - test/orm/test_lazy_relations.py | 6 +- test/orm/test_mapper.py | 16 +- test/orm/test_merge.py | 4 +- test/orm/test_of_type.py | 3 +- test/orm/test_options.py | 306 +--- test/orm/test_pickled.py | 26 +- test/orm/test_query.py | 146 +- test/orm/test_relationships.py | 16 +- test/orm/test_selectin_relations.py | 27 +- test/orm/test_subquery_relations.py | 32 +- test/orm/test_unitofwork.py | 2 +- 35 files changed, 1792 insertions(+), 840 deletions(-) diff --git a/lib/sqlalchemy/ext/associationproxy.py b/lib/sqlalchemy/ext/associationproxy.py index 411033a6bf..dd5c10ac95 100644 --- a/lib/sqlalchemy/ext/associationproxy.py +++ b/lib/sqlalchemy/ext/associationproxy.py @@ -472,10 +472,23 @@ class AssociationProxyInstance(object): def attr(self): """Return a tuple of ``(local_attr, remote_attr)``. - This attribute is convenient when specifying a join - using :meth:`_query.Query.join` across two relationships:: + This attribute was originally intended to facilitate using the + :meth:`_query.Query.join` method to join across the two relationships + at once, however this makes use of a deprecated calling style. + + To use :meth:`_sql.select.join` or :meth:`_orm.Query.join` with + an association proxy, the current method is to make use of the + :attr:`.AssociationProxyInstance.local_attr` and + :attr:`.AssociationProxyInstance.remote_attr` attributes separately:: + + stmt = ( + select(Parent). + join(Parent.proxied.local_attr). + join(Parent.proxied.remote_attr) + ) - sess.query(Parent).join(*Parent.proxied.attr) + A future release may seek to provide a more succinct join pattern + for association proxy attributes. .. seealso:: diff --git a/lib/sqlalchemy/orm/mapper.py b/lib/sqlalchemy/orm/mapper.py index 1aa6666a55..4de12b88c7 100644 --- a/lib/sqlalchemy/orm/mapper.py +++ b/lib/sqlalchemy/orm/mapper.py @@ -3111,14 +3111,20 @@ class Mapper( # "enable" options, to turn on the properties that we want to # load by default (subject to options from the query) enable_opt.set_generic_strategy( - (prop.key,), dict(prop.strategy_key) + # convert string name to an attribute before passing + # to loader strategy + (getattr(entity.entity_namespace, prop.key),), + dict(prop.strategy_key), ) else: # "disable" options, to turn off the properties from the # superclass that we *don't* want to load, applied after # the options from the query to override them disable_opt.set_generic_strategy( - (prop.key,), {"do_nothing": True} + # convert string name to an attribute before passing + # to loader strategy + (getattr(entity.entity_namespace, prop.key),), + {"do_nothing": True}, ) primary_key = [ diff --git a/lib/sqlalchemy/orm/strategy_options.py b/lib/sqlalchemy/orm/strategy_options.py index b7ed4e89bb..675c7218bd 100644 --- a/lib/sqlalchemy/orm/strategy_options.py +++ b/lib/sqlalchemy/orm/strategy_options.py @@ -301,6 +301,7 @@ class Load(Generative, LoaderOption): ) if isinstance(attr, util.string_types): + default_token = attr.endswith(_DEFAULT_TOKEN) attr_str_name = attr if attr.endswith(_WILDCARD_TOKEN) or default_token: @@ -328,7 +329,7 @@ class Load(Generative, LoaderOption): "Using strings to indicate column or " "relationship paths in loader options is deprecated " "and will be removed in SQLAlchemy 2.0. Please use " - "the class-bound attribute directly." + "the class-bound attribute directly.", ) try: # use getattr on the class to work around diff --git a/lib/sqlalchemy/testing/warnings.py b/lib/sqlalchemy/testing/warnings.py index 9e02a0c03b..9886b122d1 100644 --- a/lib/sqlalchemy/testing/warnings.py +++ b/lib/sqlalchemy/testing/warnings.py @@ -73,16 +73,8 @@ def setup_filters(): r"The Query\.with_parent\(\) method", r"The Query\.select_entity_from\(\) method", r"The ``aliased`` and ``from_joinpoint`` keyword arguments", - r"Using strings to indicate relationship names in Query.join", - r"Using strings to indicate column or relationship paths in " - "loader options", - r"Using strings to indicate relationship names in the ORM " - r"with_parent\(\)", r"The Query.with_polymorphic\(\) method is considered " "legacy as of the 1.x series", - r"Passing a chain of multiple join conditions to Query.join\(\) " - r"is deprecated and will be removed in SQLAlchemy 2.0.", - r"Query.join\(\) will no longer accept tuples as arguments", # # ORM Session # diff --git a/setup.cfg b/setup.cfg index 7df0ad5c85..f432561b18 100644 --- a/setup.cfg +++ b/setup.cfg @@ -92,7 +92,7 @@ tag_build = dev where = lib [tool:pytest] -addopts = --tb native -v -r sfxX --maxfail=25 -p no:warnings -p no:logging +addopts = --tb native -v -r sfxX --maxfail=250 -p no:warnings -p no:logging python_files = test/*test_*.py [upload] diff --git a/test/ext/test_associationproxy.py b/test/ext/test_associationproxy.py index bbb430a6f5..258ecb90c4 100644 --- a/test/ext/test_associationproxy.py +++ b/test/ext/test_associationproxy.py @@ -2277,9 +2277,9 @@ class ComparatorTest(fixtures.MappedTest, AssertsCompiledSQL): def test_join_separate_attr(self): User = self.classes.User self.assert_compile( - self.session.query(User).join( - User.keywords.local_attr, User.keywords.remote_attr - ), + self.session.query(User) + .join(User.keywords.local_attr) + .join(User.keywords.remote_attr), "SELECT users.id AS users_id, users.name AS users_name, " "users.singular_id AS users_singular_id " "FROM users JOIN userkeywords ON users.id = " @@ -2290,7 +2290,9 @@ class ComparatorTest(fixtures.MappedTest, AssertsCompiledSQL): def test_join_single_attr(self): User = self.classes.User self.assert_compile( - self.session.query(User).join(*User.keywords.attr), + self.session.query(User) + .join(User.keywords.attr[0]) + .join(User.keywords.attr[1]), "SELECT users.id AS users_id, users.name AS users_name, " "users.singular_id AS users_singular_id " "FROM users JOIN userkeywords ON users.id = " diff --git a/test/ext/test_horizontal_shard.py b/test/ext/test_horizontal_shard.py index a0bc8bbe54..192617901e 100644 --- a/test/ext/test_horizontal_shard.py +++ b/test/ext/test_horizontal_shard.py @@ -863,7 +863,7 @@ class SelectinloadRegressionTest(fixtures.DeclarativeMappedTest): session.add(book) session.commit() - result = session.query(Book).options(selectinload("pages")).all() + result = session.query(Book).options(selectinload(Book.pages)).all() eq_(result, [book]) diff --git a/test/orm/inheritance/test_assorted_poly.py b/test/orm/inheritance/test_assorted_poly.py index 2db4641ddd..729e1ee047 100644 --- a/test/orm/inheritance/test_assorted_poly.py +++ b/test/orm/inheritance/test_assorted_poly.py @@ -641,7 +641,7 @@ class RelationshipTest4(fixtures.MappedTest): def go(): testcar = session.get( - Car, car1.car_id, options=[joinedload("employee")] + Car, car1.car_id, options=[joinedload(Car.employee)] ) assert str(testcar.employee) == "Engineer E4, status X" @@ -662,7 +662,7 @@ class RelationshipTest4(fixtures.MappedTest): testcar = session.get( Car, car1.car_id, - options=[joinedload("employee")], + options=[joinedload(Car.employee)], ) assert str(testcar.employee) == "Engineer E4, status X" @@ -670,7 +670,7 @@ class RelationshipTest4(fixtures.MappedTest): session.expunge_all() s = session.query(Car) - c = s.join("employee").filter(Person.name == "E4")[0] + c = s.join(Car.employee).filter(Person.name == "E4")[0] assert c.car_id == car1.car_id @@ -1449,7 +1449,7 @@ class GenerativeTest(fixtures.MappedTest, AssertsExecutionResults): r = ( session.query(Person) .filter(Person.name.like("%2")) - .join("status") + .join(Person.status) .filter_by(name="active") .order_by(Person.person_id) ) @@ -1472,7 +1472,7 @@ class GenerativeTest(fixtures.MappedTest, AssertsExecutionResults): session = fixture_session() r = ( session.query(Engineer) - .join("status") + .join(Engineer.status) .filter( Person.name.in_(["E2", "E3", "E4", "M4", "M2", "M1"]) & (Status.name == "active") @@ -2226,7 +2226,7 @@ class Ticket2419Test(fixtures.DeclarativeMappedTest): s.commit() - q = s.query(B, B.ds.any(D.id == 1)).options(joinedload("es")) + q = s.query(B, B.ds.any(D.id == 1)).options(joinedload(B.es)) q = q.join(C, C.b_id == B.id) q = q.limit(5) eq_(q.all(), [(b, True)]) diff --git a/test/orm/inheritance/test_basic.py b/test/orm/inheritance/test_basic.py index 52b362b9ef..e870a80f0d 100644 --- a/test/orm/inheritance/test_basic.py +++ b/test/orm/inheritance/test_basic.py @@ -224,7 +224,7 @@ class PolyExpressionEagerLoad(fixtures.DeclarativeMappedTest): result = ( session.query(A) .filter_by(child_id=None) - .options(joinedload("child")) + .options(joinedload(A.child)) .one() ) diff --git a/test/orm/inheritance/test_polymorphic_rel.py b/test/orm/inheritance/test_polymorphic_rel.py index 1a96ee011e..b9d9ad932b 100644 --- a/test/orm/inheritance/test_polymorphic_rel.py +++ b/test/orm/inheritance/test_polymorphic_rel.py @@ -332,7 +332,7 @@ class _PolymorphicTestBase(fixtures.NoCache): sess = fixture_session() eq_( sess.query(Person) - .join("paperwork") + .join(Person.paperwork) .filter(Paperwork.description.like("%review%")) .all(), [b1, m1], @@ -357,7 +357,7 @@ class _PolymorphicTestBase(fixtures.NoCache): eq_( sess.query(Person) .order_by(Person.person_id) - .join("paperwork") + .join(Person.paperwork) .filter(Paperwork.description.like("%#2%")) .all(), [e1, m1], @@ -368,7 +368,7 @@ class _PolymorphicTestBase(fixtures.NoCache): eq_( sess.query(Engineer) .order_by(Person.person_id) - .join("paperwork") + .join(Person.paperwork) .filter(Paperwork.description.like("%#2%")) .all(), [e1], @@ -379,7 +379,7 @@ class _PolymorphicTestBase(fixtures.NoCache): eq_( sess.query(Person) .order_by(Person.person_id) - .join("paperwork") + .join(Person.paperwork) .filter(Person.name.like("%dog%")) .filter(Paperwork.description.like("%#2%")) .all(), @@ -391,7 +391,7 @@ class _PolymorphicTestBase(fixtures.NoCache): eq_( sess.query(Person) .order_by(Person.person_id) - .join("paperwork", aliased=True) + .join(Person.paperwork, aliased=True) .filter(Paperwork.description.like("%review%")) .all(), [b1, m1], @@ -420,7 +420,7 @@ class _PolymorphicTestBase(fixtures.NoCache): eq_( sess.query(Person) .order_by(Person.person_id) - .join(pa, "paperwork") + .join(pa, Person.paperwork) .filter(pa.description.like("%review%")) .all(), [b1, m1], @@ -431,7 +431,7 @@ class _PolymorphicTestBase(fixtures.NoCache): eq_( sess.query(Person) .order_by(Person.person_id) - .join("paperwork", aliased=True) + .join(Person.paperwork, aliased=True) .filter(Paperwork.description.like("%#2%")) .all(), [e1, m1], @@ -443,7 +443,7 @@ class _PolymorphicTestBase(fixtures.NoCache): eq_( sess.query(Person) .order_by(Person.person_id) - .join(pa, "paperwork") + .join(pa, Person.paperwork) .filter(pa.description.like("%#2%")) .all(), [e1, m1], @@ -454,7 +454,7 @@ class _PolymorphicTestBase(fixtures.NoCache): eq_( sess.query(Engineer) .order_by(Person.person_id) - .join("paperwork", aliased=True) + .join(Person.paperwork, aliased=True) .filter(Paperwork.description.like("%#2%")) .all(), [e1], @@ -466,7 +466,7 @@ class _PolymorphicTestBase(fixtures.NoCache): eq_( sess.query(Engineer) .order_by(Person.person_id) - .join(pa, "paperwork") + .join(pa, Person.paperwork) .filter(pa.description.like("%#2%")) .all(), [e1], @@ -478,7 +478,7 @@ class _PolymorphicTestBase(fixtures.NoCache): eq_( sess.query(Person) .order_by(Person.person_id) - .join(pa, "paperwork") + .join(pa, Person.paperwork) .filter(Person.name.like("%dog%")) .filter(pa.description.like("%#2%")) .all(), @@ -491,7 +491,7 @@ class _PolymorphicTestBase(fixtures.NoCache): sess.query(Person) .with_polymorphic(Manager) .order_by(Person.person_id) - .join("paperwork") + .join(Person.paperwork) .filter(Paperwork.description.like("%review%")) .all(), [b1, m1], @@ -520,7 +520,7 @@ class _PolymorphicTestBase(fixtures.NoCache): sess.query(Person) .with_polymorphic([Manager, Engineer]) .order_by(Person.person_id) - .join("paperwork") + .join(Person.paperwork) .filter(Paperwork.description.like("%#2%")) .all(), [e1, m1], @@ -532,7 +532,7 @@ class _PolymorphicTestBase(fixtures.NoCache): sess.query(Person) .with_polymorphic([Manager, Engineer]) .order_by(Person.person_id) - .join("paperwork") + .join(Person.paperwork) .filter(Person.name.like("%dog%")) .filter(Paperwork.description.like("%#2%")) .all(), @@ -544,7 +544,7 @@ class _PolymorphicTestBase(fixtures.NoCache): eq_( sess.query(Person) .with_polymorphic(Manager) - .join("paperwork", aliased=True) + .join(Person.paperwork, aliased=True) .filter(Paperwork.description.like("%review%")) .all(), [b1, m1], @@ -556,7 +556,7 @@ class _PolymorphicTestBase(fixtures.NoCache): eq_( sess.query(Person) .with_polymorphic(Manager) - .join(pa, "paperwork") + .join(pa, Person.paperwork) .filter(pa.description.like("%review%")) .all(), [b1, m1], @@ -568,7 +568,7 @@ class _PolymorphicTestBase(fixtures.NoCache): sess.query(Person) .with_polymorphic([Manager, Engineer]) .order_by(Person.person_id) - .join("paperwork", aliased=True) + .join(Person.paperwork, aliased=True) .filter(Paperwork.description.like("%#2%")) .all(), [e1, m1], @@ -581,7 +581,7 @@ class _PolymorphicTestBase(fixtures.NoCache): sess.query(Person) .with_polymorphic([Manager, Engineer]) .order_by(Person.person_id) - .join(pa, "paperwork") + .join(pa, Person.paperwork) .filter(pa.description.like("%#2%")) .all(), [e1, m1], @@ -595,7 +595,7 @@ class _PolymorphicTestBase(fixtures.NoCache): sess.query(Person) .with_polymorphic([Manager, Engineer]) .order_by(Person.person_id) - .join(pa, "paperwork") + .join(pa, Person.paperwork) .filter(Person.name.like("%dog%")) .filter(pa.description.like("%#2%")) .all(), @@ -606,7 +606,7 @@ class _PolymorphicTestBase(fixtures.NoCache): sess = fixture_session() eq_( sess.query(Company) - .join("employees") + .join(Company.employees) .filter(Person.name == "vlad") .one(), c2, @@ -616,7 +616,7 @@ class _PolymorphicTestBase(fixtures.NoCache): sess = fixture_session() eq_( sess.query(Company) - .join("employees", aliased=True) + .join(Company.employees, aliased=True) .filter(Person.name == "vlad") .one(), c2, @@ -627,7 +627,7 @@ class _PolymorphicTestBase(fixtures.NoCache): ea = aliased(Person) eq_( sess.query(Company) - .join(ea, "employees") + .join(ea, Company.employees) .filter(ea.name == "vlad") .one(), c2, @@ -646,7 +646,7 @@ class _PolymorphicTestBase(fixtures.NoCache): any_ = Company.employees.any(Person.name == "wally") eq_( sess.query(Company) - .join("employees", aliased=True) + .join(Company.employees, aliased=True) .filter(Person.name == "dilbert") .filter(any_) .all(), @@ -1172,7 +1172,7 @@ class _PolymorphicTestBase(fixtures.NoCache): ealias = aliased(Engineer) eq_( sess.query(Company) - .join(ealias, "employees") + .join(ealias, Company.employees) .filter(ealias.primary_language == "java") .all(), [c1], @@ -1231,7 +1231,7 @@ class _PolymorphicTestBase(fixtures.NoCache): sess = fixture_session() eq_( sess.query(Company) - .join("employees") + .join(Company.employees) .filter(Engineer.primary_language == "java") .all(), [c1], @@ -1264,7 +1264,10 @@ class _PolymorphicTestBase(fixtures.NoCache): def test_join_to_subclass_fourteen(self): sess = fixture_session() eq_( - sess.query(Company).join("employees", Engineer.machines).all(), + sess.query(Company) + .join(Company.employees) + .join(Engineer.machines) + .all(), [c1, c2], ) @@ -1272,7 +1275,8 @@ class _PolymorphicTestBase(fixtures.NoCache): sess = fixture_session() eq_( sess.query(Company) - .join("employees", Engineer.machines) + .join(Company.employees) + .join(Engineer.machines) .filter(Machine.name.ilike("%thinkpad%")) .all(), [c1], @@ -1365,7 +1369,7 @@ class _PolymorphicTestBase(fixtures.NoCache): sess = fixture_session() eq_( sess.query(Company) - .join("employees") + .join(Company.employees) .filter(Person.name.in_(["dilbert", "vlad"])) .join(Person.paperwork) .filter(Paperwork.description.like("%#2%")) @@ -1377,7 +1381,7 @@ class _PolymorphicTestBase(fixtures.NoCache): sess = fixture_session() eq_( sess.query(Company) - .join("employees") + .join(Company.employees) .filter(Person.name.in_(["dilbert", "vlad"])) .join(Person.paperwork) .filter(Paperwork.description.like("%#%")) @@ -1445,7 +1449,7 @@ class _PolymorphicTestBase(fixtures.NoCache): pa = aliased(Paperwork) eq_( sess.query(Company) - .join(ea, "employees") + .join(ea, Company.employees) .filter(ea.name.in_(["dilbert", "vlad"])) .join(pa, ea.paperwork) .filter(pa.description.like("%#2%")) diff --git a/test/orm/inheritance/test_relationship.py b/test/orm/inheritance/test_relationship.py index e795f0c7ff..881353e3bb 100644 --- a/test/orm/inheritance/test_relationship.py +++ b/test/orm/inheritance/test_relationship.py @@ -164,7 +164,7 @@ class SelfReferentialTestJoinedToBase(fixtures.MappedTest): pa = aliased(Person) eq_( sess.query(Engineer) - .join(pa, "reports_to") + .join(pa, Engineer.reports_to) .filter(pa.name == "dogbert") .first(), Engineer(name="dilbert"), @@ -276,7 +276,7 @@ class SelfReferentialJ2JTest(fixtures.MappedTest): eq_( sess.query(Engineer) - .join(ma, "reports_to") + .join(ma, Engineer.reports_to) .filter(ma.name == "dogbert") .first(), Engineer(name="dilbert"), @@ -507,7 +507,7 @@ class SelfReferentialJ2JSelfTest(fixtures.MappedTest): ea = aliased(Engineer) eq_( sess.query(Engineer) - .join(ea, "reports_to") + .join(ea, Engineer.reports_to) .filter(ea.name == "wally") .first(), Engineer(name="dilbert"), @@ -937,7 +937,7 @@ class SelfReferentialM2MTest(fixtures.MappedTest, AssertsCompiledSQL): # test that the splicing of the join works here, doesn't break in # the middle of "parent join child1" - q = sess.query(Child1).options(joinedload("left_child2")) + q = sess.query(Child1).options(joinedload(Child1.left_child2)) self.assert_compile( q.limit(1).statement, "SELECT child1.id, parent.id AS id_1, parent.cls, " @@ -969,7 +969,7 @@ class SelfReferentialM2MTest(fixtures.MappedTest, AssertsCompiledSQL): sess.flush() sess.expunge_all() - query_ = sess.query(Child1).options(subqueryload("left_child2")) + query_ = sess.query(Child1).options(subqueryload(Child1.left_child2)) for row in query_.all(): assert row.left_child2 @@ -1283,7 +1283,9 @@ class SubClassEagerToSubClassTest(fixtures.MappedTest): def go(): eq_( - sess.query(Subparent).options(joinedload("children")).all(), + sess.query(Subparent) + .options(joinedload(Subparent.children)) + .all(), [p1, p2], ) @@ -1311,7 +1313,7 @@ class SubClassEagerToSubClassTest(fixtures.MappedTest): eq_( sess.query(Subparent) .join(Subparent.children) - .options(contains_eager("children")) + .options(contains_eager(Subparent.children)) .all(), [p1, p2], ) @@ -1337,7 +1339,9 @@ class SubClassEagerToSubClassTest(fixtures.MappedTest): def go(): eq_( - sess.query(Subparent).options(subqueryload("children")).all(), + sess.query(Subparent) + .options(subqueryload(Subparent.children)) + .all(), [p1, p2], ) @@ -1770,7 +1774,8 @@ class SubClassToSubClassMultiTest(AssertsCompiledSQL, fixtures.MappedTest): s = fixture_session() self.assert_compile( s.query(Parent) - .join(Parent.sub1, Sub1.sub2) + .join(Parent.sub1) + .join(Sub1.sub2) .join(Sub2.ep1) .join(Sub2.ep2), "SELECT parent.id AS parent_id, parent.data AS parent_data " diff --git a/test/orm/inheritance/test_single.py b/test/orm/inheritance/test_single.py index a3230f91d8..690bdfc577 100644 --- a/test/orm/inheritance/test_single.py +++ b/test/orm/inheritance/test_single.py @@ -764,7 +764,7 @@ class RelationshipFromSingleTest( sess = fixture_session() with self.sql_execution_asserter(testing.db) as asserter: - sess.query(Manager).options(subqueryload("stuff")).all() + sess.query(Manager).options(subqueryload(Manager.stuff)).all() asserter.assert_( CompiledSQL( @@ -992,7 +992,7 @@ class RelationshipToSingleTest( sess = fixture_session() self.assert_compile( - sess.query(Company, Engineer.name).outerjoin("engineers"), + sess.query(Company, Engineer.name).outerjoin(Company.engineers), "SELECT companies.company_id AS companies_company_id, " "companies.name AS companies_name, " "employees.name AS employees_name " @@ -1378,7 +1378,7 @@ class RelationshipToSingleTest( sess.expunge_all() eq_( sess.query(Company) - .options(joinedload("engineers")) + .options(joinedload(Company.engineers)) .order_by(Company.name) .all(), [ diff --git a/test/orm/test_ac_relationships.py b/test/orm/test_ac_relationships.py index 26dd674800..6a050b698c 100644 --- a/test/orm/test_ac_relationships.py +++ b/test/orm/test_ac_relationships.py @@ -49,7 +49,7 @@ class PartitionByFixture(fixtures.DeclarativeMappedTest): .label("index"), ).alias() - partitioned_b = cls.partitioned_b = aliased(B, alias=partition) + cls.partitioned_b = partitioned_b = aliased(B, alias=partition) A.partitioned_bs = relationship( partitioned_b, @@ -141,7 +141,7 @@ class AliasedClassRelationshipTest( self.assert_sql_count(testing.db, go, 2) - @testing.combinations("string", "ac_attribute", "ac_attr_w_of_type") + @testing.combinations("ac_attribute", "ac_attr_w_of_type") def test_selectinload_w_joinedload_after(self, calling_style): """test has been enhanced to also test #7224""" @@ -151,9 +151,7 @@ class AliasedClassRelationshipTest( partitioned_b = self.partitioned_b - if calling_style == "string": - opt = selectinload(A.partitioned_bs).joinedload("cs") - elif calling_style == "ac_attribute": + if calling_style == "ac_attribute": opt = selectinload(A.partitioned_bs).joinedload(partitioned_b.cs) elif calling_style == "ac_attr_w_of_type": # this would have been a workaround for people who encountered diff --git a/test/orm/test_assorted_eager.py b/test/orm/test_assorted_eager.py index 6f983e0ed1..a97538da64 100644 --- a/test/orm/test_assorted_eager.py +++ b/test/orm/test_assorted_eager.py @@ -259,7 +259,7 @@ class EagerTest(fixtures.MappedTest): ) s = fixture_session() - q = s.query(Thing).options(sa.orm.joinedload("category")) + q = s.query(Thing).options(sa.orm.joinedload(Thing.category)) result = q.select_from( tests.outerjoin( @@ -292,7 +292,7 @@ class EagerTest(fixtures.MappedTest): ) s = fixture_session() - q = s.query(Thing).options(sa.orm.joinedload("category")) + q = s.query(Thing).options(sa.orm.joinedload(Thing.category)) result = q.filter( sa.and_( tests.c.owner_id == 1, @@ -301,7 +301,7 @@ class EagerTest(fixtures.MappedTest): options.c.someoption == False, # noqa ), ) - ).outerjoin("owner_option") + ).outerjoin(Thing.owner_option) result_str = ["%d %s" % (t.id, t.category.name) for t in result] eq_(result_str, ["1 Some Category", "3 Some Category"]) @@ -311,13 +311,13 @@ class EagerTest(fixtures.MappedTest): Thing, tests = (self.classes.Thing, self.tables.tests) s = fixture_session() - q = s.query(Thing).options(sa.orm.joinedload("category")) + q = s.query(Thing).options(sa.orm.joinedload(Thing.category)) result = q.filter( (tests.c.owner_id == 1) & text( "options.someoption is null or options.someoption=:opt" ).bindparams(opt=False) - ).join("owner_option") + ).join(Thing.owner_option) result_str = ["%d %s" % (t.id, t.category.name) for t in result] eq_(result_str, ["3 Some Category"]) @@ -330,14 +330,14 @@ class EagerTest(fixtures.MappedTest): ) s = fixture_session() - q = s.query(Thing).options(sa.orm.joinedload("category")) + q = s.query(Thing).options(sa.orm.joinedload(Thing.category)) result = q.filter( (tests.c.owner_id == 1) & ( (options.c.someoption == None) | (options.c.someoption == False) ) # noqa - ).join("owner_option") + ).join(Thing.owner_option) result_str = ["%d %s" % (t.id, t.category.name) for t in result] eq_(result_str, ["3 Some Category"]) @@ -552,7 +552,7 @@ class EagerTest3(fixtures.MappedTest): # "order by max desc" separately q = ( session.query(Data) - .options(sa.orm.joinedload("foo")) + .options(sa.orm.joinedload(Data.foo)) .select_from( datas.join(arb_data, arb_data.c.data_id == datas.c.id) ) @@ -639,7 +639,7 @@ class EagerTest4(fixtures.MappedTest): q = ( sess.query(Department) - .join("employees") + .join(Department.employees) .filter(Employee.name.startswith("J")) .distinct() .order_by(sa.desc(Department.name)) @@ -1317,10 +1317,10 @@ class EagerTest9(fixtures.MappedTest): acc = ( session.query(Account) .options( - sa.orm.joinedload("entries") - .joinedload("transaction") - .joinedload("entries") - .joinedload("account") + sa.orm.joinedload(Account.entries) + .joinedload(Entry.transaction) + .joinedload(Transaction.entries) + .joinedload(Entry.account) ) .order_by(Account.account_id) ).first() diff --git a/test/orm/test_cache_key.py b/test/orm/test_cache_key.py index f25a57fe5a..d689bd6bad 100644 --- a/test/orm/test_cache_key.py +++ b/test/orm/test_cache_key.py @@ -249,6 +249,8 @@ class CacheKeyTest(CacheKeyFixture, _fixtures.FixtureTest): "User", "Address", "Keyword", "Order", "Item" ) + a1 = aliased(Address) + self._run_cache_key_fixture( lambda: ( Load(User).joinedload(User.addresses), @@ -261,10 +263,10 @@ class CacheKeyTest(CacheKeyFixture, _fixtures.FixtureTest): User.orders.and_(Order.description != "somename") ), Load(User).defer(User.id), - Load(User).subqueryload("addresses"), - Load(Address).defer("id"), + Load(User).subqueryload(User.addresses), + Load(Address).defer(Address.id), Load(Address).defer("*"), - Load(aliased(Address)).defer("id"), + Load(a1).defer(a1.id), Load(User).joinedload(User.addresses).defer(Address.id), Load(User).joinedload(User.orders).joinedload(Order.items), Load(User).joinedload(User.orders).subqueryload(Order.items), @@ -276,33 +278,11 @@ class CacheKeyTest(CacheKeyFixture, _fixtures.FixtureTest): Load(User).defaultload(User.orders).defaultload(Order.items), Load(User).defaultload(User.orders), Load(Address).raiseload("*"), - Load(Address).raiseload("user"), + Load(Address).raiseload(Address.user), ), compare_values=True, ) - def test_bound_options_equiv_on_strname(self): - """Bound loader options resolve on string name so test that the cache - key for the string version matches the resolved version. - - """ - User, Address, Keyword, Order, Item = self.classes( - "User", "Address", "Keyword", "Order", "Item" - ) - - for left, right in [ - (Load(User).defer(User.id), Load(User).defer("id")), - ( - Load(User).joinedload(User.addresses), - Load(User).joinedload("addresses"), - ), - ( - Load(User).joinedload(User.orders).joinedload(Order.items), - Load(User).joinedload("orders").joinedload("items"), - ), - ]: - eq_(left._generate_cache_key(), right._generate_cache_key()) - def test_selects_w_orm_joins(self): User, Address, Keyword, Order, Item = self.classes( @@ -353,16 +333,10 @@ class CacheKeyTest(CacheKeyFixture, _fixtures.FixtureTest): .join(User.orders), fixture_session() .query(User) - .join("addresses") - .join("dingalings", from_joinpoint=True), - fixture_session().query(User).join("addresses"), - fixture_session().query(User).join("orders"), - fixture_session().query(User).join("addresses").join("orders"), + .join(User.addresses) + .join(Address.dingaling), fixture_session().query(User).join(Address, User.addresses), - fixture_session().query(User).join(a1, "addresses"), - fixture_session() - .query(User) - .join(a1, "addresses", aliased=True), + fixture_session().query(User).join(a1, User.addresses), fixture_session().query(User).join(User.addresses.of_type(a1)), ), compare_values=True, diff --git a/test/orm/test_composites.py b/test/orm/test_composites.py index 4bdca7a45a..1dc139df98 100644 --- a/test/orm/test_composites.py +++ b/test/orm/test_composites.py @@ -179,7 +179,9 @@ class PointTest(fixtures.MappedTest, testing.AssertsCompiledSQL): def go(): g2 = ( - sess.query(Graph).options(sa.orm.joinedload("edges")).get(g.id) + sess.query(Graph) + .options(sa.orm.joinedload(Graph.edges)) + .get(g.id) ) eq_( diff --git a/test/orm/test_default_strategies.py b/test/orm/test_default_strategies.py index 249a446ea7..9b228bbaa2 100644 --- a/test/orm/test_default_strategies.py +++ b/test/orm/test_default_strategies.py @@ -1,7 +1,10 @@ import sqlalchemy as sa from sqlalchemy import testing from sqlalchemy import util +from sqlalchemy.orm import defaultload +from sqlalchemy.orm import joinedload from sqlalchemy.orm import relationship +from sqlalchemy.orm import subqueryload from sqlalchemy.testing import assert_raises_message from sqlalchemy.testing import eq_ from sqlalchemy.testing.fixtures import fixture_session @@ -239,8 +242,8 @@ class DefaultStrategyOptionsTest(_fixtures.FixtureTest): def go(): users[:] = ( sess.query(self.classes.User) - .options(sa.orm.subqueryload("*")) - .options(sa.orm.joinedload(self.classes.User.addresses)) + .options(subqueryload("*")) + .options(joinedload(self.classes.User.addresses)) .options(sa.orm.lazyload("*")) .order_by(self.classes.User.id) .all() @@ -254,7 +257,7 @@ class DefaultStrategyOptionsTest(_fixtures.FixtureTest): def test_star_must_be_alone(self): sess = self._downgrade_fixture() User = self.classes.User - opt = sa.orm.subqueryload("*", User.addresses) + opt = subqueryload("*", User.addresses) assert_raises_message( sa.exc.ArgumentError, "Wildcard token cannot be followed by another entity", @@ -287,7 +290,7 @@ class DefaultStrategyOptionsTest(_fixtures.FixtureTest): users[:] = ( sess.query(self.classes.User) .options(sa.orm.lazyload("*")) - .options(sa.orm.joinedload(self.classes.User.addresses)) + .options(joinedload(self.classes.User.addresses)) .order_by(self.classes.User.id) .all() ) @@ -317,7 +320,7 @@ class DefaultStrategyOptionsTest(_fixtures.FixtureTest): users[:] = ( sess.query(self.classes.User) .options(sa.orm.lazyload("*")) - .options(sa.orm.subqueryload(self.classes.User.orders)) + .options(subqueryload(self.classes.User.orders)) .order_by(self.classes.User.id) .all() ) @@ -355,7 +358,7 @@ class DefaultStrategyOptionsTest(_fixtures.FixtureTest): users[:] = ( sess.query(self.classes.User) .options(sa.orm.noload("*")) - .options(sa.orm.joinedload(self.classes.User.addresses)) + .options(joinedload(self.classes.User.addresses)) .order_by(self.classes.User.id) .all() ) @@ -385,7 +388,7 @@ class DefaultStrategyOptionsTest(_fixtures.FixtureTest): users[:] = ( sess.query(self.classes.User) .options(sa.orm.noload("*")) - .options(sa.orm.subqueryload(self.classes.User.orders)) + .options(subqueryload(self.classes.User.orders)) .order_by(self.classes.User.id) .all() ) @@ -414,7 +417,7 @@ class DefaultStrategyOptionsTest(_fixtures.FixtureTest): def go(): users[:] = ( sess.query(self.classes.User) - .options(sa.orm.joinedload("*")) + .options(joinedload("*")) .order_by(self.classes.User.id) .all() ) @@ -428,14 +431,20 @@ class DefaultStrategyOptionsTest(_fixtures.FixtureTest): sess = self._upgrade_fixture() users = [] + User, Order, Item = self.classes("User", "Order", "Item") + # test upgrade all to joined: 1 sql def go(): users[:] = ( - sess.query(self.classes.User) - .options(sa.orm.joinedload(".*")) - .options(sa.orm.joinedload("addresses.*")) - .options(sa.orm.joinedload("orders.*")) - .options(sa.orm.joinedload("orders.items.*")) + sess.query(User) + .options(joinedload(".*")) + .options(defaultload(User.addresses).joinedload("*")) + .options(defaultload(User.orders).joinedload("*")) + .options( + defaultload(User.orders) + .defaultload(Order.items) + .joinedload("*") + ) .order_by(self.classes.User.id) .all() ) @@ -450,13 +459,19 @@ class DefaultStrategyOptionsTest(_fixtures.FixtureTest): sess = self._upgrade_fixture() users = [] + User, Order, Item = self.classes("User", "Order", "Item") + # test joined all but 'keywords': upgraded to 1 sql def go(): users[:] = ( - sess.query(self.classes.User) - .options(sa.orm.lazyload("orders.items.keywords")) - .options(sa.orm.joinedload("*")) - .order_by(self.classes.User.id) + sess.query(User) + .options( + defaultload(User.orders) + .defaultload(Order.items) + .lazyload(Item.keywords) + ) + .options(joinedload("*")) + .order_by(User.id) .all() ) @@ -492,8 +507,8 @@ class DefaultStrategyOptionsTest(_fixtures.FixtureTest): def go(): users[:] = ( sess.query(self.classes.User) - .options(sa.orm.subqueryload(self.classes.User.addresses)) - .options(sa.orm.joinedload("*")) + .options(subqueryload(self.classes.User.addresses)) + .options(joinedload("*")) .order_by(self.classes.User.id) .all() ) @@ -513,7 +528,7 @@ class DefaultStrategyOptionsTest(_fixtures.FixtureTest): def go(): users[:] = ( sess.query(self.classes.User) - .options(sa.orm.subqueryload("*")) + .options(subqueryload("*")) .order_by(self.classes.User.id) .all() ) @@ -527,15 +542,21 @@ class DefaultStrategyOptionsTest(_fixtures.FixtureTest): sess = self._upgrade_fixture() users = [] + User, Order = self.classes("User", "Order") + # test upgrade all to subquery: 1 sql + 4 relationships = 5 def go(): users[:] = ( - sess.query(self.classes.User) - .options(sa.orm.subqueryload(".*")) - .options(sa.orm.subqueryload("addresses.*")) - .options(sa.orm.subqueryload("orders.*")) - .options(sa.orm.subqueryload("orders.items.*")) - .order_by(self.classes.User.id) + sess.query(User) + .options(subqueryload(".*")) + .options(defaultload(User.addresses).subqueryload("*")) + .options(defaultload(User.orders).subqueryload("*")) + .options( + defaultload(User.orders) + .defaultload(Order.items) + .subqueryload("*") + ) + .order_by(User.id) .all() ) @@ -550,14 +571,19 @@ class DefaultStrategyOptionsTest(_fixtures.FixtureTest): is still honored""" sess = self._upgrade_fixture() users = [] + User, Order, Item = self.classes("User", "Order", "Item") # test subquery all but 'keywords' (1 sql + 3 relationships = 4) def go(): users[:] = ( - sess.query(self.classes.User) - .options(sa.orm.lazyload("orders.items.keywords")) - .options(sa.orm.subqueryload("*")) - .order_by(self.classes.User.id) + sess.query(User) + .options( + defaultload(User.orders) + .defaultload(Order.items) + .lazyload(Item.keywords) + ) + .options(subqueryload("*")) + .order_by(User.id) .all() ) @@ -593,9 +619,9 @@ class DefaultStrategyOptionsTest(_fixtures.FixtureTest): def go(): users[:] = ( sess.query(self.classes.User) - .options(sa.orm.joinedload(self.classes.User.addresses)) - .options(sa.orm.joinedload(self.classes.User.orders)) - .options(sa.orm.subqueryload("*")) + .options(joinedload(self.classes.User.addresses)) + .options(joinedload(self.classes.User.orders)) + .options(subqueryload("*")) .order_by(self.classes.User.id) .all() ) @@ -661,7 +687,7 @@ class NoLoadTest(_fixtures.FixtureTest): ) ), ) - q = fixture_session().query(m).options(sa.orm.lazyload("addresses")) + q = fixture_session().query(m).options(sa.orm.lazyload(User.addresses)) result = [None] def go(): @@ -690,7 +716,7 @@ class NoLoadTest(_fixtures.FixtureTest): a1 = ( s.query(Address) .filter_by(id=1) - .options(sa.orm.noload("user")) + .options(sa.orm.noload(Address.user)) .first() ) diff --git a/test/orm/test_deferred.py b/test/orm/test_deferred.py index 9f9068783f..e44d6ec869 100644 --- a/test/orm/test_deferred.py +++ b/test/orm/test_deferred.py @@ -370,7 +370,7 @@ class DeferredOptionsTest(AssertsCompiledSQL, _fixtures.FixtureTest): self.mapper_registry.map_imperatively(Order, orders) sess = fixture_session() - q = sess.query(Order).order_by(Order.id).options(defer("user_id")) + q = sess.query(Order).order_by(Order.id).options(defer(Order.user_id)) def go(): q.all()[0].user_id @@ -395,7 +395,7 @@ class DeferredOptionsTest(AssertsCompiledSQL, _fixtures.FixtureTest): ) sess.expunge_all() - q2 = q.options(undefer("user_id")) + q2 = q.options(undefer(Order.user_id)) self.sql_eq_( q2.all, [ @@ -985,7 +985,11 @@ class DeferredOptionsTest(AssertsCompiledSQL, _fixtures.FixtureTest): eq_(item.description, "item 4") sess.expunge_all() - result = q.options(undefer("orders.items.description")).all() + result = q.options( + defaultload(User.orders) + .defaultload(Order.items) + .undefer(Item.description) + ).all() item = result[0].orders[1].items[1] def go(): @@ -1055,7 +1059,9 @@ class DeferredOptionsTest(AssertsCompiledSQL, _fixtures.FixtureTest): sess = fixture_session() q = sess.query(User).options( - joinedload(User.orders).defer("description").defer("isopen") + joinedload(User.orders) + .defer(Order.description) + .defer(Order.isopen) ) self.assert_compile( q, @@ -1075,7 +1081,9 @@ class DeferredOptionsTest(AssertsCompiledSQL, _fixtures.FixtureTest): self.mapper_registry.map_imperatively(Order, orders) sess = fixture_session() - q = sess.query(Order).options(load_only("isopen", "description")) + q = sess.query(Order).options( + load_only(Order.isopen, Order.description) + ) self.assert_compile( q, "SELECT orders.id AS orders_id, " @@ -1092,7 +1100,7 @@ class DeferredOptionsTest(AssertsCompiledSQL, _fixtures.FixtureTest): q = ( sess.query(Order) .order_by(Order.id) - .options(load_only("isopen", "description")) + .options(load_only(Order.isopen, Order.description)) ) eq_(q.first(), Order(id=1)) @@ -1107,7 +1115,7 @@ class DeferredOptionsTest(AssertsCompiledSQL, _fixtures.FixtureTest): sess = fixture_session() q = sess.query(Order).options( - load_only("isopen", "description"), undefer("user_id") + load_only(Order.isopen, Order.description), undefer(Order.user_id) ) self.assert_compile( q, @@ -1117,8 +1125,7 @@ class DeferredOptionsTest(AssertsCompiledSQL, _fixtures.FixtureTest): "orders.isopen AS orders_isopen FROM orders", ) - @testing.combinations(("string",), ("attr",)) - def test_load_only_synonym(self, type_): + def test_load_only_synonym(self): orders, Order = self.tables.orders, self.classes.Order self.mapper_registry.map_imperatively( @@ -1127,10 +1134,7 @@ class DeferredOptionsTest(AssertsCompiledSQL, _fixtures.FixtureTest): properties={"desc": synonym("description")}, ) - if type_ == "attr": - opt = load_only(Order.isopen, Order.desc) - else: - opt = load_only("isopen", "desc") + opt = load_only(Order.isopen, Order.desc) sess = fixture_session() q = sess.query(Order).options(opt) @@ -1184,10 +1188,12 @@ class DeferredOptionsTest(AssertsCompiledSQL, _fixtures.FixtureTest): opt = ( Load(User) .defaultload(User.addresses) - .load_only("id", "email_address") + .load_only(Address.id, Address.email_address) ) else: - opt = defaultload(User.addresses).load_only("id", "email_address") + opt = defaultload(User.addresses).load_only( + Address.id, Address.email_address + ) q = sess.query(User).options(opt).filter(User.id.in_([7, 8])) def go(): @@ -1211,9 +1217,9 @@ class DeferredOptionsTest(AssertsCompiledSQL, _fixtures.FixtureTest): sess = fixture_session() q = sess.query(User, Order, Address).options( - Load(User).load_only("name"), - Load(Order).load_only("id"), - Load(Address).load_only("id", "email_address"), + Load(User).load_only(User.name), + Load(Order).load_only(Order.id), + Load(Address).load_only(Address.id, Address.email_address), ) self.assert_compile( @@ -1252,10 +1258,10 @@ class DeferredOptionsTest(AssertsCompiledSQL, _fixtures.FixtureTest): sess = fixture_session() q = sess.query(User).options( - load_only("name") - .defaultload("addresses") - .load_only("id", "email_address"), - defaultload("orders").load_only("id"), + load_only(User.name) + .defaultload(User.addresses) + .load_only(Address.id, Address.email_address), + defaultload(User.orders).load_only(Order.id), ) # hmmmm joinedload seems to be forcing users.id into here... @@ -1339,7 +1345,7 @@ class InheritanceTest(_Polymorphic): q = ( s.query(Manager) .order_by(Manager.person_id) - .options(load_only("status", "manager_name")) + .options(load_only(Manager.status, Manager.manager_name)) ) self.assert_compile( q, @@ -1358,7 +1364,9 @@ class InheritanceTest(_Polymorphic): q = ( s.query(Manager) .order_by(Manager.person_id) - .options(Load(Manager).load_only("status", "manager_name")) + .options( + Load(Manager).load_only(Manager.status, Manager.manager_name) + ) ) self.assert_compile( q, @@ -1377,7 +1385,7 @@ class InheritanceTest(_Polymorphic): q = ( s.query(Boss) .order_by(Person.person_id) - .options(load_only("status", "manager_name")) + .options(load_only(Boss.status, Boss.manager_name)) ) self.assert_compile( q, @@ -1396,7 +1404,7 @@ class InheritanceTest(_Polymorphic): q = ( s.query(Boss) .order_by(Person.person_id) - .options(Load(Boss).load_only("status", "manager_name")) + .options(Load(Boss).load_only(Boss.status, Manager.manager_name)) ) self.assert_compile( q, @@ -1416,7 +1424,7 @@ class InheritanceTest(_Polymorphic): q = ( s.query(m1) .order_by(m1.person_id) - .options(load_only("status", "manager_name")) + .options(load_only(m1.status, m1.manager_name)) ) self.assert_compile( q, @@ -1436,7 +1444,7 @@ class InheritanceTest(_Polymorphic): q = ( s.query(m1) .order_by(m1.person_id) - .options(Load(m1).load_only("status", "manager_name")) + .options(Load(m1).load_only(m1.status, m1.manager_name)) ) self.assert_compile( q, @@ -1511,7 +1519,7 @@ class InheritanceTest(_Polymorphic): .join(Company.managers) .options( contains_eager(Company.managers).load_only( - "status", "manager_name" + Manager.status, Manager.manager_name ) ) ) @@ -1536,7 +1544,7 @@ class InheritanceTest(_Polymorphic): .options( Load(Company) .contains_eager(Company.managers) - .load_only("status", "manager_name") + .load_only(Manager.status, Manager.manager_name) ) ) self.assert_compile( @@ -1562,7 +1570,7 @@ class InheritanceTest(_Polymorphic): q = ( s.query(Manager) .order_by(Person.person_id) - .options(defer(".*"), undefer("status")) + .options(defer(".*"), undefer(Manager.status)) ) self.assert_compile( q, @@ -1577,7 +1585,9 @@ class InheritanceTest(_Polymorphic): def test_load_only_subclass_of_type(self): s = fixture_session() q = s.query(Company).options( - joinedload(Company.employees.of_type(Manager)).load_only("status") + joinedload(Company.employees.of_type(Manager)).load_only( + Manager.status + ) ) self.assert_compile( q, @@ -1624,7 +1634,11 @@ class InheritanceTest(_Polymorphic): def test_defer_super_name_on_subclass(self): s = fixture_session() - q = s.query(Manager).order_by(Person.person_id).options(defer("name")) + q = ( + s.query(Manager) + .order_by(Person.person_id) + .options(defer(Person.name)) + ) self.assert_compile( q, "SELECT managers.person_id AS managers_person_id, " @@ -1642,7 +1656,7 @@ class InheritanceTest(_Polymorphic): q = ( s.query(Manager) .order_by(Person.person_id) - .options(Load(Manager).defer("name")) + .options(Load(Manager).defer(Manager.name)) ) self.assert_compile( q, @@ -1686,19 +1700,6 @@ class InheritanceTest(_Polymorphic): wp = with_polymorphic(Person, [Manager], flat=True) - # needs to be explicit, we don't currently dig onto all the - # sub-entities in the wp - assert_raises_message( - sa.exc.ArgumentError, - r'Can\'t find property named "status" on ' - r"with_polymorphic\(Person, \[Manager\]\) in this Query.", - s.query(Company) - .options( - joinedload(Company.employees.of_type(wp)).load_only("status") - ) - ._compile_context, - ) - assert_raises_message( sa.exc.ArgumentError, 'Attribute "Manager.status" does not link from element ' @@ -2225,7 +2226,9 @@ class DeferredPopulationTest(fixtures.MappedTest): Thing = self.classes.Thing session = fixture_session() - thing = session.query(Thing).options(sa.orm.undefer("name")).first() + thing = ( + session.query(Thing).options(sa.orm.undefer(Thing.name)).first() + ) self._test(thing) def test_query_twice_with_clear(self): @@ -2234,7 +2237,9 @@ class DeferredPopulationTest(fixtures.MappedTest): session = fixture_session() result = session.query(Thing).first() # noqa session.expunge_all() - thing = session.query(Thing).options(sa.orm.undefer("name")).first() + thing = ( + session.query(Thing).options(sa.orm.undefer(Thing.name)).first() + ) self._test(thing) def test_query_twice_no_clear(self): @@ -2242,7 +2247,9 @@ class DeferredPopulationTest(fixtures.MappedTest): session = fixture_session() result = session.query(Thing).first() # noqa - thing = session.query(Thing).options(sa.orm.undefer("name")).first() + thing = ( + session.query(Thing).options(sa.orm.undefer(Thing.name)).first() + ) self._test(thing) def test_joinedload_with_clear(self): @@ -2250,10 +2257,14 @@ class DeferredPopulationTest(fixtures.MappedTest): session = fixture_session() human = ( # noqa - session.query(Human).options(sa.orm.joinedload("thing")).first() + session.query(Human) + .options(sa.orm.joinedload(Human.thing)) + .first() ) session.expunge_all() - thing = session.query(Thing).options(sa.orm.undefer("name")).first() + thing = ( + session.query(Thing).options(sa.orm.undefer(Thing.name)).first() + ) self._test(thing) def test_joinedload_no_clear(self): @@ -2261,9 +2272,13 @@ class DeferredPopulationTest(fixtures.MappedTest): session = fixture_session() human = ( # noqa - session.query(Human).options(sa.orm.joinedload("thing")).first() + session.query(Human) + .options(sa.orm.joinedload(Human.thing)) + .first() + ) + thing = ( + session.query(Thing).options(sa.orm.undefer(Thing.name)).first() ) - thing = session.query(Thing).options(sa.orm.undefer("name")).first() self._test(thing) def test_join_with_clear(self): @@ -2271,10 +2286,12 @@ class DeferredPopulationTest(fixtures.MappedTest): session = fixture_session() result = ( # noqa - session.query(Human).add_entity(Thing).join("thing").first() + session.query(Human).add_entity(Thing).join(Human.thing).first() ) session.expunge_all() - thing = session.query(Thing).options(sa.orm.undefer("name")).first() + thing = ( + session.query(Thing).options(sa.orm.undefer(Thing.name)).first() + ) self._test(thing) def test_join_no_clear(self): @@ -2282,7 +2299,9 @@ class DeferredPopulationTest(fixtures.MappedTest): session = fixture_session() result = ( # noqa - session.query(Human).add_entity(Thing).join("thing").first() + session.query(Human).add_entity(Thing).join(Human.thing).first() + ) + thing = ( + session.query(Thing).options(sa.orm.undefer(Thing.name)).first() ) - thing = session.query(Thing).options(sa.orm.undefer("name")).first() self._test(thing) diff --git a/test/orm/test_deprecations.py b/test/orm/test_deprecations.py index ddfad7e0f0..2ab45827b5 100644 --- a/test/orm/test_deprecations.py +++ b/test/orm/test_deprecations.py @@ -7,6 +7,7 @@ from sqlalchemy import event from sqlalchemy import exc as sa_exc from sqlalchemy import ForeignKey from sqlalchemy import func +from sqlalchemy import inspect from sqlalchemy import Integer from sqlalchemy import literal_column from sqlalchemy import MetaData @@ -31,18 +32,24 @@ from sqlalchemy.orm import contains_alias from sqlalchemy.orm import contains_eager from sqlalchemy.orm import declarative_base from sqlalchemy.orm import declared_attr +from sqlalchemy.orm import defaultload from sqlalchemy.orm import defer from sqlalchemy.orm import deferred from sqlalchemy.orm import eagerload +from sqlalchemy.orm import exc as orm_exc from sqlalchemy.orm import foreign from sqlalchemy.orm import instrumentation from sqlalchemy.orm import joinedload +from sqlalchemy.orm import Load +from sqlalchemy.orm import load_only from sqlalchemy.orm import mapper from sqlalchemy.orm import relation from sqlalchemy.orm import relationship from sqlalchemy.orm import scoped_session +from sqlalchemy.orm import selectinload from sqlalchemy.orm import Session from sqlalchemy.orm import sessionmaker +from sqlalchemy.orm import strategy_options from sqlalchemy.orm import subqueryload from sqlalchemy.orm import synonym from sqlalchemy.orm import undefer @@ -70,14 +77,22 @@ from sqlalchemy.testing.mock import call from sqlalchemy.testing.mock import Mock from sqlalchemy.testing.schema import Column from sqlalchemy.testing.schema import Table +from sqlalchemy.util import pickle from . import _fixtures from .inheritance import _poly_fixtures +from .inheritance._poly_fixtures import _Polymorphic +from .inheritance._poly_fixtures import Company +from .inheritance._poly_fixtures import Engineer +from .test_ac_relationships import PartitionByFixture from .test_bind import GetBindTest as _GetBindTest from .test_dynamic import _DynamicFixture from .test_events import _RemoveListeners from .test_options import PathTest as OptionsPathTest +from .test_options import PathTest +from .test_options import QueryTest as OptionsQueryTest from .test_query import QueryTest from .test_transaction import _LocalFixture +from ..sql.test_compare import CacheKeyFixture join_aliased_dep = ( @@ -94,12 +109,27 @@ join_chain_dep = ( r"Passing a chain of multiple join conditions to Query.join\(\)" ) +undefer_needs_chaining = ( + r"The \*addl_attrs on orm.(?:un)?defer is deprecated. " + "Please use method chaining" +) + join_strings_dep = "Using strings to indicate relationship names in Query.join" join_tuple_form = ( r"Query.join\(\) will no longer accept tuples as " "arguments in SQLAlchemy 2.0." ) +opt_strings_dep = ( + "Using strings to indicate column or relationship " + "paths in loader options" +) + +wparent_strings_dep = ( + r"Using strings to indicate relationship names " + r"in the ORM with_parent\(\) function" +) + def _aliased_join_warning(arg=None): return testing.expect_warnings( @@ -115,6 +145,337 @@ def _aliased_join_deprecation(arg=None): ) +class CustomJoinTest(QueryTest): + run_setup_mappers = None + + def test_double_same_mappers_flag_alias(self): + """test aliasing of joins with a custom join condition""" + + ( + addresses, + items, + order_items, + orders, + Item, + User, + Address, + Order, + users, + ) = ( + self.tables.addresses, + self.tables.items, + self.tables.order_items, + self.tables.orders, + self.classes.Item, + self.classes.User, + self.classes.Address, + self.classes.Order, + self.tables.users, + ) + + self.mapper_registry.map_imperatively(Address, addresses) + self.mapper_registry.map_imperatively( + Order, + orders, + properties={ + "items": relationship( + Item, + secondary=order_items, + lazy="select", + order_by=items.c.id, + ) + }, + ) + self.mapper_registry.map_imperatively(Item, items) + self.mapper_registry.map_imperatively( + User, + users, + properties=dict( + addresses=relationship(Address, lazy="select"), + open_orders=relationship( + Order, + primaryjoin=and_( + orders.c.isopen == 1, users.c.id == orders.c.user_id + ), + lazy="select", + viewonly=True, + ), + closed_orders=relationship( + Order, + primaryjoin=and_( + orders.c.isopen == 0, users.c.id == orders.c.user_id + ), + lazy="select", + viewonly=True, + ), + ), + ) + q = fixture_session().query(User) + + with assertions.expect_deprecated_20( + join_aliased_dep, + join_strings_dep, + join_chain_dep, + raise_on_any_unexpected=True, + ): + eq_( + q.join("open_orders", "items", aliased=True) + .filter(Item.id == 4) + .join("closed_orders", "items", aliased=True) + .filter(Item.id == 3) + .all(), + [User(id=7)], + ) + + +class PickleTest(fixtures.MappedTest): + @classmethod + def define_tables(cls, metadata): + Table( + "users", + metadata, + Column( + "id", Integer, primary_key=True, test_needs_autoincrement=True + ), + Column("name", String(30), nullable=False), + test_needs_acid=True, + test_needs_fk=True, + ) + + Table( + "addresses", + metadata, + Column( + "id", Integer, primary_key=True, test_needs_autoincrement=True + ), + Column("user_id", None, ForeignKey("users.id")), + Column("email_address", String(50), nullable=False), + test_needs_acid=True, + test_needs_fk=True, + ) + Table( + "orders", + metadata, + Column( + "id", Integer, primary_key=True, test_needs_autoincrement=True + ), + Column("user_id", None, ForeignKey("users.id")), + Column("address_id", None, ForeignKey("addresses.id")), + Column("description", String(30)), + Column("isopen", Integer), + test_needs_acid=True, + test_needs_fk=True, + ) + Table( + "dingalings", + metadata, + Column( + "id", Integer, primary_key=True, test_needs_autoincrement=True + ), + Column("address_id", None, ForeignKey("addresses.id")), + Column("data", String(30)), + test_needs_acid=True, + test_needs_fk=True, + ) + + def _option_test_fixture(self): + users, addresses, dingalings = ( + self.tables.users, + self.tables.addresses, + self.tables.dingalings, + ) + + # these must be module level for pickling + from .test_pickled import User, Address, Dingaling + + self.mapper_registry.map_imperatively( + User, + users, + properties={"addresses": relationship(Address, backref="user")}, + ) + self.mapper_registry.map_imperatively( + Address, + addresses, + properties={"dingaling": relationship(Dingaling)}, + ) + self.mapper_registry.map_imperatively(Dingaling, dingalings) + sess = fixture_session() + u1 = User(name="ed") + u1.addresses.append(Address(email_address="ed@bar.com")) + sess.add(u1) + sess.flush() + sess.expunge_all() + return sess, User, Address, Dingaling + + @testing.requires.non_broken_pickle + def test_became_bound_options(self): + sess, User, Address, Dingaling = self._option_test_fixture() + + for opt in [ + sa.orm.joinedload("addresses"), + sa.orm.defer("name"), + sa.orm.joinedload("addresses").joinedload(Address.dingaling), + ]: + with assertions.expect_deprecated_20(opt_strings_dep): + context = sess.query(User).options(opt)._compile_context() + opt = [ + v + for v in context.attributes.values() + if isinstance(v, sa.orm.Load) + ][0] + + opt2 = pickle.loads(pickle.dumps(opt)) + eq_(opt.path, opt2.path) + eq_(opt.local_opts, opt2.local_opts) + + u1 = sess.query(User).options(opt).first() + pickle.loads(pickle.dumps(u1)) + + @testing.requires.non_broken_pickle + @testing.combinations( + lambda: sa.orm.joinedload("addresses"), + lambda: sa.orm.defer("name"), + lambda Address: sa.orm.joinedload("addresses").joinedload( + Address.dingaling + ), + lambda: sa.orm.joinedload("addresses").raiseload("*"), + ) + def test_unbound_options(self, test_case): + sess, User, Address, Dingaling = self._option_test_fixture() + + opt = testing.resolve_lambda(test_case, User=User, Address=Address) + opt2 = pickle.loads(pickle.dumps(opt)) + eq_(opt.path, opt2.path) + + with assertions.expect_deprecated_20(opt_strings_dep): + u1 = sess.query(User).options(opt).first() + pickle.loads(pickle.dumps(u1)) + + @testing.requires.non_broken_pickle + @testing.combinations( + lambda User: sa.orm.Load(User).joinedload("addresses"), + lambda User: sa.orm.Load(User).joinedload("addresses").raiseload("*"), + lambda User: sa.orm.Load(User).defer("name"), + lambda User, Address: sa.orm.Load(User) + .joinedload("addresses") + .joinedload(Address.dingaling), + lambda User, Address: sa.orm.Load(User) + .joinedload("addresses", innerjoin=True) + .joinedload(Address.dingaling), + ) + def test_bound_options(self, test_case): + sess, User, Address, Dingaling = self._option_test_fixture() + + with assertions.expect_deprecated_20(opt_strings_dep): + opt = testing.resolve_lambda(test_case, User=User, Address=Address) + + opt2 = pickle.loads(pickle.dumps(opt)) + eq_(opt.path, opt2.path) + eq_(opt.context.keys(), opt2.context.keys()) + eq_(opt.local_opts, opt2.local_opts) + + u1 = sess.query(User).options(opt).first() + pickle.loads(pickle.dumps(u1)) + + +class SynonymTest(QueryTest, AssertsCompiledSQL): + __dialect__ = "default" + + @classmethod + def setup_mappers(cls): + ( + users, + Keyword, + items, + order_items, + orders, + Item, + User, + Address, + keywords, + Order, + item_keywords, + addresses, + ) = ( + cls.tables.users, + cls.classes.Keyword, + cls.tables.items, + cls.tables.order_items, + cls.tables.orders, + cls.classes.Item, + cls.classes.User, + cls.classes.Address, + cls.tables.keywords, + cls.classes.Order, + cls.tables.item_keywords, + cls.tables.addresses, + ) + + cls.mapper_registry.map_imperatively( + User, + users, + properties={ + "name_syn": synonym("name"), + "addresses": relationship(Address), + "orders": relationship( + Order, backref="user", order_by=orders.c.id + ), # o2m, m2o + "orders_syn": synonym("orders"), + "orders_syn_2": synonym("orders_syn"), + }, + ) + cls.mapper_registry.map_imperatively(Address, addresses) + cls.mapper_registry.map_imperatively( + Order, + orders, + properties={ + "items": relationship(Item, secondary=order_items), # m2m + "address": relationship(Address), # m2o + "items_syn": synonym("items"), + }, + ) + cls.mapper_registry.map_imperatively( + Item, + items, + properties={ + "keywords": relationship( + Keyword, secondary=item_keywords + ) # m2m + }, + ) + cls.mapper_registry.map_imperatively(Keyword, keywords) + + def test_options_syn_of_syn_string(self): + User, Order = self.classes.User, self.classes.Order + + s = fixture_session() + + def go(): + with testing.expect_deprecated_20(opt_strings_dep): + result = ( + s.query(User) + .filter_by(name="jack") + .options(joinedload("orders_syn_2")) + .all() + ) + eq_( + result, + [ + User( + id=7, + name="jack", + orders=[ + Order(description="order 1"), + Order(description="order 3"), + Order(description="order 5"), + ], + ) + ], + ) + + self.assert_sql_count(testing.db, go, 1) + + class DeprecatedQueryTest(_fixtures.FixtureTest, AssertsCompiledSQL): __dialect__ = "default" @@ -310,10 +671,7 @@ class DeprecatedQueryTest(_fixtures.FixtureTest, AssertsCompiledSQL): q1 = s.query(User).options(joinedload("addresses")) - with testing.expect_deprecated_20( - "Using strings to indicate column or relationship " - "paths in loader options" - ): + with testing.expect_deprecated_20(opt_strings_dep): self.assert_compile( q1, "SELECT users.id AS users_id, users.name AS users_name, " @@ -2754,16 +3112,10 @@ class DeprecatedOptionAllTest(OptionsPathTest, _fixtures.FixtureTest): sess = fixture_session() - with testing.expect_deprecated( - r"The \*addl_attrs on orm.defer is deprecated. " - "Please use method chaining" - ): + with testing.expect_deprecated(undefer_needs_chaining): sess.query(User).options(defer("addresses", "email_address")) - with testing.expect_deprecated( - r"The \*addl_attrs on orm.undefer is deprecated. " - "Please use method chaining" - ): + with testing.expect_deprecated(undefer_needs_chaining): sess.query(User).options(undefer("addresses", "email_address")) @@ -3128,20 +3480,22 @@ class NonPrimaryRelationshipLoaderTest(_fixtures.FixtureTest): closed_mapper = User.closed_orders.entity open_mapper = User.open_orders.entity - eq_( - [Order(id=1), Order(id=5)], - fixture_session() - .query(closed_mapper) - .with_parent(user, property="closed_orders") - .all(), - ) - eq_( - [Order(id=3)], - fixture_session() - .query(open_mapper) - .with_parent(user, property="open_orders") - .all(), - ) + with testing.expect_deprecated_20(wparent_strings_dep): + eq_( + [Order(id=1), Order(id=5)], + fixture_session() + .query(closed_mapper) + .with_parent(user, property="closed_orders") + .all(), + ) + with testing.expect_deprecated_20(wparent_strings_dep): + eq_( + [Order(id=3)], + fixture_session() + .query(open_mapper) + .with_parent(user, property="open_orders") + .all(), + ) class ViewonlyFlagWarningTest(fixtures.MappedTest): @@ -4078,6 +4432,43 @@ class DeclarativeBind(fixtures.TestBase): class JoinTest(QueryTest, AssertsCompiledSQL): __dialect__ = "default" + @testing.combinations( + "string_relationship", + "string_relationship_only", + ) + def test_filter_by_from_join(self, onclause_type): + User, Address = self.classes("User", "Address") + (address_table,) = self.tables("addresses") + (user_table,) = self.tables("users") + + sess = fixture_session() + q = sess.query(User) + + with assertions.expect_deprecated_20(join_strings_dep): + if onclause_type == "string_relationship": + q = q.join(Address, "addresses") + elif onclause_type == "string_relationship_only": + q = q.join("addresses") + else: + assert False + + q2 = q.filter_by(email_address="foo") + + self.assert_compile( + q2, + "SELECT users.id AS users_id, users.name AS users_name " + "FROM users JOIN addresses ON users.id = addresses.user_id " + "WHERE addresses.email_address = :email_address_1", + ) + + q2 = q.reset_joinpoint().filter_by(name="user") + self.assert_compile( + q2, + "SELECT users.id AS users_id, users.name AS users_name " + "FROM users JOIN addresses ON users.id = addresses.user_id " + "WHERE users.name = :name_1", + ) + def test_implicit_joins_from_aliases(self): Item, User, Order = ( self.classes.Item, @@ -5266,6 +5657,75 @@ class InheritedJoinTest( AssertsCompiledSQL, ): run_setup_mappers = "once" + __dialect__ = "default" + + def test_load_only_alias_subclass(self): + Manager = self.classes.Manager + + s = fixture_session() + m1 = aliased(Manager, flat=True) + q = ( + s.query(m1) + .order_by(m1.person_id) + .options(load_only("status", "manager_name")) + ) + with assertions.expect_deprecated_20(opt_strings_dep): + self.assert_compile( + q, + "SELECT managers_1.person_id AS managers_1_person_id, " + "people_1.person_id AS people_1_person_id, " + "people_1.type AS people_1_type, " + "managers_1.status AS managers_1_status, " + "managers_1.manager_name AS managers_1_manager_name " + "FROM people AS people_1 JOIN managers AS " + "managers_1 ON people_1.person_id = managers_1.person_id " + "ORDER BY managers_1.person_id", + ) + + def test_load_only_alias_subclass_bound(self): + Manager = self.classes.Manager + + s = fixture_session() + m1 = aliased(Manager, flat=True) + with assertions.expect_deprecated_20(opt_strings_dep): + q = ( + s.query(m1) + .order_by(m1.person_id) + .options(Load(m1).load_only("status", "manager_name")) + ) + self.assert_compile( + q, + "SELECT managers_1.person_id AS managers_1_person_id, " + "people_1.person_id AS people_1_person_id, " + "people_1.type AS people_1_type, " + "managers_1.status AS managers_1_status, " + "managers_1.manager_name AS managers_1_manager_name " + "FROM people AS people_1 JOIN managers AS " + "managers_1 ON people_1.person_id = managers_1.person_id " + "ORDER BY managers_1.person_id", + ) + + def test_load_only_of_type_with_polymorphic(self): + Company, Person, Manager = self.classes("Company", "Person", "Manager") + s = fixture_session() + + wp = with_polymorphic(Person, [Manager], flat=True) + + # needs to be explicit, we don't currently dig onto all the + # sub-entities in the wp + with assertions.expect_deprecated_20(opt_strings_dep): + assert_raises_message( + sa.exc.ArgumentError, + r'Can\'t find property named "status" on ' + r"with_polymorphic\(Person, \[Manager\]\) in this Query.", + s.query(Company) + .options( + joinedload(Company.employees.of_type(wp)).load_only( + "status" + ) + ) + ._compile_context, + ) def test_join_to_selectable(self): people, Company, engineers, Engineer = ( @@ -5957,3 +6417,834 @@ class RequirementsTest(fixtures.MappedTest): # TODO: is weakref support detectable without an instance? # self.assertRaises( # sa.exc.ArgumentError, mapper, NoWeakrefSupport, t2) + + +class DeferredOptionsTest(AssertsCompiledSQL, _fixtures.FixtureTest): + __dialect__ = "default" + + def test_load_only_synonym(self): + orders, Order = self.tables.orders, self.classes.Order + + self.mapper_registry.map_imperatively( + Order, + orders, + properties={"desc": synonym("description")}, + ) + + opt = load_only("isopen", "desc") + + sess = fixture_session() + q = sess.query(Order).options(opt) + with assertions.expect_deprecated_20(opt_strings_dep): + self.assert_compile( + q, + "SELECT orders.id AS orders_id, orders.description " + "AS orders_description, orders.isopen AS orders_isopen " + "FROM orders", + ) + + def test_deep_options(self): + users, items, order_items, Order, Item, User, orders = ( + self.tables.users, + self.tables.items, + self.tables.order_items, + self.classes.Order, + self.classes.Item, + self.classes.User, + self.tables.orders, + ) + + self.mapper_registry.map_imperatively( + Item, + items, + properties=dict(description=deferred(items.c.description)), + ) + self.mapper_registry.map_imperatively( + Order, + orders, + properties=dict(items=relationship(Item, secondary=order_items)), + ) + self.mapper_registry.map_imperatively( + User, + users, + properties=dict(orders=relationship(Order, order_by=orders.c.id)), + ) + + sess = fixture_session() + q = sess.query(User).order_by(User.id) + result = q.all() + item = result[0].orders[1].items[1] + + def go(): + eq_(item.description, "item 4") + + self.sql_count_(1, go) + eq_(item.description, "item 4") + + sess.expunge_all() + with assertions.expect_deprecated(undefer_needs_chaining): + result = q.options( + undefer(User.orders, Order.items, Item.description) + ).all() + item = result[0].orders[1].items[1] + + def go(): + eq_(item.description, "item 4") + + self.sql_count_(0, go) + eq_(item.description, "item 4") + + +class OptionsTest(PathTest, OptionsQueryTest): + def _option_fixture(self, *arg): + return strategy_options._UnboundLoad._from_keys( + strategy_options._UnboundLoad.joinedload, arg, True, {} + ) + + def test_chained(self): + User = self.classes.User + Order = self.classes.Order + sess = fixture_session() + q = sess.query(User) + opt = self._option_fixture(User.orders).joinedload("items") + with assertions.expect_deprecated_20(opt_strings_dep): + self._assert_path_result( + opt, q, [(User, "orders"), (User, "orders", Order, "items")] + ) + + def test_chained_plus_dotted(self): + User = self.classes.User + Order = self.classes.Order + Item = self.classes.Item + sess = fixture_session() + q = sess.query(User) + opt = self._option_fixture("orders.items").joinedload("keywords") + with assertions.expect_deprecated_20(opt_strings_dep): + self._assert_path_result( + opt, + q, + [ + (User, "orders"), + (User, "orders", Order, "items"), + (User, "orders", Order, "items", Item, "keywords"), + ], + ) + + def test_with_current_matching_string(self): + Item, User, Order = ( + self.classes.Item, + self.classes.User, + self.classes.Order, + ) + + sess = fixture_session() + q = sess.query(Item)._with_current_path( + self._make_path_registry([User, "orders", Order, "items"]) + ) + + opt = self._option_fixture("orders.items.keywords") + with assertions.expect_deprecated_20(opt_strings_dep): + self._assert_path_result(opt, q, [(Item, "keywords")]) + + def test_with_current_nonmatching_string(self): + Item, User, Order = ( + self.classes.Item, + self.classes.User, + self.classes.Order, + ) + + sess = fixture_session() + q = sess.query(Item)._with_current_path( + self._make_path_registry([User, "orders", Order, "items"]) + ) + + opt = self._option_fixture("keywords") + self._assert_path_result(opt, q, []) + + opt = self._option_fixture("items.keywords") + self._assert_path_result(opt, q, []) + + def test_path_multilevel_string(self): + Item, User, Order = ( + self.classes.Item, + self.classes.User, + self.classes.Order, + ) + + sess = fixture_session() + q = sess.query(User) + + opt = self._option_fixture("orders.items.keywords") + with assertions.expect_deprecated_20(opt_strings_dep): + self._assert_path_result( + opt, + q, + [ + (User, "orders"), + (User, "orders", Order, "items"), + (User, "orders", Order, "items", Item, "keywords"), + ], + ) + + def test_chained_plus_multi(self): + User = self.classes.User + Order = self.classes.Order + Item = self.classes.Item + sess = fixture_session() + q = sess.query(User) + opt = self._option_fixture(User.orders, Order.items).joinedload( + "keywords" + ) + with assertions.expect_deprecated_20(opt_strings_dep): + self._assert_path_result( + opt, + q, + [ + (User, "orders"), + (User, "orders", Order, "items"), + (User, "orders", Order, "items", Item, "keywords"), + ], + ) + + def test_multi_entity_opt_on_string(self): + Item = self.classes.Item + Order = self.classes.Order + opt = self._option_fixture("items") + sess = fixture_session() + q = sess.query(Item, Order) + with assertions.expect_deprecated_20(opt_strings_dep): + self._assert_path_result(opt, q, []) + + def test_get_path_one_level_string(self): + User = self.classes.User + + sess = fixture_session() + q = sess.query(User) + + opt = self._option_fixture("addresses") + with assertions.expect_deprecated_20(opt_strings_dep): + self._assert_path_result(opt, q, [(User, "addresses")]) + + def test_get_path_one_level_with_unrelated(self): + Order = self.classes.Order + + sess = fixture_session() + q = sess.query(Order) + opt = self._option_fixture("addresses") + with assertions.expect_deprecated_20(opt_strings_dep): + self._assert_path_result(opt, q, []) + + +class SubOptionsTest(PathTest, OptionsQueryTest): + run_create_tables = False + run_inserts = None + run_deletes = None + + def _assert_opts(self, q, sub_opt, non_sub_opts): + attr_a = {} + + for val in sub_opt._to_bind: + val._bind_loader( + [ + ent.entity_zero + for ent in q._compile_state()._lead_mapper_entities + ], + q._compile_options._current_path, + attr_a, + False, + ) + + attr_b = {} + + for opt in non_sub_opts: + for val in opt._to_bind: + val._bind_loader( + [ + ent.entity_zero + for ent in q._compile_state()._lead_mapper_entities + ], + q._compile_options._current_path, + attr_b, + False, + ) + + for k, l in attr_b.items(): + if not l.strategy: + del attr_b[k] + + def strat_as_tuple(strat): + return ( + strat.strategy, + strat.local_opts, + strat.propagate_to_loaders, + strat._of_type, + strat.is_class_strategy, + strat.is_opts_only, + ) + + eq_( + {path: strat_as_tuple(load) for path, load in attr_a.items()}, + {path: strat_as_tuple(load) for path, load in attr_b.items()}, + ) + + def test_invalid_two(self): + User, Address, Order, Item, SubItem = self.classes( + "User", "Address", "Order", "Item", "SubItem" + ) + + # these options are "invalid", in that User.orders -> Item.keywords + # is not a path. However, the "normal" option is not generating + # an error for now, which is bad, but we're testing here only that + # it works the same way, so there you go. If and when we make this + # case raise, then both cases should raise in the same way. + sub_opt = joinedload("orders").options( + joinedload("keywords"), joinedload("items") + ) + non_sub_opts = [ + joinedload(User.orders).joinedload(Item.keywords), + defaultload(User.orders).joinedload(Order.items), + ] + sess = fixture_session() + with assertions.expect_deprecated_20(opt_strings_dep): + self._assert_opts(sess.query(User), sub_opt, non_sub_opts) + + def test_four_strings(self): + User, Address, Order, Item, SubItem, Keyword = self.classes( + "User", "Address", "Order", "Item", "SubItem", "Keyword" + ) + sub_opt = joinedload("orders").options( + defer("description"), + joinedload("items").options( + joinedload("keywords").options(defer("name")), + defer("description"), + ), + ) + non_sub_opts = [ + joinedload(User.orders), + defaultload(User.orders).defer(Order.description), + defaultload(User.orders).joinedload(Order.items), + defaultload(User.orders) + .defaultload(Order.items) + .joinedload(Item.keywords), + defaultload(User.orders) + .defaultload(Order.items) + .defer(Item.description), + defaultload(User.orders) + .defaultload(Order.items) + .defaultload(Item.keywords) + .defer(Keyword.name), + ] + sess = fixture_session() + with assertions.expect_deprecated_20(opt_strings_dep): + self._assert_opts(sess.query(User), sub_opt, non_sub_opts) + + def test_five_strings(self): + User, Address, Order, Item, SubItem, Keyword = self.classes( + "User", "Address", "Order", "Item", "SubItem", "Keyword" + ) + sub_opt = joinedload("orders").options(load_only("description")) + non_sub_opts = [ + joinedload(User.orders), + defaultload(User.orders).load_only(Order.description), + ] + sess = fixture_session() + with assertions.expect_deprecated_20(opt_strings_dep): + self._assert_opts(sess.query(User), sub_opt, non_sub_opts) + + +class OptionsNoPropTest(_fixtures.FixtureTest): + """test the error messages emitted when using property + options in conjunction with column-only entities, or + for not existing options + + """ + + run_create_tables = False + run_inserts = None + run_deletes = None + + def test_option_with_column_basestring(self): + Item = self.classes.Item + + message = ( + "Query has only expression-based entities - can't " + 'find property named "keywords".' + ) + self._assert_eager_with_just_column_exception( + Item.id, "keywords", message + ) + + def test_option_against_nonexistent_basestring(self): + Item = self.classes.Item + with assertions.expect_deprecated_20(opt_strings_dep): + self._assert_eager_with_entity_exception( + [Item], + (joinedload("foo"),), + 'Can\'t find property named "foo" on mapped class ' + "Item->items in this Query.", + ) + + def test_option_against_nonexistent_twolevel_basestring(self): + Item = self.classes.Item + with assertions.expect_deprecated_20(opt_strings_dep): + self._assert_eager_with_entity_exception( + [Item], + (joinedload("keywords.foo"),), + 'Can\'t find property named "foo" on mapped class ' + "Keyword->keywords in this Query.", + ) + + def test_option_against_nonexistent_twolevel_chained(self): + Item = self.classes.Item + with assertions.expect_deprecated_20(opt_strings_dep): + self._assert_eager_with_entity_exception( + [Item], + (joinedload("keywords").joinedload("foo"),), + 'Can\'t find property named "foo" on mapped class ' + "Keyword->keywords in this Query.", + ) + + @testing.fails_if( + lambda: True, + "PropertyOption doesn't yet check for relation/column on end result", + ) + def test_option_against_non_relation_basestring(self): + Item = self.classes.Item + Keyword = self.classes.Keyword + self._assert_eager_with_entity_exception( + [Keyword, Item], + (joinedload("keywords"),), + r"Attribute 'keywords' of entity 'Mapper\|Keyword\|keywords' " + "does not refer to a mapped entity", + ) + + @testing.fails_if( + lambda: True, + "PropertyOption doesn't yet check for relation/column on end result", + ) + def test_option_against_multi_non_relation_basestring(self): + Item = self.classes.Item + Keyword = self.classes.Keyword + self._assert_eager_with_entity_exception( + [Keyword, Item], + (joinedload("keywords"),), + r"Attribute 'keywords' of entity 'Mapper\|Keyword\|keywords' " + "does not refer to a mapped entity", + ) + + def test_option_against_wrong_entity_type_basestring(self): + Item = self.classes.Item + with assertions.expect_deprecated_20(opt_strings_dep): + self._assert_loader_strategy_exception( + [Item], + (joinedload("id").joinedload("keywords"),), + 'Can\'t apply "joined loader" strategy to property "Item.id", ' + 'which is a "column property"; this loader strategy is ' + 'intended to be used with a "relationship property".', + ) + + def test_col_option_against_relationship_basestring(self): + Item = self.classes.Item + with assertions.expect_deprecated_20(opt_strings_dep): + self._assert_loader_strategy_exception( + [Item], + (load_only("keywords"),), + 'Can\'t apply "column loader" strategy to property ' + '"Item.keywords", which is a "relationship property"; this ' + "loader strategy is intended to be used with a " + '"column property".', + ) + + def test_option_against_multi_non_relation_twolevel_basestring(self): + Item = self.classes.Item + Keyword = self.classes.Keyword + with assertions.expect_deprecated_20(opt_strings_dep): + self._assert_loader_strategy_exception( + [Keyword, Item], + (joinedload("id").joinedload("keywords"),), + 'Can\'t apply "joined loader" strategy to property ' + '"Keyword.id", ' + 'which is a "column property"; this loader strategy is ' + "intended " + 'to be used with a "relationship property".', + ) + + def test_option_against_multi_nonexistent_basestring(self): + Item = self.classes.Item + Keyword = self.classes.Keyword + with assertions.expect_deprecated_20(opt_strings_dep): + self._assert_eager_with_entity_exception( + [Keyword, Item], + (joinedload("description"),), + 'Can\'t find property named "description" on mapped class ' + "Keyword->keywords in this Query.", + ) + + def test_option_against_multi_no_entities_basestring(self): + Item = self.classes.Item + Keyword = self.classes.Keyword + self._assert_eager_with_entity_exception( + [Keyword.id, Item.id], + (joinedload("keywords"),), + r"Query has only expression-based entities - can't find property " + 'named "keywords".', + ) + + def test_option_with_mapper_then_column_basestring(self): + Item = self.classes.Item + + with assertions.expect_deprecated_20(opt_strings_dep): + self._assert_option([Item, Item.id], "keywords") + + def test_option_with_mapper_basestring(self): + Item = self.classes.Item + + with assertions.expect_deprecated_20(opt_strings_dep): + self._assert_option([Item], "keywords") + + def test_option_with_column_then_mapper_basestring(self): + Item = self.classes.Item + + with assertions.expect_deprecated_20(opt_strings_dep): + self._assert_option([Item.id, Item], "keywords") + + @classmethod + def setup_mappers(cls): + users, User, addresses, Address, orders, Order = ( + cls.tables.users, + cls.classes.User, + cls.tables.addresses, + cls.classes.Address, + cls.tables.orders, + cls.classes.Order, + ) + cls.mapper_registry.map_imperatively( + User, + users, + properties={ + "addresses": relationship(Address), + "orders": relationship(Order), + }, + ) + cls.mapper_registry.map_imperatively(Address, addresses) + cls.mapper_registry.map_imperatively(Order, orders) + keywords, items, item_keywords, Keyword, Item = ( + cls.tables.keywords, + cls.tables.items, + cls.tables.item_keywords, + cls.classes.Keyword, + cls.classes.Item, + ) + cls.mapper_registry.map_imperatively( + Keyword, + keywords, + properties={ + "keywords": column_property(keywords.c.name + "some keyword") + }, + ) + cls.mapper_registry.map_imperatively( + Item, + items, + properties=dict( + keywords=relationship(Keyword, secondary=item_keywords) + ), + ) + + class OrderWProp(cls.classes.Order): + @property + def some_attr(self): + return "hi" + + cls.mapper_registry.map_imperatively( + OrderWProp, None, inherits=cls.classes.Order + ) + + def _assert_option(self, entity_list, option): + Item = self.classes.Item + + context = ( + fixture_session() + .query(*entity_list) + .options(joinedload(option)) + ._compile_state() + ) + key = ("loader", (inspect(Item), inspect(Item).attrs.keywords)) + assert key in context.attributes + + def _assert_loader_strategy_exception(self, entity_list, options, message): + assert_raises_message( + orm_exc.LoaderStrategyException, + message, + fixture_session() + .query(*entity_list) + .options(*options) + ._compile_state, + ) + + def _assert_eager_with_entity_exception( + self, entity_list, options, message + ): + assert_raises_message( + sa.exc.ArgumentError, + message, + fixture_session() + .query(*entity_list) + .options(*options) + ._compile_state, + ) + + def _assert_eager_with_just_column_exception( + self, column, eager_option, message + ): + assert_raises_message( + sa.exc.ArgumentError, + message, + fixture_session() + .query(column) + .options(joinedload(eager_option)) + ._compile_state, + ) + + +class OptionsNoPropTestInh(_Polymorphic): + def test_missing_str_attr_of_type_subclass(self): + s = fixture_session() + + with assertions.expect_deprecated_20(opt_strings_dep): + assert_raises_message( + sa.exc.ArgumentError, + r'Can\'t find property named "manager_name" on ' + r"mapped class Engineer->engineers in this Query.$", + s.query(Company) + .options( + joinedload(Company.employees.of_type(Engineer)).load_only( + "manager_name" + ) + ) + ._compile_state, + ) + + +class CacheKeyTest(CacheKeyFixture, _fixtures.FixtureTest): + """In these tests we've moved / adapted all the tests from + test_cache_key that make use of string options or string join(). Because + we are ensuring cache keys are distinct we still keep a lot of the + non-deprecated cases in the lists that we are testing. + + """ + + run_setup_mappers = "once" + run_inserts = None + run_deletes = None + + @classmethod + def setup_mappers(cls): + cls._setup_stock_mapping() + + def _stmt_20(self, *elements): + return tuple( + elem._statement_20() if isinstance(elem, sa.orm.Query) else elem + for elem in elements + ) + + def _deprecated_opt(self, fn): + with assertions.expect_deprecated_20( + opt_strings_dep, raise_on_any_unexpected=True + ): + return fn() + + def _deprecated_join(self, fn): + with assertions.expect_deprecated_20( + join_strings_dep, raise_on_any_unexpected=True + ): + return fn() + + def _deprecated_join_w_aliased(self, fn): + with assertions.expect_deprecated_20( + join_strings_dep, join_aliased_dep, raise_on_any_unexpected=True + ): + return fn() + + def test_bound_options(self): + User, Address, Keyword, Order, Item = self.classes( + "User", "Address", "Keyword", "Order", "Item" + ) + + self._run_cache_key_fixture( + lambda: ( + Load(User).joinedload(User.addresses), + Load(User).joinedload( + User.addresses.of_type(aliased(Address)) + ), + Load(User).joinedload(User.orders), + self._deprecated_opt( + lambda: Load(User).subqueryload("addresses") + ), + self._deprecated_opt(lambda: Load(Address).defer("id")), + Load(Address).defer("*"), + self._deprecated_opt( + lambda: Load(aliased(Address)).defer("id") + ), + Load(User).joinedload(User.addresses).defer(Address.id), + Load(User).joinedload(User.orders).joinedload(Order.items), + Load(User).joinedload(User.orders).subqueryload(Order.items), + Load(User).subqueryload(User.orders).subqueryload(Order.items), + Load(Address).raiseload("*"), + self._deprecated_opt(lambda: Load(Address).raiseload("user")), + ), + compare_values=True, + ) + + def test_bound_options_equiv_on_strname(self): + """Bound loader options resolve on string name so test that the cache + key for the string version matches the resolved version. + + """ + User, Address, Keyword, Order, Item = self.classes( + "User", "Address", "Keyword", "Order", "Item" + ) + + for left, right in [ + ( + Load(User).defer(User.id), + self._deprecated_opt(lambda: Load(User).defer("id")), + ), + ( + Load(User).joinedload(User.addresses), + self._deprecated_opt( + lambda: Load(User).joinedload("addresses") + ), + ), + ( + Load(User).joinedload(User.orders).joinedload(Order.items), + self._deprecated_opt( + lambda: Load(User).joinedload("orders").joinedload("items") + ), + ), + ]: + eq_(left._generate_cache_key(), right._generate_cache_key()) + + def test_orm_query_w_orm_joins(self): + + User, Address, Keyword, Order, Item = self.classes( + "User", "Address", "Keyword", "Order", "Item" + ) + + a1 = aliased(Address) + + self._run_cache_key_fixture( + lambda: self._stmt_20( + fixture_session().query(User).join(User.addresses), + fixture_session().query(User).join(User.orders), + fixture_session() + .query(User) + .join(User.addresses) + .join(User.orders), + self._deprecated_join_w_aliased( + lambda: fixture_session() + .query(User) + .join("addresses") + .join("dingalings", from_joinpoint=True) + ), + self._deprecated_join( + lambda: fixture_session().query(User).join("addresses") + ), + self._deprecated_join( + lambda: fixture_session().query(User).join("orders") + ), + self._deprecated_join( + lambda: fixture_session() + .query(User) + .join("addresses") + .join("orders") + ), + fixture_session().query(User).join(Address, User.addresses), + self._deprecated_join( + lambda: fixture_session().query(User).join(a1, "addresses") + ), + self._deprecated_join_w_aliased( + lambda: fixture_session() + .query(User) + .join(a1, "addresses", aliased=True) + ), + fixture_session().query(User).join(User.addresses.of_type(a1)), + ), + compare_values=True, + ) + + def test_unbound_options(self): + User, Address, Keyword, Order, Item = self.classes( + "User", "Address", "Keyword", "Order", "Item" + ) + + # unbound options dont emit a deprecation warning during cache + # key generation + self._run_cache_key_fixture( + lambda: ( + joinedload(User.addresses), + joinedload(User.addresses.of_type(aliased(Address))), + joinedload("addresses"), + joinedload(User.orders), + joinedload(User.orders.and_(Order.id != 5)), + joinedload(User.orders).selectinload("items"), + joinedload(User.orders).selectinload(Order.items), + defer(User.id), + defer("id"), + defer("*"), + defer(Address.id), + joinedload(User.addresses).defer(Address.id), + joinedload(User.addresses).defer("id"), + subqueryload(User.orders) + .subqueryload(Order.items) + .defer(Item.description), + defaultload(User.orders).defaultload(Order.items), + defaultload(User.orders), + ), + compare_values=True, + ) + + def test_unbound_sub_options(self): + """test #6869""" + + User, Address, Keyword, Order, Item = self.classes( + "User", "Address", "Keyword", "Order", "Item" + ) + + self._run_cache_key_fixture( + lambda: ( + joinedload(User.addresses).options( + joinedload(Address.dingaling) + ), + joinedload(User.addresses).options( + joinedload(Address.dingaling).options(load_only("name")) + ), + joinedload(User.orders).options( + joinedload(Order.items).options(joinedload(Item.keywords)) + ), + ), + compare_values=True, + ) + + +class AliasedClassRelationshipTest( + PartitionByFixture, testing.AssertsCompiledSQL +): + __requires__ = ("window_functions",) + __dialect__ = "default" + + def test_selectinload_w_joinedload_after(self): + """test has been enhanced to also test #7224""" + + A, B, C = self.classes("A", "B", "C") + + s = Session(testing.db) + + opt = selectinload(A.partitioned_bs).joinedload("cs") + + def go(): + for a1 in s.query(A).options(opt): + for b in a1.partitioned_bs: + eq_(len(b.cs), 2) + + with assertions.expect_deprecated_20(opt_strings_dep): + self.assert_sql_count(testing.db, go, 2) diff --git a/test/orm/test_eager_relations.py b/test/orm/test_eager_relations.py index cb578ee2da..c235edadfa 100644 --- a/test/orm/test_eager_relations.py +++ b/test/orm/test_eager_relations.py @@ -754,7 +754,7 @@ class EagerTest(_fixtures.FixtureTest, testing.AssertsCompiledSQL): def go(): eq_( self.static.item_keyword_result[0:2], - q.join("keywords").filter(Keyword.name == "red").all(), + q.join(Item.keywords).filter(Keyword.name == "red").all(), ) self.assert_sql_count(testing.db, go, 1) @@ -763,7 +763,9 @@ class EagerTest(_fixtures.FixtureTest, testing.AssertsCompiledSQL): ka = aliased(Keyword) eq_( self.static.item_keyword_result[0:2], - (q.join(ka, "keywords").filter(ka.name == "red")).all(), + ( + q.join(Item.keywords.of_type(ka)).filter(ka.name == "red") + ).all(), ) self.assert_sql_count(testing.db, go, 1) @@ -1401,7 +1403,7 @@ class EagerTest(_fixtures.FixtureTest, testing.AssertsCompiledSQL): if not testing.against("mssql"): result = ( - q.join("orders") + q.join(User.orders) .order_by(Order.user_id.desc()) .limit(2) .offset(1) @@ -1423,7 +1425,7 @@ class EagerTest(_fixtures.FixtureTest, testing.AssertsCompiledSQL): ) result = ( - q.join("addresses") + q.join(User.addresses) .order_by(Address.email_address.desc()) .limit(1) .offset(0) @@ -4040,7 +4042,7 @@ class AddEntityTest(_fixtures.FixtureTest): def go(): ret = ( sess.query(User, oalias) - .join(oalias, "orders") + .join(User.orders.of_type(oalias)) .order_by(User.id, oalias.id) .all() ) @@ -4099,7 +4101,7 @@ class AddEntityTest(_fixtures.FixtureTest): ret = ( sess.query(User, oalias) .options(joinedload(User.addresses)) - .join(oalias, "orders") + .join(User.orders.of_type(oalias)) .order_by(User.id, oalias.id) .all() ) @@ -4113,7 +4115,7 @@ class AddEntityTest(_fixtures.FixtureTest): ret = ( sess.query(User, oalias) .options(joinedload(User.addresses), joinedload(oalias.items)) - .join(oalias, "orders") + .join(User.orders.of_type(oalias)) .order_by(User.id, oalias.id) .all() ) @@ -5972,7 +5974,9 @@ class EntityViaMultiplePathTestTwo(fixtures.DeclarativeMappedTest): s.query(LDA) .join(LDA.ld) .options(contains_eager(LDA.ld)) - .join("a", (l_ac, "ld"), (u_ac, "user")) + .join(LDA.a) + .join(A.ld.of_type(l_ac)) + .join(l_ac.user.of_type(u_ac)) .options( contains_eager(LDA.a) .contains_eager(A.ld, alias=l_ac) diff --git a/test/orm/test_expire.py b/test/orm/test_expire.py index 92a7ea42d3..d9204db96c 100644 --- a/test/orm/test_expire.py +++ b/test/orm/test_expire.py @@ -1157,7 +1157,7 @@ class ExpireTest(_fixtures.FixtureTest): assert "addresses" not in u.__dict__ ( sess.query(User) - .options(sa.orm.joinedload("addresses")) + .options(sa.orm.joinedload(User.addresses)) .filter_by(id=8) .all() ) @@ -1206,7 +1206,7 @@ class ExpireTest(_fixtures.FixtureTest): sess.expunge_all() # same tests, using deferred at the options level - o = sess.query(Order).options(sa.orm.defer("description")).get(3) + o = sess.query(Order).options(sa.orm.defer(Order.description)).get(3) assert "description" not in o.__dict__ @@ -1983,7 +1983,7 @@ class RefreshTest(_fixtures.FixtureTest): ) }, ) - q = s.query(User).options(sa.orm.lazyload("addresses")) + q = s.query(User).options(sa.orm.lazyload(User.addresses)) u = q.filter(users.c.id == 8).first() def go(): @@ -2049,7 +2049,9 @@ class RefreshTest(_fixtures.FixtureTest): q = ( s.query(User) .filter_by(name="fred") - .options(sa.orm.lazyload("addresses").joinedload("dingalings")) + .options( + sa.orm.lazyload(User.addresses).joinedload(Address.dingalings) + ) ) u1 = q.one() diff --git a/test/orm/test_froms.py b/test/orm/test_froms.py index d6579cebd1..3351967fc1 100644 --- a/test/orm/test_froms.py +++ b/test/orm/test_froms.py @@ -1098,7 +1098,7 @@ class InstancesTest(QueryTest, AssertsCompiledSQL): def go(): result = ( - q.options(contains_eager("addresses")) + q.options(contains_eager(User.addresses)) .from_statement(query) .all() ) @@ -1129,7 +1129,7 @@ class InstancesTest(QueryTest, AssertsCompiledSQL): ulist = query.alias("ulist") ulist_alias = aliased(User, alias=ulist) result = ( - q.options(contains_eager("addresses", alias=ulist)) + q.options(contains_eager(User.addresses, alias=ulist)) .select_entity_from(ulist_alias) .all() ) @@ -1160,7 +1160,7 @@ class InstancesTest(QueryTest, AssertsCompiledSQL): result = ( sess.query(User) .select_entity_from(query.subquery()) - .options(contains_eager("addresses")) + .options(contains_eager(User.addresses)) .all() ) assert self.static.user_address_result == result @@ -1194,7 +1194,7 @@ class InstancesTest(QueryTest, AssertsCompiledSQL): result = ( sess.query(User) .select_entity_from(query.subquery()) - .options(contains_eager("addresses", alias=adalias)) + .options(contains_eager(User.addresses, alias=adalias)) .all() ) assert self.static.user_address_result == result @@ -1273,7 +1273,7 @@ class InstancesTest(QueryTest, AssertsCompiledSQL): def go(): result = ( - q.options(contains_eager("addresses")) + q.options(contains_eager(User.addresses)) .from_statement(selectquery) .all() ) @@ -1302,7 +1302,7 @@ class InstancesTest(QueryTest, AssertsCompiledSQL): def go(): result = ( sess.execute( - q.options(contains_eager("addresses")).from_statement( + q.options(contains_eager(User.addresses)).from_statement( selectquery ) ) @@ -1325,7 +1325,7 @@ class InstancesTest(QueryTest, AssertsCompiledSQL): def go(): result = ( - q.options(contains_eager("addresses", alias=adalias)) + q.options(contains_eager(User.addresses.of_type(adalias))) .outerjoin(adalias, User.addresses) .order_by(User.id, adalias.id) ) @@ -1341,6 +1341,7 @@ class InstancesTest(QueryTest, AssertsCompiledSQL): self.tables.order_items, self.classes.User, ) + Order = self.classes.Order sess = fixture_session() q = sess.query(User) @@ -1357,16 +1358,12 @@ class InstancesTest(QueryTest, AssertsCompiledSQL): # test using Alias with more than one level deep - # new way: - # from sqlalchemy.orm.strategy_options import Load - # opt = Load(User).contains_eager('orders', alias=oalias). - # contains_eager('items', alias=ialias) - def go(): result = list( q.options( - contains_eager("orders", alias=oalias), - contains_eager("orders.items", alias=ialias), + contains_eager(User.orders, alias=oalias).contains_eager( + Order.items, alias=ialias + ), ).from_statement(query) ) assert self.static.user_order_result == result @@ -1869,7 +1866,7 @@ class MixedEntitiesTest(QueryTest, AssertsCompiledSQL): adalias = aliased(Address) eq_( sess.query(User, func.count(adalias.email_address)) - .outerjoin(adalias, "addresses") + .outerjoin(User.addresses.of_type(adalias)) .group_by(User) .order_by(User.id) .all(), @@ -2110,7 +2107,7 @@ class MixedEntitiesTest(QueryTest, AssertsCompiledSQL): results = ( sess.query(User) .limit(1) - .options(joinedload("addresses")) + .options(joinedload(User.addresses)) .add_columns(User.name) .all() ) @@ -2321,21 +2318,21 @@ class MixedEntitiesTest(QueryTest, AssertsCompiledSQL): q = ( sess.query(User) .add_entity(address_entity) - .outerjoin(address_entity, "addresses") + .outerjoin(address_entity, User.addresses) .order_by(User.id, address_entity.id) ) eq_(q.all(), expected) sess.expunge_all() q = sess.query(User).add_entity(address_entity) - q = q.join(address_entity, "addresses") + q = q.join(address_entity, User.addresses) q = q.filter_by(email_address="ed@bettyboop.com") eq_(q.all(), [(user8, address3)]) sess.expunge_all() q = ( sess.query(User, address_entity) - .join(address_entity, "addresses") + .join(address_entity, User.addresses) .filter_by(email_address="ed@bettyboop.com") ) eq_(q.all(), [(user8, address3)]) @@ -2343,8 +2340,8 @@ class MixedEntitiesTest(QueryTest, AssertsCompiledSQL): q = ( sess.query(User, address_entity) - .join(address_entity, "addresses") - .options(joinedload("addresses")) + .join(address_entity, User.addresses) + .options(joinedload(User.addresses)) .filter_by(email_address="ed@bettyboop.com") ) eq_(list(util.OrderedSet(q.all())), [(user8, address3)]) @@ -2458,7 +2455,7 @@ class MixedEntitiesTest(QueryTest, AssertsCompiledSQL): q = ( q.group_by(users) .order_by(User.id) - .outerjoin("addresses") + .outerjoin(User.addresses) .add_columns(func.count(Address.id).label("count")) ) eq_(q.all(), expected) @@ -2469,7 +2466,7 @@ class MixedEntitiesTest(QueryTest, AssertsCompiledSQL): q = ( q.group_by(users) .order_by(User.id) - .outerjoin(adalias, "addresses") + .outerjoin(User.addresses.of_type(adalias)) .add_columns(func.count(adalias.id).label("count")) ) eq_(q.all(), expected) @@ -2576,7 +2573,7 @@ class MixedEntitiesTest(QueryTest, AssertsCompiledSQL): .add_columns( func.count(addresses.c.id), ("Name:" + users.c.name) ) - .outerjoin("addresses") + .outerjoin(User.addresses) .group_by(users) .order_by(users.c.id) ) @@ -2604,21 +2601,21 @@ class MixedEntitiesTest(QueryTest, AssertsCompiledSQL): for crit, j, exp in [ ( User.id + Address.id, - User.addresses, + (User.addresses,), "SELECT users.id + addresses.id AS anon_1 " "FROM users JOIN addresses ON users.id = " "addresses.user_id", ), ( User.id + Address.id, - Address.user, + (Address.user,), "SELECT users.id + addresses.id AS anon_1 " "FROM addresses JOIN users ON users.id = " "addresses.user_id", ), ( Address.id + User.id, - User.addresses, + (User.addresses,), "SELECT addresses.id + users.id AS anon_1 " "FROM users JOIN addresses ON users.id = " "addresses.user_id", @@ -2634,13 +2631,13 @@ class MixedEntitiesTest(QueryTest, AssertsCompiledSQL): q = s.query(crit) mzero = q._compile_state()._entity_zero() is_(mzero, q._compile_state()._entities[0].entity_zero) - q = q.join(j) + q = q.join(*j) self.assert_compile(q, exp) for crit, j, exp in [ ( ua.id + Address.id, - ua.addresses, + (ua.addresses,), "SELECT users_1.id + addresses.id AS anon_1 " "FROM users AS users_1 JOIN addresses " "ON users_1.id = addresses.user_id", @@ -2664,7 +2661,7 @@ class MixedEntitiesTest(QueryTest, AssertsCompiledSQL): q = s.query(crit) mzero = q._compile_state()._entity_zero() is_(mzero, q._compile_state()._entities[0].entity_zero) - q = q.join(j) + q = q.join(*j) self.assert_compile(q, exp) def test_aliased_adapt_on_names(self): @@ -2764,7 +2761,7 @@ class SelectFromTest(QueryTest, AssertsCompiledSQL): eq_( sess.query(User) .select_entity_from(sel) - .options(joinedload("addresses")) + .options(joinedload(User.addresses)) .first(), User(name="jack", addresses=[Address(id=1)]), ) @@ -2980,7 +2977,7 @@ class SelectFromTest(QueryTest, AssertsCompiledSQL): sess = fixture_session() self.assert_compile( - sess.query(User).select_from(Address).join("user"), + sess.query(User).select_from(Address).join(Address.user), "SELECT users.id AS users_id, users.name AS users_name " "FROM addresses JOIN users ON users.id = addresses.user_id", ) @@ -3050,7 +3047,7 @@ class SelectFromTest(QueryTest, AssertsCompiledSQL): eq_( sess.query(User) .select_entity_from(sel.subquery()) - .join("addresses") + .join(User.addresses) .add_entity(Address) .order_by(User.id) .order_by(Address.id) @@ -3079,7 +3076,7 @@ class SelectFromTest(QueryTest, AssertsCompiledSQL): eq_( sess.query(User) .select_entity_from(sel.subquery()) - .join(adalias, "addresses") + .join(adalias, User.addresses) .add_entity(adalias) .order_by(User.id) .order_by(adalias.id) @@ -3161,7 +3158,9 @@ class SelectFromTest(QueryTest, AssertsCompiledSQL): eq_( sess.query(User) .select_entity_from(sel.subquery()) - .join(User.orders, Order.items, Item.keywords) + .join(User.orders) + .join(Order.items) + .join(Item.keywords) .filter(Keyword.name.in_(["red", "big", "round"])) .all(), [User(name="jack", id=7)], @@ -3226,11 +3225,13 @@ class SelectFromTest(QueryTest, AssertsCompiledSQL): sess.query(User) .select_entity_from(sel.subquery()) .options( - joinedload("orders") - .joinedload("items") - .joinedload("keywords") + joinedload(User.orders) + .joinedload(Order.items) + .joinedload(Item.keywords) ) - .join(User.orders, Order.items, Item.keywords) + .join(User.orders) + .join(Order.items) + .join(Item.keywords) .filter(Keyword.name.in_(["red", "big", "round"])) .all(), [ @@ -3337,7 +3338,7 @@ class SelectFromTest(QueryTest, AssertsCompiledSQL): def go(): eq_( sess.query(User) - .options(joinedload("addresses")) + .options(joinedload(User.addresses)) .select_entity_from(sel.subquery()) .order_by(User.id) .all(), @@ -3360,7 +3361,7 @@ class SelectFromTest(QueryTest, AssertsCompiledSQL): def go(): eq_( sess.query(User) - .options(joinedload("addresses")) + .options(joinedload(User.addresses)) .select_entity_from(sel.subquery()) .filter(User.id == 8) .order_by(User.id) @@ -3383,7 +3384,7 @@ class SelectFromTest(QueryTest, AssertsCompiledSQL): def go(): eq_( sess.query(User) - .options(joinedload("addresses")) + .options(joinedload(User.addresses)) .select_entity_from(sel.subquery()) .order_by(User.id)[1], User( @@ -3398,79 +3399,6 @@ class SelectFromTest(QueryTest, AssertsCompiledSQL): class CustomJoinTest(QueryTest): run_setup_mappers = None - def test_double_same_mappers_flag_alias(self): - """test aliasing of joins with a custom join condition""" - - ( - addresses, - items, - order_items, - orders, - Item, - User, - Address, - Order, - users, - ) = ( - self.tables.addresses, - self.tables.items, - self.tables.order_items, - self.tables.orders, - self.classes.Item, - self.classes.User, - self.classes.Address, - self.classes.Order, - self.tables.users, - ) - - self.mapper_registry.map_imperatively(Address, addresses) - self.mapper_registry.map_imperatively( - Order, - orders, - properties={ - "items": relationship( - Item, - secondary=order_items, - lazy="select", - order_by=items.c.id, - ) - }, - ) - self.mapper_registry.map_imperatively(Item, items) - self.mapper_registry.map_imperatively( - User, - users, - properties=dict( - addresses=relationship(Address, lazy="select"), - open_orders=relationship( - Order, - primaryjoin=and_( - orders.c.isopen == 1, users.c.id == orders.c.user_id - ), - lazy="select", - viewonly=True, - ), - closed_orders=relationship( - Order, - primaryjoin=and_( - orders.c.isopen == 0, users.c.id == orders.c.user_id - ), - lazy="select", - viewonly=True, - ), - ), - ) - q = fixture_session().query(User) - - eq_( - q.join("open_orders", "items", aliased=True) - .filter(Item.id == 4) - .join("closed_orders", "items", aliased=True) - .filter(Item.id == 3) - .all(), - [User(id=7)], - ) - def test_double_same_mappers_explicit_alias(self): """test aliasing of joins with a custom join condition""" @@ -3614,7 +3542,7 @@ class ExternalColumnsTest(QueryTest): sess = fixture_session() - sess.query(Address).options(joinedload("user")).all() + sess.query(Address).options(joinedload(Address.user)).all() eq_( sess.query(User).all(), @@ -3647,7 +3575,7 @@ class ExternalColumnsTest(QueryTest): def go(): eq_( sess.query(Address) - .options(joinedload("user")) + .options(joinedload(Address.user)) .order_by(Address.id) .all(), address_result, @@ -3657,15 +3585,15 @@ class ExternalColumnsTest(QueryTest): ualias = aliased(User) eq_( - sess.query(Address, ualias).join(ualias, "user").all(), + sess.query(Address, ualias).join(ualias, Address.user).all(), [(address, address.user) for address in address_result], ) ualias2 = aliased(User) eq_( sess.query(Address, ualias.count) - .join(ualias, "user") - .join(ualias2, "user") + .join(ualias, Address.user) + .join(ualias2, Address.user) .order_by(Address.id) .all(), [ @@ -3679,8 +3607,8 @@ class ExternalColumnsTest(QueryTest): eq_( sess.query(Address, ualias.concat, ualias.count) - .join(ualias, "user") - .join(ualias2, "user") + .join(Address.user.of_type(ualias)) + .join(Address.user.of_type(ualias2)) .order_by(Address.id) .all(), [ @@ -3711,7 +3639,7 @@ class ExternalColumnsTest(QueryTest): eq_( list( sess.query(Address) - .join("user") + .join(Address.user) .with_entities(Address.id, User.id, User.concat, User.count) ), [ @@ -3726,7 +3654,7 @@ class ExternalColumnsTest(QueryTest): eq_( list( sess.query(Address, ua) - .select_entity_from(join(Address, ua, "user")) + .select_entity_from(join(Address, ua, Address.user)) .with_entities(Address.id, ua.id, ua.concat, ua.count) ), [ @@ -3782,7 +3710,7 @@ class ExternalColumnsTest(QueryTest): def go(): o1 = ( sess.query(Order) - .options(joinedload("address").joinedload("user")) + .options(joinedload(Order.address).joinedload(Address.user)) .get(1) ) eq_(o1.address.user.count, 1) @@ -3794,7 +3722,7 @@ class ExternalColumnsTest(QueryTest): def go(): o1 = ( sess.query(Order) - .options(joinedload("address").joinedload("user")) + .options(joinedload(Order.address).joinedload(Address.user)) .first() ) eq_(o1.address.user.count, 1) diff --git a/test/orm/test_generative.py b/test/orm/test_generative.py index 1a40447a6d..0713462775 100644 --- a/test/orm/test_generative.py +++ b/test/orm/test_generative.py @@ -264,11 +264,13 @@ class RelationshipsTest(_fixtures.FixtureTest): """Query.join""" User, Address = self.classes.User, self.classes.Address + Order = self.classes.Order session = fixture_session() q = ( session.query(User) - .join("orders", "addresses") + .outerjoin(User.orders) + .outerjoin(Order.addresses) .filter(Address.id == 1) ) eq_([User(id=7)], q.all()) @@ -285,7 +287,8 @@ class RelationshipsTest(_fixtures.FixtureTest): session = fixture_session() q = ( session.query(User) - .outerjoin("orders", "addresses") + .outerjoin(User.orders) + .outerjoin(Order.addresses) .filter(sa.or_(Order.id == None, Address.id == 1)) ) # noqa eq_(set([User(id=7), User(id=8), User(id=10)]), set(q.all())) @@ -303,7 +306,8 @@ class RelationshipsTest(_fixtures.FixtureTest): q = ( session.query(User) - .outerjoin("orders", "addresses") + .outerjoin(User.orders) + .outerjoin(Order.addresses) .filter(sa.or_(Order.id == None, Address.id == 1)) ) # noqa eq_(q.count(), 4) diff --git a/test/orm/test_joins.py b/test/orm/test_joins.py index eb7dfd6f38..42f9b9aa16 100644 --- a/test/orm/test_joins.py +++ b/test/orm/test_joins.py @@ -226,8 +226,6 @@ class JoinTest(QueryTest, AssertsCompiledSQL): [ "relationship", "relationship_only", - "string_relationship", - "string_relationship_only", "none", "explicit", "table_none", @@ -235,11 +233,6 @@ class JoinTest(QueryTest, AssertsCompiledSQL): ], [True, False], ) - ).difference( - [ - ("string_relationship", False), - ("string_relationship_only", False), - ] ), argnames="onclause_type, use_legacy", ) @@ -256,12 +249,8 @@ class JoinTest(QueryTest, AssertsCompiledSQL): if onclause_type == "relationship": q = q.join(Address, User.addresses) - elif onclause_type == "string_relationship": - q = q.join(Address, "addresses") elif onclause_type == "relationship_only": q = q.join(User.addresses) - elif onclause_type == "string_relationship_only": - q = q.join("addresses") elif onclause_type == "none": q = q.join(Address) elif onclause_type == "explicit": diff --git a/test/orm/test_lazy_relations.py b/test/orm/test_lazy_relations.py index 457cfee4e2..2bea9b1106 100644 --- a/test/orm/test_lazy_relations.py +++ b/test/orm/test_lazy_relations.py @@ -658,14 +658,14 @@ class LazyTest(_fixtures.FixtureTest): [Order(id=1), Order(id=5)], fixture_session() .query(closed_mapper) - .with_parent(user, property="closed_orders") + .with_parent(user, property=User.closed_orders) .all(), ) eq_( [Order(id=3)], fixture_session() .query(open_mapper) - .with_parent(user, property="open_orders") + .with_parent(user, property=User.open_orders) .all(), ) @@ -720,7 +720,7 @@ class LazyTest(_fixtures.FixtureTest): eq_( self.static.item_keyword_result[0:2], - q.join("keywords").filter(keywords.c.name == "red").all(), + q.join(Item.keywords).filter(keywords.c.name == "red").all(), ) def test_uses_get(self): diff --git a/test/orm/test_mapper.py b/test/orm/test_mapper.py index 6c8b26c711..7d9e6f9c38 100644 --- a/test/orm/test_mapper.py +++ b/test/orm/test_mapper.py @@ -1498,7 +1498,7 @@ class MapperTest(_fixtures.FixtureTest, AssertsCompiledSQL): session = fixture_session() q = ( session.query(Item) - .join("keywords") + .join(Item.keywords) .distinct() .filter(Keyword.name == "red") ) @@ -2376,7 +2376,7 @@ class RequirementsTest(fixtures.MappedTest): h1.h2s.extend([H2("abc"), H2("def")]) s.flush() - h1s = s.query(H1).options(sa.orm.joinedload("h2s")).all() + h1s = s.query(H1).options(sa.orm.joinedload(H1.h2s)).all() eq_(len(h1s), 5) self.assert_unordered_result( @@ -2394,15 +2394,15 @@ class RequirementsTest(fixtures.MappedTest): {"h2s": (H2, [{"value": "def"}])}, ) - h1s = s.query(H1).options(sa.orm.joinedload("h3s")).all() + h1s = s.query(H1).options(sa.orm.joinedload(H1.h3s)).all() eq_(len(h1s), 5) h1s = ( s.query(H1) .options( - sa.orm.joinedload("t6a").joinedload("h1b"), - sa.orm.joinedload("h2s"), - sa.orm.joinedload("h3s").joinedload("h1s"), + sa.orm.joinedload(H1.t6a).joinedload(H6.h1b), + sa.orm.joinedload(H1.h2s), + sa.orm.joinedload(H1.h3s).joinedload(H3.h1s), ) .all() ) @@ -3151,13 +3151,13 @@ class ConfigureOrNotConfigureTest(_fixtures.FixtureTest, AssertsCompiledSQL): if use_bound: stmt = select(User).options( - Load(User).load_only("name"), + Load(User).load_only(User.name), ) is_true(um.configured) else: stmt = select(User).options( - load_only("name"), + load_only(User.name), ) is_false(um.configured) diff --git a/test/orm/test_merge.py b/test/orm/test_merge.py index 7d61a87222..3b97bd5a57 100644 --- a/test/orm/test_merge.py +++ b/test/orm/test_merge.py @@ -1211,7 +1211,9 @@ class MergeTest(_fixtures.FixtureTest): sess.commit() sess2 = fixture_session() - u2 = sess2.query(User).options(sa.orm.joinedload("addresses")).get(7) + u2 = ( + sess2.query(User).options(sa.orm.joinedload(User.addresses)).get(7) + ) sess3 = fixture_session() u3 = sess3.merge(u2, load=False) # noqa diff --git a/test/orm/test_of_type.py b/test/orm/test_of_type.py index bc32e322d4..bdf7ab8592 100644 --- a/test/orm/test_of_type.py +++ b/test/orm/test_of_type.py @@ -81,7 +81,8 @@ class _PolymorphicTestBase(object): sess = fixture_session() eq_( sess.query(Company) - .join(Company.employees.of_type(Engineer), "machines") + .join(Company.employees.of_type(Engineer)) + .join(Engineer.machines) .filter(Machine.name.ilike("%thinkpad%")) .all(), [self.c1], diff --git a/test/orm/test_options.py b/test/orm/test_options.py index ebbbe738de..1a2a5ba70f 100644 --- a/test/orm/test_options.py +++ b/test/orm/test_options.py @@ -509,15 +509,6 @@ class OptionsTest(PathTest, QueryTest): strategy_options._UnboundLoad.joinedload, arg, True, {} ) - def test_get_path_one_level_string(self): - User = self.classes.User - - sess = fixture_session() - q = sess.query(User) - - opt = self._option_fixture("addresses") - self._assert_path_result(opt, q, [(User, "addresses")]) - def test_get_path_one_level_attribute(self): User = self.classes.User @@ -545,33 +536,13 @@ class OptionsTest(PathTest, QueryTest): def test_get_path_one_level_with_unrelated(self): Order = self.classes.Order + User = self.classes.User sess = fixture_session() q = sess.query(Order) - opt = self._option_fixture("addresses") + opt = self._option_fixture(User.addresses) self._assert_path_result(opt, q, []) - def test_path_multilevel_string(self): - Item, User, Order = ( - self.classes.Item, - self.classes.User, - self.classes.Order, - ) - - sess = fixture_session() - q = sess.query(User) - - opt = self._option_fixture("orders.items.keywords") - self._assert_path_result( - opt, - q, - [ - (User, "orders"), - (User, "orders", Order, "items"), - (User, "orders", Order, "items", Item, "keywords"), - ], - ) - def test_path_multilevel_attribute(self): Item, User, Order = ( self.classes.Item, @@ -593,21 +564,6 @@ class OptionsTest(PathTest, QueryTest): ], ) - def test_with_current_matching_string(self): - Item, User, Order = ( - self.classes.Item, - self.classes.User, - self.classes.Order, - ) - - sess = fixture_session() - q = sess.query(Item)._with_current_path( - self._make_path_registry([User, "orders", Order, "items"]) - ) - - opt = self._option_fixture("orders.items.keywords") - self._assert_path_result(opt, q, [(Item, "keywords")]) - def test_with_current_matching_attribute(self): Item, User, Order = ( self.classes.Item, @@ -623,24 +579,6 @@ class OptionsTest(PathTest, QueryTest): opt = self._option_fixture(User.orders, Order.items, Item.keywords) self._assert_path_result(opt, q, [(Item, "keywords")]) - def test_with_current_nonmatching_string(self): - Item, User, Order = ( - self.classes.Item, - self.classes.User, - self.classes.Order, - ) - - sess = fixture_session() - q = sess.query(Item)._with_current_path( - self._make_path_registry([User, "orders", Order, "items"]) - ) - - opt = self._option_fixture("keywords") - self._assert_path_result(opt, q, []) - - opt = self._option_fixture("items.keywords") - self._assert_path_result(opt, q, []) - def test_with_current_nonmatching_attribute(self): Item, User, Order = ( self.classes.Item, @@ -923,14 +861,6 @@ class OptionsTest(PathTest, QueryTest): q = sess.query(Item, Order) self._assert_path_result(opt, q, [(Order, "items")]) - def test_multi_entity_opt_on_string(self): - Item = self.classes.Item - Order = self.classes.Order - opt = self._option_fixture("items") - sess = fixture_session() - q = sess.query(Item, Order) - self._assert_path_result(opt, q, []) - def test_multi_entity_no_mapped_entities(self): Item = self.classes.Item Order = self.classes.Order @@ -955,28 +885,11 @@ class OptionsTest(PathTest, QueryTest): Order = self.classes.Order sess = fixture_session() q = sess.query(User) - opt = self._option_fixture(User.orders).joinedload("items") + opt = self._option_fixture(User.orders).joinedload(Order.items) self._assert_path_result( opt, q, [(User, "orders"), (User, "orders", Order, "items")] ) - def test_chained_plus_dotted(self): - User = self.classes.User - Order = self.classes.Order - Item = self.classes.Item - sess = fixture_session() - q = sess.query(User) - opt = self._option_fixture("orders.items").joinedload("keywords") - self._assert_path_result( - opt, - q, - [ - (User, "orders"), - (User, "orders", Order, "items"), - (User, "orders", Order, "items", Item, "keywords"), - ], - ) - def test_chained_plus_multi(self): User = self.classes.User Order = self.classes.Order @@ -984,7 +897,7 @@ class OptionsTest(PathTest, QueryTest): sess = fixture_session() q = sess.query(User) opt = self._option_fixture(User.orders, Order.items).joinedload( - "keywords" + Item.keywords ) self._assert_path_result( opt, @@ -1055,47 +968,21 @@ class OptionsNoPropTest(_fixtures.FixtureTest): run_inserts = None run_deletes = None - def test_option_with_mapper_basestring(self): - Item = self.classes.Item - - self._assert_option([Item], "keywords") - def test_option_with_mapper_PropCompatator(self): Item = self.classes.Item self._assert_option([Item], Item.keywords) - def test_option_with_mapper_then_column_basestring(self): - Item = self.classes.Item - - self._assert_option([Item, Item.id], "keywords") - def test_option_with_mapper_then_column_PropComparator(self): Item = self.classes.Item self._assert_option([Item, Item.id], Item.keywords) - def test_option_with_column_then_mapper_basestring(self): - Item = self.classes.Item - - self._assert_option([Item.id, Item], "keywords") - def test_option_with_column_then_mapper_PropComparator(self): Item = self.classes.Item self._assert_option([Item.id, Item], Item.keywords) - def test_option_with_column_basestring(self): - Item = self.classes.Item - - message = ( - "Query has only expression-based entities - can't " - 'find property named "keywords".' - ) - self._assert_eager_with_just_column_exception( - Item.id, "keywords", message - ) - def test_option_with_column_PropComparator(self): Item = self.classes.Item @@ -1118,81 +1005,6 @@ class OptionsNoPropTest(_fixtures.FixtureTest): "the root entities to the target attribute. ", ) - def test_option_against_nonexistent_basestring(self): - Item = self.classes.Item - self._assert_eager_with_entity_exception( - [Item], - (joinedload("foo"),), - 'Can\'t find property named "foo" on mapped class ' - "Item->items in this Query.", - ) - - def test_option_against_nonexistent_twolevel_basestring(self): - Item = self.classes.Item - self._assert_eager_with_entity_exception( - [Item], - (joinedload("keywords.foo"),), - 'Can\'t find property named "foo" on mapped class ' - "Keyword->keywords in this Query.", - ) - - def test_option_against_nonexistent_twolevel_chained(self): - Item = self.classes.Item - self._assert_eager_with_entity_exception( - [Item], - (joinedload("keywords").joinedload("foo"),), - 'Can\'t find property named "foo" on mapped class ' - "Keyword->keywords in this Query.", - ) - - @testing.fails_if( - lambda: True, - "PropertyOption doesn't yet check for relation/column on end result", - ) - def test_option_against_non_relation_basestring(self): - Item = self.classes.Item - Keyword = self.classes.Keyword - self._assert_eager_with_entity_exception( - [Keyword, Item], - (joinedload("keywords"),), - r"Attribute 'keywords' of entity 'Mapper\|Keyword\|keywords' " - "does not refer to a mapped entity", - ) - - @testing.fails_if( - lambda: True, - "PropertyOption doesn't yet check for relation/column on end result", - ) - def test_option_against_multi_non_relation_basestring(self): - Item = self.classes.Item - Keyword = self.classes.Keyword - self._assert_eager_with_entity_exception( - [Keyword, Item], - (joinedload("keywords"),), - r"Attribute 'keywords' of entity 'Mapper\|Keyword\|keywords' " - "does not refer to a mapped entity", - ) - - def test_option_against_wrong_entity_type_basestring(self): - Item = self.classes.Item - self._assert_loader_strategy_exception( - [Item], - (joinedload("id").joinedload("keywords"),), - 'Can\'t apply "joined loader" strategy to property "Item.id", ' - 'which is a "column property"; this loader strategy is ' - 'intended to be used with a "relationship property".', - ) - - def test_col_option_against_relationship_basestring(self): - Item = self.classes.Item - self._assert_loader_strategy_exception( - [Item], - (load_only("keywords"),), - 'Can\'t apply "column loader" strategy to property ' - '"Item.keywords", which is a "relationship property"; this ' - 'loader strategy is intended to be used with a "column property".', - ) - def test_load_only_against_multi_entity_attr(self): User = self.classes.User Item = self.classes.Item @@ -1217,37 +1029,6 @@ class OptionsNoPropTest(_fixtures.FixtureTest): 'loader strategy is intended to be used with a "column property".', ) - def test_option_against_multi_non_relation_twolevel_basestring(self): - Item = self.classes.Item - Keyword = self.classes.Keyword - self._assert_loader_strategy_exception( - [Keyword, Item], - (joinedload("id").joinedload("keywords"),), - 'Can\'t apply "joined loader" strategy to property "Keyword.id", ' - 'which is a "column property"; this loader strategy is intended ' - 'to be used with a "relationship property".', - ) - - def test_option_against_multi_nonexistent_basestring(self): - Item = self.classes.Item - Keyword = self.classes.Keyword - self._assert_eager_with_entity_exception( - [Keyword, Item], - (joinedload("description"),), - 'Can\'t find property named "description" on mapped class ' - "Keyword->keywords in this Query.", - ) - - def test_option_against_multi_no_entities_basestring(self): - Item = self.classes.Item - Keyword = self.classes.Keyword - self._assert_eager_with_entity_exception( - [Keyword.id, Item.id], - (joinedload("keywords"),), - r"Query has only expression-based entities - can't find property " - 'named "keywords".', - ) - def test_option_against_wrong_multi_entity_type_attr_one(self): Item = self.classes.Item Keyword = self.classes.Keyword @@ -1467,22 +1248,6 @@ class OptionsNoPropTestInh(_Polymorphic): ._compile_state, ) - def test_missing_str_attr_of_type_subclass(self): - s = fixture_session() - - assert_raises_message( - sa.exc.ArgumentError, - r'Can\'t find property named "manager_name" on ' - r"mapped class Engineer->engineers in this Query.$", - s.query(Company) - .options( - joinedload(Company.employees.of_type(Engineer)).load_only( - "manager_name" - ) - ) - ._compile_state, - ) - def test_missing_attr_of_type_wpoly_subclass(self): s = fixture_session() @@ -1883,35 +1648,6 @@ class SubOptionsTest(PathTest, QueryTest): sess = fixture_session() self._assert_opts(sess.query(User), sub_opt, non_sub_opts) - def test_four_strings(self): - User, Address, Order, Item, SubItem, Keyword = self.classes( - "User", "Address", "Order", "Item", "SubItem", "Keyword" - ) - sub_opt = joinedload("orders").options( - defer("description"), - joinedload("items").options( - joinedload("keywords").options(defer("name")), - defer("description"), - ), - ) - non_sub_opts = [ - joinedload(User.orders), - defaultload(User.orders).defer(Order.description), - defaultload(User.orders).joinedload(Order.items), - defaultload(User.orders) - .defaultload(Order.items) - .joinedload(Item.keywords), - defaultload(User.orders) - .defaultload(Order.items) - .defer(Item.description), - defaultload(User.orders) - .defaultload(Order.items) - .defaultload(Item.keywords) - .defer(Keyword.name), - ] - sess = fixture_session() - self._assert_opts(sess.query(User), sub_opt, non_sub_opts) - def test_five(self): User, Address, Order, Item, SubItem, Keyword = self.classes( "User", "Address", "Order", "Item", "SubItem", "Keyword" @@ -1924,18 +1660,6 @@ class SubOptionsTest(PathTest, QueryTest): sess = fixture_session() self._assert_opts(sess.query(User), sub_opt, non_sub_opts) - def test_five_strings(self): - User, Address, Order, Item, SubItem, Keyword = self.classes( - "User", "Address", "Order", "Item", "SubItem", "Keyword" - ) - sub_opt = joinedload("orders").options(load_only("description")) - non_sub_opts = [ - joinedload(User.orders), - defaultload(User.orders).load_only(Order.description), - ] - sess = fixture_session() - self._assert_opts(sess.query(User), sub_opt, non_sub_opts) - def test_invalid_one(self): User, Address, Order, Item, SubItem = self.classes( "User", "Address", "Order", "Item", "SubItem" @@ -1956,26 +1680,6 @@ class SubOptionsTest(PathTest, QueryTest): sess = fixture_session() self._assert_opts(sess.query(User), sub_opt, non_sub_opts) - def test_invalid_two(self): - User, Address, Order, Item, SubItem = self.classes( - "User", "Address", "Order", "Item", "SubItem" - ) - - # these options are "invalid", in that User.orders -> Item.keywords - # is not a path. However, the "normal" option is not generating - # an error for now, which is bad, but we're testing here only that - # it works the same way, so there you go. If and when we make this - # case raise, then both cases should raise in the same way. - sub_opt = joinedload("orders").options( - joinedload("keywords"), joinedload("items") - ) - non_sub_opts = [ - joinedload(User.orders).joinedload(Item.keywords), - defaultload(User.orders).joinedload(Order.items), - ] - sess = fixture_session() - self._assert_opts(sess.query(User), sub_opt, non_sub_opts) - def test_not_implemented_fromload(self): User, Address, Order, Item, SubItem = self.classes( "User", "Address", "Order", "Item", "SubItem" @@ -2030,7 +1734,7 @@ class MapperOptionsTest(_fixtures.FixtureTest): u = ( sess.query(User) .order_by(User.id) - .options(sa.orm.joinedload("adlist")) + .options(sa.orm.joinedload(User.adlist)) .filter_by(name="jack") ).one() eq_(u.adlist, [self.static.user_address_result[0].addresses[0]]) diff --git a/test/orm/test_pickled.py b/test/orm/test_pickled.py index e33ec9a5c5..e6f15c47b5 100644 --- a/test/orm/test_pickled.py +++ b/test/orm/test_pickled.py @@ -345,8 +345,10 @@ class PickleTest(fixtures.MappedTest): u1 = ( sess.query(User) .options( - sa.orm.defer("name"), - sa.orm.defer("addresses.email_address"), + sa.orm.defer(User.name), + sa.orm.defaultload(User.addresses).defer( + Address.email_address + ), ) .get(u1.id) ) @@ -496,13 +498,11 @@ class PickleTest(fixtures.MappedTest): @testing.requires.non_broken_pickle @testing.combinations( lambda User: sa.orm.joinedload(User.addresses), - lambda: sa.orm.joinedload("addresses"), - lambda: sa.orm.defer("name"), lambda User: sa.orm.defer(User.name), - lambda Address: sa.orm.joinedload("addresses").joinedload( + lambda Address: sa.orm.joinedload(User.addresses).joinedload( Address.dingaling ), - lambda: sa.orm.joinedload("addresses").raiseload("*"), + lambda: sa.orm.joinedload(User.addresses).raiseload("*"), lambda: sa.orm.raiseload("*"), ) def test_unbound_options(self, test_case): @@ -518,15 +518,15 @@ class PickleTest(fixtures.MappedTest): @testing.requires.non_broken_pickle @testing.combinations( lambda User: sa.orm.Load(User).joinedload(User.addresses), - lambda User: sa.orm.Load(User).joinedload("addresses"), - lambda User: sa.orm.Load(User).joinedload("addresses").raiseload("*"), - lambda User: sa.orm.Load(User).defer("name"), + lambda User: sa.orm.Load(User) + .joinedload(User.addresses) + .raiseload("*"), lambda User: sa.orm.Load(User).defer(User.name), lambda User, Address: sa.orm.Load(User) - .joinedload("addresses") + .joinedload(User.addresses) .joinedload(Address.dingaling), lambda User, Address: sa.orm.Load(User) - .joinedload("addresses", innerjoin=True) + .joinedload(User.addresses, innerjoin=True) .joinedload(Address.dingaling), ) def test_bound_options(self, test_case): @@ -548,10 +548,8 @@ class PickleTest(fixtures.MappedTest): for opt in [ sa.orm.joinedload(User.addresses), - sa.orm.joinedload("addresses"), - sa.orm.defer("name"), sa.orm.defer(User.name), - sa.orm.joinedload("addresses").joinedload(Address.dingaling), + sa.orm.joinedload(User.addresses).joinedload(Address.dingaling), ]: context = sess.query(User).options(opt)._compile_context() opt = [ diff --git a/test/orm/test_query.py b/test/orm/test_query.py index 3e58f211c4..c9353f5511 100644 --- a/test/orm/test_query.py +++ b/test/orm/test_query.py @@ -1340,7 +1340,7 @@ class GetTest(QueryTest): s = fixture_session() - q = s.query(User).join("addresses").filter(Address.user_id == 8) + q = s.query(User).join(User.addresses).filter(Address.user_id == 8) assert_raises(sa_exc.InvalidRequestError, q.get, 7) assert_raises( sa_exc.InvalidRequestError, @@ -1361,7 +1361,7 @@ class GetTest(QueryTest): s.query(User).get(7) - q = s.query(User).join("addresses").filter(Address.user_id == 8) + q = s.query(User).join(User.addresses).filter(Address.user_id == 8) assert_raises(sa_exc.InvalidRequestError, q.get, 7) def test_unique_param_names(self): @@ -1428,6 +1428,7 @@ class GetTest(QueryTest): def test_populate_existing(self): User, Address = self.classes.User, self.classes.Address + Order = self.classes.Order s = fixture_session(autoflush=False) @@ -1457,13 +1458,15 @@ class GetTest(QueryTest): # eager load does s.query(User).options( - joinedload("addresses"), joinedload("orders").joinedload("items") + joinedload(User.addresses), + joinedload(User.orders).joinedload(Order.items), ).populate_existing().all() assert u.addresses[0].email_address == "jack@bean.com" assert u.orders[1].items[2].description == "item 5" def test_populate_existing_future(self): User, Address = self.classes.User, self.classes.Address + Order = self.classes.Order s = fixture_session(autoflush=False) @@ -1500,8 +1503,8 @@ class GetTest(QueryTest): stmt = ( select(User) .options( - joinedload("addresses"), - joinedload("orders").joinedload("items"), + joinedload(User.addresses), + joinedload(User.orders).joinedload(Order.items), ) .execution_options(populate_existing=True) ) @@ -1545,7 +1548,7 @@ class InvalidGenerationsTest(QueryTest, AssertsCompiledSQL): q = testing.resolve_lambda(test_case, User=User, s=s) - assert_raises(sa_exc.InvalidRequestError, q.join, "addresses") + assert_raises(sa_exc.InvalidRequestError, q.join, User.addresses) assert_raises(sa_exc.InvalidRequestError, q.filter, User.name == "ed") @@ -1557,7 +1560,7 @@ class InvalidGenerationsTest(QueryTest, AssertsCompiledSQL): assert_raises(sa_exc.InvalidRequestError, q.having, "foo") - q.enable_assertions(False).join("addresses") + q.enable_assertions(False).join(User.addresses) q.enable_assertions(False).filter(User.name == "ed") q.enable_assertions(False).order_by("foo") q.enable_assertions(False).group_by("foo") @@ -1570,7 +1573,7 @@ class InvalidGenerationsTest(QueryTest, AssertsCompiledSQL): q = s.query(User).select_from(users) assert_raises(sa_exc.InvalidRequestError, q.select_from, users) - q = s.query(User).join("addresses") + q = s.query(User).join(User.addresses) assert_raises(sa_exc.InvalidRequestError, q.select_from, users) q = s.query(User).order_by(User.id) @@ -3360,13 +3363,13 @@ class FilterTest(QueryTest, AssertsCompiledSQL): # test that the contents are not adapted by the aliased join ua = aliased(Address) assert [User(id=7), User(id=8)] == sess.query(User).join( - ua, "addresses" + ua, User.addresses ).filter( ~User.addresses.any(Address.email_address == "fred@fred.com") ).all() assert [User(id=10)] == sess.query(User).outerjoin( - ua, "addresses" + ua, User.addresses ).filter(~User.addresses.any()).all() def test_any_doesnt_overcorrelate(self): @@ -3378,7 +3381,7 @@ class FilterTest(QueryTest, AssertsCompiledSQL): # test that any() doesn't overcorrelate assert [User(id=7), User(id=8)] == sess.query(User).join( - "addresses" + User.addresses ).filter( ~User.addresses.any(Address.email_address == "fred@fred.com") ).all() @@ -3417,7 +3420,7 @@ class FilterTest(QueryTest, AssertsCompiledSQL): # test has() doesn't overcorrelate assert [Address(id=2), Address(id=3), Address(id=4)] == sess.query( Address - ).join("user").filter( + ).join(Address.user).filter( Address.user.has(User.name.like("%ed%"), id=8) ).order_by( Address.id @@ -3427,7 +3430,7 @@ class FilterTest(QueryTest, AssertsCompiledSQL): ua = aliased(User) assert [Address(id=2), Address(id=3), Address(id=4)] == sess.query( Address - ).join(ua, "user").filter( + ).join(ua, Address.user).filter( Address.user.has(User.name.like("%ed%"), id=8) ).order_by( Address.id @@ -4409,7 +4412,7 @@ class AggregateTest(QueryTest): sess = fixture_session() assert [User(name="ed", id=8)] == sess.query(User).order_by( User.id - ).group_by(User).join("addresses").having( + ).group_by(User).join(User.addresses).having( func.count(Address.id) > 2 ).all() @@ -4417,7 +4420,7 @@ class AggregateTest(QueryTest): User(name="jack", id=7), User(name="fred", id=9), ] == sess.query(User).order_by(User.id).group_by(User).join( - "addresses" + User.addresses ).having( func.count(Address.id) < 2 ).all() @@ -4828,7 +4831,7 @@ class DistinctTest(QueryTest, AssertsCompiledSQL): subq = ( sess.query(User, Address.email_address) - .join("addresses") + .join(User.addresses) .distinct() .subquery() ) @@ -4850,7 +4853,7 @@ class DistinctTest(QueryTest, AssertsCompiledSQL): sess = fixture_session() q = ( sess.query(User, Address.email_address) - .join("addresses") + .join(User.addresses) .distinct() ) @@ -4875,9 +4878,9 @@ class DistinctTest(QueryTest, AssertsCompiledSQL): # test that it works on embedded joinedload/LIMIT subquery q = ( sess.query(User) - .join("addresses") + .join(User.addresses) .distinct() - .options(joinedload("addresses")) + .options(joinedload(User.addresses)) .order_by(desc(Address.email_address)) .limit(2) ) @@ -5227,9 +5230,9 @@ class DistinctTest(QueryTest, AssertsCompiledSQL): q = ( sess.query(User) - .join("addresses") + .join(User.addresses) .distinct(Address.email_address) - .options(joinedload("addresses")) + .options(joinedload(User.addresses)) .order_by(desc(Address.email_address)) .limit(2) ) @@ -5407,7 +5410,7 @@ class YieldTest(_fixtures.FixtureTest): User = self.classes.User sess = fixture_session() - q = sess.query(User).options(joinedload("addresses")).yield_per(1) + q = sess.query(User).options(joinedload(User.addresses)).yield_per(1) assert_raises_message( sa_exc.InvalidRequestError, "Can't use yield_per with eager loaders that require " @@ -5420,7 +5423,7 @@ class YieldTest(_fixtures.FixtureTest): User = self.classes.User sess = fixture_session() - q = sess.query(User).options(subqueryload("addresses")).yield_per(1) + q = sess.query(User).options(subqueryload(User.addresses)).yield_per(1) assert_raises_message( sa_exc.InvalidRequestError, "Can't use yield_per with eager loaders that require " @@ -5455,7 +5458,7 @@ class YieldTest(_fixtures.FixtureTest): sess = fixture_session() q = ( sess.query(User) - .options(subqueryload("addresses")) + .options(subqueryload(User.addresses)) .enable_eagerloads(False) .yield_per(1) ) @@ -5463,7 +5466,7 @@ class YieldTest(_fixtures.FixtureTest): q = ( sess.query(User) - .options(joinedload("addresses")) + .options(joinedload(User.addresses)) .enable_eagerloads(False) .yield_per(1) ) @@ -5475,7 +5478,7 @@ class YieldTest(_fixtures.FixtureTest): sess = fixture_session() q = ( sess.query(Address) - .options(lazyload("*"), joinedload("user")) + .options(lazyload("*"), joinedload(Address.user)) .yield_per(1) .filter_by(id=1) ) @@ -6154,7 +6157,7 @@ class TextTest(QueryTest, AssertsCompiledSQL): q = ( s.query(User) - .options(joinedload("addresses")) + .options(joinedload(User.addresses)) .order_by(desc("name")) .limit(1) ) @@ -6172,7 +6175,7 @@ class TextTest(QueryTest, AssertsCompiledSQL): q = ( s.query(User) - .options(joinedload("addresses")) + .options(joinedload(User.addresses)) .order_by("name") .limit(1) ) @@ -6190,7 +6193,7 @@ class TextTest(QueryTest, AssertsCompiledSQL): self.assert_compile( s.query(User) - .options(joinedload("addresses")) + .options(joinedload(User.addresses)) .order_by("users_name") .limit(1), "SELECT anon_1.users_id AS anon_1_users_id, " @@ -6209,7 +6212,7 @@ class TextTest(QueryTest, AssertsCompiledSQL): # however! this works (again?) eq_( s.query(User) - .options(joinedload("addresses")) + .options(joinedload(User.addresses)) .order_by("users_name") .first(), User(name="chuck", addresses=[]), @@ -6222,7 +6225,7 @@ class TextTest(QueryTest, AssertsCompiledSQL): self.assert_compile( s.query(User) - .options(joinedload("addresses")) + .options(joinedload(User.addresses)) .order_by(desc("users_name")) .limit(1), "SELECT anon_1.users_id AS anon_1_users_id, " @@ -6241,7 +6244,7 @@ class TextTest(QueryTest, AssertsCompiledSQL): # however! this works (again?) eq_( s.query(User) - .options(joinedload("addresses")) + .options(joinedload(User.addresses)) .order_by(desc("users_name")) .first(), User(name="jack", addresses=[Address()]), @@ -6260,7 +6263,7 @@ class TextTest(QueryTest, AssertsCompiledSQL): q = sess.query(User, Address.email_address.label("email_address")) result = ( - q.join("addresses") + q.join(User.addresses) .options(joinedload(User.orders)) .order_by("email_address desc") .limit(1) @@ -6330,13 +6333,6 @@ class ParentTest(QueryTest, AssertsCompiledSQL): ] == o # test with explicit property - o = sess.query(Order).with_parent(u1, property="orders").all() - assert [ - Order(description="order 1"), - Order(description="order 3"), - Order(description="order 5"), - ] == o - o = sess.query(Order).with_parent(u1, property=User.orders).all() assert [ Order(description="order 1"), @@ -6385,7 +6381,7 @@ class ParentTest(QueryTest, AssertsCompiledSQL): sess = fixture_session() u1 = sess.query(User).get(7) q = sess.query(User, Address).filter( - with_parent(u1, "addresses", from_entity=Address) + with_parent(u1, User.addresses, from_entity=Address) ) self.assert_compile( q, @@ -6404,7 +6400,7 @@ class ParentTest(QueryTest, AssertsCompiledSQL): sess = fixture_session() u1 = sess.query(User).get(7) q = sess.query(User, Address).with_parent( - u1, "addresses", from_entity=Address + u1, User.addresses, from_entity=Address ) self.assert_compile( q, @@ -6440,7 +6436,7 @@ class ParentTest(QueryTest, AssertsCompiledSQL): sess = fixture_session() u1 = sess.query(User).get(7) a1 = aliased(Address) - q = sess.query(a1).with_parent(u1, "addresses") + q = sess.query(a1).with_parent(u1, User.addresses) self.assert_compile( q, "SELECT addresses_1.id AS addresses_1_id, " @@ -6530,7 +6526,7 @@ class ParentTest(QueryTest, AssertsCompiledSQL): q = sess.query(User) u1 = q.filter_by(name="jack").one() utrans = User(id=u1.id) - o = sess.query(Order).with_parent(utrans, "orders") + o = sess.query(Order).with_parent(utrans, User.orders) eq_( [ Order(description="order 1"), @@ -6540,7 +6536,7 @@ class ParentTest(QueryTest, AssertsCompiledSQL): o.all(), ) - o = sess.query(Order).filter(with_parent(utrans, "orders")) + o = sess.query(Order).filter(with_parent(utrans, User.orders)) eq_( [ Order(description="order 1"), @@ -6559,11 +6555,11 @@ class ParentTest(QueryTest, AssertsCompiledSQL): opending = Order(id=20, user_id=o1.user_id) sess.add(opending) eq_( - sess.query(User).with_parent(opending, "user").one(), + sess.query(User).with_parent(opending, Order.user).one(), User(id=o1.user_id), ) eq_( - sess.query(User).filter(with_parent(opending, "user")).one(), + sess.query(User).filter(with_parent(opending, Order.user)).one(), User(id=o1.user_id), ) @@ -6576,7 +6572,7 @@ class ParentTest(QueryTest, AssertsCompiledSQL): opending = Order(user_id=o1.user_id) sess.add(opending) eq_( - sess.query(User).with_parent(opending, "user").one(), + sess.query(User).with_parent(opending, Order.user).one(), User(id=o1.user_id), ) @@ -6587,8 +6583,8 @@ class ParentTest(QueryTest, AssertsCompiledSQL): sess = fixture_session() u1, u2 = sess.query(User).order_by(User.id)[0:2] - q1 = sess.query(Address).with_parent(u1, "addresses") - q2 = sess.query(Address).with_parent(u2, "addresses") + q1 = sess.query(Address).with_parent(u1, User.addresses) + q2 = sess.query(Address).with_parent(u2, User.addresses) self.assert_compile( q1.union(q2), @@ -6614,7 +6610,10 @@ class ParentTest(QueryTest, AssertsCompiledSQL): self.assert_compile( sess.query(Address).filter( - or_(with_parent(u1, "addresses"), with_parent(u2, "addresses")) + or_( + with_parent(u1, User.addresses), + with_parent(u2, User.addresses), + ) ), "SELECT addresses.id AS addresses_id, addresses.user_id AS " "addresses_user_id, addresses.email_address AS " @@ -6832,7 +6831,7 @@ class WithTransientOnNone(_fixtures.FixtureTest, AssertsCompiledSQL): sess = fixture_session() - q = sess.query(User).with_parent(Address(user_id=None), "user") + q = sess.query(User).with_parent(Address(user_id=None), Address.user) with expect_warnings("Got None for value of column"): self.assert_compile( q, @@ -6847,7 +6846,7 @@ class WithTransientOnNone(_fixtures.FixtureTest, AssertsCompiledSQL): s = fixture_session() q = s.query(User).with_parent( - Address(user_id=None, email_address=None), "special_user" + Address(user_id=None, email_address=None), Address.special_user ) with expect_warnings("Got None for value of column"): @@ -7025,35 +7024,6 @@ class SynonymTest(QueryTest, AssertsCompiledSQL): self.assert_sql_count(testing.db, go, 1) - def test_options_syn_of_syn_string(self): - User, Order = self.classes.User, self.classes.Order - - s = fixture_session() - - def go(): - result = ( - s.query(User) - .filter_by(name="jack") - .options(joinedload("orders_syn_2")) - .all() - ) - eq_( - result, - [ - User( - id=7, - name="jack", - orders=[ - Order(description="order 1"), - Order(description="order 3"), - Order(description="order 5"), - ], - ) - ], - ) - - self.assert_sql_count(testing.db, go, 1) - def test_joins(self): User, Order = self.classes.User, self.classes.Order @@ -7084,12 +7054,12 @@ class SynonymTest(QueryTest, AssertsCompiledSQL): Order, User = self.classes.Order, self.classes.User for nameprop, orderprop in ( - ("name", "orders"), - ("name_syn", "orders"), - ("name", "orders_syn"), - ("name", "orders_syn_2"), - ("name_syn", "orders_syn"), - ("name_syn", "orders_syn_2"), + ("name", User.orders), + ("name_syn", User.orders), + ("name", User.orders_syn), + ("name", User.orders_syn_2), + ("name_syn", User.orders_syn), + ("name_syn", User.orders_syn_2), ): with fixture_session() as sess: q = sess.query(User) diff --git a/test/orm/test_relationships.py b/test/orm/test_relationships.py index a25e39c82b..2547a981a2 100644 --- a/test/orm/test_relationships.py +++ b/test/orm/test_relationships.py @@ -358,7 +358,7 @@ class M2ODontOverwriteFKTest(fixtures.MappedTest): sess.commit() # test that was broken by #3060 - a1 = sess.query(A).options(joinedload("b")).first() + a1 = sess.query(A).options(joinedload(A.b)).first() a1.bid = b1.id sess.flush() @@ -6081,7 +6081,11 @@ class RaiseLoadTest(_fixtures.FixtureTest): users, properties=dict(addresses=relationship(Address, lazy="raise")), ) - q = fixture_session().query(User).options(sa.orm.lazyload("addresses")) + q = ( + fixture_session() + .query(User) + .options(sa.orm.lazyload(User.addresses)) + ) result = [None] def go(): @@ -6110,7 +6114,7 @@ class RaiseLoadTest(_fixtures.FixtureTest): a1 = ( s.query(Address) .filter_by(id=1) - .options(sa.orm.raiseload("user")) + .options(sa.orm.raiseload(Address.user)) .first() ) @@ -6138,7 +6142,7 @@ class RaiseLoadTest(_fixtures.FixtureTest): a1 = ( s.query(Address) .filter_by(id=1) - .options(sa.orm.raiseload("user", sql_only=True)) + .options(sa.orm.raiseload(Address.user, sql_only=True)) .first() ) @@ -6157,7 +6161,7 @@ class RaiseLoadTest(_fixtures.FixtureTest): a1 = ( s.query(Address) .filter_by(id=1) - .options(sa.orm.raiseload("user", sql_only=True)) + .options(sa.orm.raiseload(Address.user, sql_only=True)) .first() ) assert "user" not in a1.__dict__ @@ -6189,7 +6193,7 @@ class RaiseLoadTest(_fixtures.FixtureTest): a1 = ( s.query(Address) .filter_by(id=1) - .options(sa.orm.raiseload("user", sql_only=True)) + .options(sa.orm.raiseload(Address.user, sql_only=True)) .first() ) diff --git a/test/orm/test_selectin_relations.py b/test/orm/test_selectin_relations.py index ceaead9c43..e3d852e682 100644 --- a/test/orm/test_selectin_relations.py +++ b/test/orm/test_selectin_relations.py @@ -352,7 +352,7 @@ class EagerTest(_fixtures.FixtureTest, testing.AssertsCompiledSQL): def go(): eq_( self.static.item_keyword_result[0:2], - q.join("keywords").filter(Keyword.name == "red").all(), + q.join(Item.keywords).filter(Keyword.name == "red").all(), ) self.assert_sql_count(testing.db, go, 2) @@ -386,7 +386,7 @@ class EagerTest(_fixtures.FixtureTest, testing.AssertsCompiledSQL): ka = aliased(Keyword) eq_( self.static.item_keyword_result[0:2], - (q.join(ka, "keywords").filter(ka.name == "red")).all(), + (q.join(ka, Item.keywords).filter(ka.name == "red")).all(), ) self.assert_sql_count(testing.db, go, 2) @@ -1571,7 +1571,7 @@ class LoadOnExistingTest(_fixtures.FixtureTest): a2 = u1.addresses[0] a2.email_address = "foo" sess.query(User).options( - selectinload("addresses").selectinload("dingaling") + selectinload(User.addresses).selectinload(Address.dingaling) ).filter_by(id=8).all() assert u1.addresses[-1] is a1 for a in u1.addresses: @@ -1590,7 +1590,7 @@ class LoadOnExistingTest(_fixtures.FixtureTest): o1 = Order() u1.orders.append(o1) sess.query(User).options( - selectinload("orders").selectinload("items") + selectinload(User.orders).selectinload(Order.items) ).filter_by(id=7).all() for o in u1.orders: if o is not o1: @@ -1604,11 +1604,11 @@ class LoadOnExistingTest(_fixtures.FixtureTest): u1 = ( sess.query(User) .filter_by(id=8) - .options(selectinload("addresses")) + .options(selectinload(User.addresses)) .one() ) sess.query(User).filter_by(id=8).options( - selectinload("addresses").selectinload("dingaling") + selectinload(User.addresses).selectinload(Address.dingaling) ).first() assert "dingaling" in u1.addresses[0].__dict__ @@ -1618,11 +1618,11 @@ class LoadOnExistingTest(_fixtures.FixtureTest): u1 = ( sess.query(User) .filter_by(id=7) - .options(selectinload("orders")) + .options(selectinload(User.orders)) .one() ) sess.query(User).filter_by(id=7).options( - selectinload("orders").selectinload("items") + selectinload(User.orders).selectinload(Order.items) ).first() assert "items" in u1.orders[0].__dict__ @@ -2784,7 +2784,7 @@ class SelfReferentialTest(fixtures.MappedTest): eq_( Node(data="n1", children=[Node(data="n11"), Node(data="n12")]), sess.query(Node) - .options(undefer("data")) + .options(undefer(Node.data)) .order_by(Node.id) .first(), ) @@ -2797,7 +2797,10 @@ class SelfReferentialTest(fixtures.MappedTest): eq_( Node(data="n1", children=[Node(data="n11"), Node(data="n12")]), sess.query(Node) - .options(undefer("data"), undefer("children.data")) + .options( + undefer(Node.data), + defaultload(Node.children).undefer(Node.data), + ) .first(), ) @@ -2832,7 +2835,9 @@ class SelfReferentialTest(fixtures.MappedTest): sess.query(Node) .filter_by(data="n1") .order_by(Node.id) - .options(selectinload("children").selectinload("children")) + .options( + selectinload(Node.children).selectinload(Node.children) + ) .first() ) eq_( diff --git a/test/orm/test_subquery_relations.py b/test/orm/test_subquery_relations.py index 70d8d19bd5..25ebb9ebe4 100644 --- a/test/orm/test_subquery_relations.py +++ b/test/orm/test_subquery_relations.py @@ -10,6 +10,7 @@ from sqlalchemy.orm import aliased from sqlalchemy.orm import backref from sqlalchemy.orm import clear_mappers from sqlalchemy.orm import close_all_sessions +from sqlalchemy.orm import defaultload from sqlalchemy.orm import defer from sqlalchemy.orm import deferred from sqlalchemy.orm import joinedload @@ -443,7 +444,7 @@ class EagerTest(_fixtures.FixtureTest, testing.AssertsCompiledSQL): def go(): eq_( self.static.item_keyword_result[0:2], - q.join("keywords").filter(Keyword.name == "red").all(), + q.join(Item.keywords).filter(Keyword.name == "red").all(), ) self.assert_sql_count(testing.db, go, 2) @@ -477,7 +478,7 @@ class EagerTest(_fixtures.FixtureTest, testing.AssertsCompiledSQL): ka = aliased(Keyword) eq_( self.static.item_keyword_result[0:2], - (q.join(ka, "keywords").filter(ka.name == "red")).all(), + (q.join(ka, Item.keywords).filter(ka.name == "red")).all(), ) self.assert_sql_count(testing.db, go, 2) @@ -1598,7 +1599,7 @@ class LoadOnExistingTest(_fixtures.FixtureTest): a2 = u1.addresses[0] a2.email_address = "foo" sess.query(User).options( - subqueryload("addresses").subqueryload("dingaling") + subqueryload(User.addresses).subqueryload(Address.dingaling) ).filter_by(id=8).all() assert u1.addresses[-1] is a1 for a in u1.addresses: @@ -1617,7 +1618,7 @@ class LoadOnExistingTest(_fixtures.FixtureTest): o1 = Order() u1.orders.append(o1) sess.query(User).options( - subqueryload("orders").subqueryload("items") + subqueryload(User.orders).subqueryload(Order.items) ).filter_by(id=7).all() for o in u1.orders: if o is not o1: @@ -1631,11 +1632,11 @@ class LoadOnExistingTest(_fixtures.FixtureTest): u1 = ( sess.query(User) .filter_by(id=8) - .options(subqueryload("addresses")) + .options(subqueryload(User.addresses)) .one() ) sess.query(User).filter_by(id=8).options( - subqueryload("addresses").subqueryload("dingaling") + subqueryload(User.addresses).subqueryload(Address.dingaling) ).first() assert "dingaling" in u1.addresses[0].__dict__ @@ -1645,11 +1646,11 @@ class LoadOnExistingTest(_fixtures.FixtureTest): u1 = ( sess.query(User) .filter_by(id=7) - .options(subqueryload("orders")) + .options(subqueryload(User.orders)) .one() ) sess.query(User).filter_by(id=7).options( - subqueryload("orders").subqueryload("items") + subqueryload(User.orders).subqueryload(Order.items) ).first() assert "items" in u1.orders[0].__dict__ @@ -2536,7 +2537,7 @@ class SelfReferentialTest(fixtures.MappedTest): eq_( Node(data="n1", children=[Node(data="n11"), Node(data="n12")]), sess.query(Node) - .options(undefer("data")) + .options(undefer(Node.data)) .order_by(Node.id) .first(), ) @@ -2549,7 +2550,10 @@ class SelfReferentialTest(fixtures.MappedTest): eq_( Node(data="n1", children=[Node(data="n11"), Node(data="n12")]), sess.query(Node) - .options(undefer("data"), undefer("children.data")) + .options( + undefer(Node.data), + defaultload(Node.children).undefer(Node.data), + ) .first(), ) @@ -2584,7 +2588,9 @@ class SelfReferentialTest(fixtures.MappedTest): sess.query(Node) .filter_by(data="n1") .order_by(Node.id) - .options(subqueryload("children").subqueryload("children")) + .options( + subqueryload(Node.children).subqueryload(Node.children) + ) .first() ) eq_( @@ -3189,7 +3195,9 @@ class JoinedNoLoadConflictTest(fixtures.DeclarativeMappedTest): # Parent->subqueryload->Child->joinedload->parent->noload->children. # the actual subqueryload has to emit *after* we've started populating # Parent->subqueryload->child. - parent = s.query(Parent).options([subqueryload("children")]).first() + parent = ( + s.query(Parent).options([subqueryload(Parent.children)]).first() + ) eq_(parent.children, [Child(name="c1")]) diff --git a/test/orm/test_unitofwork.py b/test/orm/test_unitofwork.py index afba9d9532..d95565cd40 100644 --- a/test/orm/test_unitofwork.py +++ b/test/orm/test_unitofwork.py @@ -234,7 +234,7 @@ class UnicodeSchemaTest(fixtures.MappedTest): new_a1 = ( session.query(A) - .options(sa.orm.joinedload("t2s")) + .options(sa.orm.joinedload(A.t2s)) .filter(t1.c.a == a1.a) ).one() assert new_a1.a == a1.a -- 2.47.3