]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
Fixes: #4390
authorjonathan vanasco <jonathan@2xlp.com>
Mon, 27 Sep 2021 16:51:32 +0000 (12:51 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Mon, 8 Nov 2021 18:25:51 +0000 (13:25 -0500)
Deprecated an undocumented loader option syntax ``".*"``, which appears to
be no different than passing a single asterisk, and will emit a deprecation
warning if used. This syntax may have been intended for something but there
is currently no need for it.

The original ticket was to document the `.{WILDCARD}` (e.g. `.*`) format,
however this format does not appear to be used or needed by SQLAlchemy
and is likely not used by any projects or developers.

This PR invokes `util.warn_deprecated` to notify users this functionality
is deprecated, and directs them to the #4390 issue if they actually use it.

Assuming there are no complaints over this warning in the coming months,
this code can be removed in a future major release.

Change-Id: I665e3ac26be0a7819246a2ee56fb5a5f32980c91

doc/build/changelog/unreleased_14/4390.rst [new file with mode: 0644]
lib/sqlalchemy/orm/strategy_options.py
test/orm/test_default_strategies.py
test/orm/test_deferred.py
test/orm/test_deprecations.py

diff --git a/doc/build/changelog/unreleased_14/4390.rst b/doc/build/changelog/unreleased_14/4390.rst
new file mode 100644 (file)
index 0000000..abbc664
--- /dev/null
@@ -0,0 +1,9 @@
+.. change::
+    :tags: deprecated, orm
+    :tickets: 4390
+
+    Deprecated an undocumented loader option syntax ``".*"``, which appears to
+    be no different than passing a single asterisk, and will emit a deprecation
+    warning if used. This syntax may have been intended for something but there
+    is currently no need for it.
+
index 675c7218bd64cdc21380cc5876b78a63fa30b9af..30286c1d809fcc0d2df2100687aad266029e333c 100644 (file)
@@ -919,6 +919,15 @@ class _UnboundLoad(Load):
                     return (_DEFAULT_TOKEN,)
                 # coerce fooload(".*") into "wildcard on default entity"
                 elif key.startswith("." + _WILDCARD_TOKEN):
+                    util.warn_deprecated(
+                        "The undocumented `.{WILDCARD}` format is deprecated "
+                        "and will be removed in a future version as it is "
+                        "believed to be unused. "
+                        "If you have been using this functionality, please "
+                        "comment on Issue #4390 on the SQLAlchemy project "
+                        "tracker.",
+                        version="1.4",
+                    )
                     key = key[1:]
                 return key.split(".")
             else:
index 9b228bbaa2540ff9a98cc1cf13d63ecacb92123a..9162d63ecda31ea725132aabd70fafbc0ce8952e 100644 (file)
@@ -437,7 +437,7 @@ class DefaultStrategyOptionsTest(_fixtures.FixtureTest):
         def go():
             users[:] = (
                 sess.query(User)
-                .options(joinedload(".*"))
+                .options(joinedload("*"))
                 .options(defaultload(User.addresses).joinedload("*"))
                 .options(defaultload(User.orders).joinedload("*"))
                 .options(
@@ -548,7 +548,7 @@ class DefaultStrategyOptionsTest(_fixtures.FixtureTest):
         def go():
             users[:] = (
                 sess.query(User)
-                .options(subqueryload(".*"))
+                .options(subqueryload("*"))
                 .options(defaultload(User.addresses).subqueryload("*"))
                 .options(defaultload(User.orders).subqueryload("*"))
                 .options(
index bfdfb00b7fd12761f6746de447b0f1996f950ad2..41e9fa4dda3abf38abe4a29564142afa657d6214 100644 (file)
@@ -1563,14 +1563,11 @@ class InheritanceTest(_Polymorphic):
     def test_defer_on_wildcard_subclass(self):
         # pretty much the same as load_only except doesn't
         # exclude the primary key
-
-        # TODO: what is ".*"?  this is not documented anywhere, how did this
-        # get implemented without docs ?  see #4390
         s = fixture_session()
         q = (
             s.query(Manager)
             .order_by(Person.person_id)
-            .options(defer(".*"), undefer(Manager.status))
+            .options(defer("*"), undefer(Manager.status))
         )
         self.assert_compile(
             q,
index 061cad7e3b7260d43cc8a86a1005c4748d1200dd..3928b9051292f2d648739dc27cb91755fc635194 100644 (file)
@@ -88,8 +88,14 @@ from .inheritance import _poly_fixtures
 from .inheritance._poly_fixtures import _Polymorphic
 from .inheritance._poly_fixtures import Company
 from .inheritance._poly_fixtures import Engineer
+from .inheritance._poly_fixtures import Manager
+from .inheritance._poly_fixtures import Person
 from .test_ac_relationships import PartitionByFixture
 from .test_bind import GetBindTest as _GetBindTest
+from .test_default_strategies import (
+    DefaultStrategyOptionsTest as _DefaultStrategyOptionsTest,
+)
+from .test_deferred import InheritanceTest as _deferred_InheritanceTest
 from .test_dynamic import _DynamicFixture
 from .test_events import _RemoveListeners
 from .test_options import PathTest as OptionsPathTest
@@ -155,6 +161,13 @@ merge_result_dep = (
     r"The merge_result\(\) function is considered legacy as of the 1.x series"
 )
 
+dep_exc_wildcard = (
+    r"The undocumented `.{WILDCARD}` format is deprecated and will be removed "
+    r"in a future version as it is believed to be unused. If you have been "
+    r"using this functionality, please comment on Issue #4390 on the "
+    r"SQLAlchemy project tracker."
+)
+
 
 def _aliased_join_warning(arg=None):
     return testing.expect_warnings(
@@ -8696,3 +8709,83 @@ class MergeResultTest(_fixtures.FixtureTest):
             [(x and x.id or None, y and y.id or None) for x, y in it],
             [(u1.id, u2.id), (u1.id, None), (u2.id, u3.id)],
         )
+
+
+class DefaultStrategyOptionsTest(_DefaultStrategyOptionsTest):
+    def test_joined_path_wildcards(self):
+        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(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()
+            )
+
+        with assertions.expect_deprecated(dep_exc_wildcard):
+            self.assert_sql_count(testing.db, go, 1)
+            self._assert_fully_loaded(users)
+
+    def test_subquery_path_wildcards(self):
+        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(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()
+            )
+
+        with assertions.expect_deprecated(dep_exc_wildcard):
+            self.assert_sql_count(testing.db, go, 5)
+
+            # verify everything loaded, with no additional sql needed
+            self._assert_fully_loaded(users)
+
+
+class Deferred_InheritanceTest(_deferred_InheritanceTest):
+    def test_defer_on_wildcard_subclass(self):
+        # pretty much the same as load_only except doesn't
+        # exclude the primary key
+
+        # what is ".*"?  this is not documented anywhere, how did this
+        # get implemented without docs ?  see #4390
+        s = fixture_session()
+        with assertions.expect_deprecated(dep_exc_wildcard):
+            q = (
+                s.query(Manager)
+                .order_by(Person.person_id)
+                .options(defer(".*"), undefer(Manager.status))
+            )
+        self.assert_compile(
+            q,
+            "SELECT managers.status AS managers_status "
+            "FROM people JOIN managers ON "
+            "people.person_id = managers.person_id ORDER BY people.person_id",
+        )
+        # note this doesn't apply to "bound" loaders since they don't seem
+        # to have this ".*" featue.