]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
Remove deprecated elements from selectable.py; remove lockmode
authorMike Bayer <mike_mp@zzzcomputing.com>
Sun, 2 Feb 2020 16:39:37 +0000 (11:39 -0500)
committerMike Bayer <mike_mp@zzzcomputing.com>
Mon, 23 Mar 2020 18:06:13 +0000 (14:06 -0400)
Removed autocommit and legacy "for update" / "lockmode" elements
from selectable.py / query.py.  lockmode was removed from
selectable in 693938dd6fb2f3ee3e031aed4c62355ac97f3ceb
however was not removed from the ORM.

Also removes the ignore_nonexistent_tables option on
join().

Change-Id: I0cfcf9e6a8d4ef6432c9e25ef75173b3b3f5fd87
Partially-fixes: #4643

lib/sqlalchemy/orm/query.py
lib/sqlalchemy/orm/session.py
lib/sqlalchemy/sql/elements.py
lib/sqlalchemy/sql/selectable.py
test/orm/test_deprecations.py
test/orm/test_session.py
test/orm/test_versioning.py
test/sql/test_deprecations.py

index 0da7d08a4aece64bc28e96f78fb9bb3a688f57ee..617bba315015d713f3caab39c9d185fb28806f15 100644 (file)
@@ -1621,39 +1621,6 @@ class Query(Generative):
         """
         self._execution_options = self._execution_options.union(kwargs)
 
-    @_generative
-    @util.deprecated(
-        "0.9",
-        "The :meth:`.Query.with_lockmode` method is deprecated and will "
-        "be removed in a future release.  Please refer to "
-        ":meth:`.Query.with_for_update`. ",
-    )
-    def with_lockmode(self, mode):
-        """Return a new :class:`.Query` object with the specified "locking mode",
-        which essentially refers to the ``FOR UPDATE`` clause.
-
-        :param mode: a string representing the desired locking mode.
-         Valid values are:
-
-         * ``None`` - translates to no lockmode
-
-         * ``'update'`` - translates to ``FOR UPDATE``
-           (standard SQL, supported by most dialects)
-
-         * ``'update_nowait'`` - translates to ``FOR UPDATE NOWAIT``
-           (supported by Oracle, PostgreSQL 8.1 upwards)
-
-         * ``'read'`` - translates to ``LOCK IN SHARE MODE`` (for MySQL),
-           and ``FOR SHARE`` (for PostgreSQL)
-
-        .. seealso::
-
-            :meth:`.Query.with_for_update` - improved API for
-            specifying the ``FOR UPDATE`` clause.
-
-        """
-        self._for_update_arg = LockmodeArg.parse_legacy_query(mode)
-
     @_generative
     def with_for_update(
         self,
@@ -1681,16 +1648,13 @@ class Query(Generative):
 
             SELECT users.id AS users_id FROM users FOR UPDATE OF users NOWAIT
 
-        .. versionadded:: 0.9.0 :meth:`.Query.with_for_update` supersedes
-           the :meth:`.Query.with_lockmode` method.
-
         .. seealso::
 
             :meth:`.GenerativeSelect.with_for_update` - Core level method with
             full argument and behavioral description.
 
         """
-        self._for_update_arg = LockmodeArg(
+        self._for_update_arg = ForUpdateArg(
             read=read,
             nowait=nowait,
             of=of,
@@ -4098,28 +4062,6 @@ class Query(Generative):
                 )
 
 
-class LockmodeArg(ForUpdateArg):
-    @classmethod
-    def parse_legacy_query(cls, mode):
-        if mode in (None, False):
-            return None
-
-        if mode == "read":
-            read = True
-            nowait = False
-        elif mode == "update":
-            read = nowait = False
-        elif mode == "update_nowait":
-            nowait = True
-            read = False
-        else:
-            raise sa_exc.ArgumentError(
-                "Unknown with_lockmode argument: %r" % mode
-            )
-
-        return LockmodeArg(read=read, nowait=nowait)
-
-
 class _QueryEntity(object):
     """represent an entity column returned within a Query result."""
 
index fefdd4ef1ad1646319763297058ee43a92a448d8..c773aeb081297b58d498299b6f7fe268d94b787b 100644 (file)
@@ -1664,11 +1664,7 @@ class Session(_SessionClassMethods):
                 util.raise_(e, with_traceback=sys.exc_info()[2])
 
     def refresh(
-        self,
-        instance,
-        attribute_names=None,
-        with_for_update=None,
-        lockmode=None,
+        self, instance, attribute_names=None, with_for_update=None,
     ):
         """Expire and refresh the attributes on the given instance.
 
@@ -1701,10 +1697,6 @@ class Session(_SessionClassMethods):
 
           .. versionadded:: 1.2
 
-        :param lockmode: Passed to the :class:`~sqlalchemy.orm.query.Query`
-          as used by :meth:`~sqlalchemy.orm.query.Query.with_lockmode`.
-          Superseded by :paramref:`.Session.refresh.with_for_update`.
-
         .. seealso::
 
             :ref:`session_expire` - introductory material
@@ -1730,13 +1722,11 @@ class Session(_SessionClassMethods):
                 "A blank dictionary is ambiguous."
             )
 
-        if lockmode:
-            with_for_update = query.LockmodeArg.parse_legacy_query(lockmode)
-        elif with_for_update is not None:
+        if with_for_update is not None:
             if with_for_update is True:
-                with_for_update = query.LockmodeArg()
+                with_for_update = query.ForUpdateArg()
             elif with_for_update:
-                with_for_update = query.LockmodeArg(**with_for_update)
+                with_for_update = query.ForUpdateArg(**with_for_update)
             else:
                 with_for_update = None
 
index 843732f6787326a1f2f1fdea37b0ad5bdd9114d0..5a10611ad89ebb3bb1372bd98d5f5016053b0e13 100644 (file)
@@ -1535,9 +1535,7 @@ class TextClause(
         ),
     )
     @_document_text_coercion("text", ":func:`.text`", ":paramref:`.text.text`")
-    def _create_text(
-        self, text, bind=None, bindparams=None, typemap=None,
-    ):
+    def _create_text(self, text, bind=None, bindparams=None, typemap=None):
         r"""Construct a new :class:`.TextClause` clause, representing
         a textual SQL string directly.
 
index 45b9e7f9dc940dec3269959ac354e546598bb508..3c23704c5dd9f46d3a9e3dbe8d22f302eeae3508 100644 (file)
@@ -833,22 +833,8 @@ class Join(FromClause):
         return self._join_condition(left, right, a_subset=left_right)
 
     @classmethod
-    @util.deprecated_params(
-        ignore_nonexistent_tables=(
-            "0.9",
-            "The :paramref:`.join_condition.ignore_nonexistent_tables` "
-            "parameter is deprecated and will be removed in a future "
-            "release.  Tables outside of the two tables being handled "
-            "are no longer considered.",
-        )
-    )
     def _join_condition(
-        cls,
-        a,
-        b,
-        ignore_nonexistent_tables=False,
-        a_subset=None,
-        consider_as_foreign_keys=None,
+        cls, a, b, a_subset=None, consider_as_foreign_keys=None
     ):
         """create a join condition between two tables or selectables.
 
@@ -864,9 +850,6 @@ class Join(FromClause):
         between the two selectables.   If there are multiple ways
         to join, or no way to join, an error is raised.
 
-        :param ignore_nonexistent_tables: unused - tables outside of the
-         two tables being handled are not considered.
-
         :param a_subset: An optional expression that is a sub-component
          of ``a``.  An attempt will be made to join to just this sub-component
          first before looking at the full ``a`` construct, and if found
@@ -1115,10 +1098,6 @@ class Join(FromClause):
         argument as a no-op, so that the argument can be passed to the
         ``alias()`` method of any selectable.
 
-        .. versionadded:: 0.9.0 Added the ``flat=True`` option to create
-          "aliases" of joins without enclosing inside of a SELECT
-          subquery.
-
         :param name: name given to the alias.
 
         :param flat: if True, produce an alias of the left and right
@@ -1126,8 +1105,6 @@ class Join(FromClause):
          two selectables.   This produces join expression that does not
          include an enclosing SELECT.
 
-         .. versionadded:: 0.9.0
-
         .. seealso::
 
             :ref:`core_tutorial_aliases`
@@ -1333,8 +1310,6 @@ class Alias(AliasedReturnsRows):
          is an instance of :class:`.Join` - see :meth:`.Join.alias`
          for details.
 
-         .. versionadded:: 0.9.0
-
         """
         return coercions.expect(
             roles.FromClauseRole, selectable, allow_select=True
@@ -2021,8 +1996,6 @@ class ForUpdateArg(ClauseElement):
     ):
         """Represents arguments specified to :meth:`.Select.for_update`.
 
-        .. versionadded:: 0.9.0
-
         """
 
         self.nowait = nowait
@@ -2386,11 +2359,6 @@ class GenerativeSelect(DeprecatedSelectBaseGenerations, SelectBase):
     represents a fixed textual string which cannot be altered at this level,
     only wrapped as a subquery.
 
-    .. versionadded:: 0.9.0 :class:`.GenerativeSelect` was added to
-       provide functionality specific to :class:`.Select` and
-       :class:`.CompoundSelect` while allowing :class:`.SelectBase` to be
-       used for other SELECT-like objects, e.g. :class:`.TextualSelect`.
-
     """
 
     _order_by_clauses = ()
index 91b15d14a233c5f745c700957291ce50a29b4a5f..4efff1f7697e507ed63154c04099a64ad22457bd 100644 (file)
@@ -1,7 +1,6 @@
 import sqlalchemy as sa
 from sqlalchemy import and_
 from sqlalchemy import event
-from sqlalchemy import exc
 from sqlalchemy import func
 from sqlalchemy import Integer
 from sqlalchemy import select
@@ -463,7 +462,7 @@ class DeprecatedQueryTest(_fixtures.FixtureTest, AssertsCompiledSQL):
         # same here, this was "passing string names to Query.columns"
         # deprecation message, that's gone here?
         assert_raises_message(
-            exc.ArgumentError,
+            sa.exc.ArgumentError,
             "Textual column expression 'name' should be explicitly",
             s.query,
             User.id,
@@ -1508,61 +1507,6 @@ class DeprecatedOptionAllTest(OptionsPathTest, _fixtures.FixtureTest):
             sess.query(User).options(undefer("addresses", "email_address"))
 
 
-class LegacyLockModeTest(_fixtures.FixtureTest):
-    run_inserts = None
-
-    @classmethod
-    def setup_mappers(cls):
-        User, users = cls.classes.User, cls.tables.users
-        mapper(User, users)
-
-    def _assert_legacy(self, arg, read=False, nowait=False):
-        User = self.classes.User
-        s = Session()
-
-        with testing.expect_deprecated(
-            r"The Query.with_lockmode\(\) method is deprecated"
-        ):
-            q = s.query(User).with_lockmode(arg)
-        sel = q._compile_context().statement
-
-        if arg is None:
-            assert q._for_update_arg is None
-            assert sel._for_update_arg is None
-            return
-
-        assert q._for_update_arg.read is read
-        assert q._for_update_arg.nowait is nowait
-
-        assert sel._for_update_arg.read is read
-        assert sel._for_update_arg.nowait is nowait
-
-    def test_false_legacy(self):
-        self._assert_legacy(None)
-
-    def test_plain_legacy(self):
-        self._assert_legacy("update")
-
-    def test_nowait_legacy(self):
-        self._assert_legacy("update_nowait", nowait=True)
-
-    def test_read_legacy(self):
-        self._assert_legacy("read", read=True)
-
-    def test_unknown_legacy_lock_mode(self):
-        User = self.classes.User
-        sess = Session()
-        with testing.expect_deprecated(
-            r"The Query.with_lockmode\(\) method is deprecated"
-        ):
-            assert_raises_message(
-                exc.ArgumentError,
-                "Unknown with_lockmode argument: 'unknown_mode'",
-                sess.query(User.id).with_lockmode,
-                "unknown_mode",
-            )
-
-
 class InstrumentationTest(fixtures.ORMTest):
     def test_dict_subclass4(self):
         # tests #2654
index 864264af9291b7942eaa45737d537e3a33834b70..8dab797eddc929bd102238f701118320bfdd2924 100644 (file)
@@ -1984,14 +1984,14 @@ class SessionInterface(fixtures.TestBase):
                 s.refresh(m1, with_for_update=False)
                 s.refresh(m1)
 
-            from sqlalchemy.orm.query import LockmodeArg
+            from sqlalchemy.orm.query import ForUpdateArg
 
             eq_(
                 [
                     call[-1]["with_for_update"]
                     for call in load_on_ident.mock_calls
                 ],
-                [LockmodeArg(read=True), LockmodeArg(), None, None],
+                [ForUpdateArg(read=True), ForUpdateArg(), None, None],
             )
 
 
index ef53e613c0778e3980c90e0d5fbfe2df660e704f..c6418745ddc0b13c0dd7cca287e32ef6ab9f46c9 100644 (file)
@@ -398,45 +398,6 @@ class VersioningTest(fixtures.MappedTest):
         s1.close()
         s1.query(Foo).with_for_update(read=True).get(f1s1.id)
 
-    @engines.close_open_connections
-    def test_versioncheck_legacy(self):
-        """query.with_lockmode performs a 'version check' on an already loaded
-        instance"""
-
-        Foo = self.classes.Foo
-
-        s1 = self._fixture()
-        f1s1 = Foo(value="f1 value")
-        s1.add(f1s1)
-        s1.commit()
-
-        s2 = create_session(autocommit=False)
-        f1s2 = s2.query(Foo).get(f1s1.id)
-        f1s2.value = "f1 new value"
-        with conditional_sane_rowcount_warnings(
-            update=True, only_returning=True
-        ):
-            s2.commit()
-
-        # load, version is wrong
-        assert_raises_message(
-            sa.orm.exc.StaleDataError,
-            r"Instance .* has version id '\d+' which does not "
-            r"match database-loaded version id '\d+'",
-            s1.query(Foo).with_for_update(read=True).get,
-            f1s1.id,
-        )
-
-        # reload it - this expires the old version first
-        s1.refresh(f1s1, with_for_update=dict(read=True))
-
-        # now assert version OK
-        s1.query(Foo).with_for_update(read=True).get(f1s1.id)
-
-        # assert brand new load is OK too
-        s1.close()
-        s1.query(Foo).with_for_update(read=True).get(f1s1.id)
-
     def test_versioncheck_not_versioned(self):
         """ensure the versioncheck logic skips if there isn't a
         version_id_col actually configured"""
@@ -471,7 +432,7 @@ class VersioningTest(fixtures.MappedTest):
         f1s2.value = "f1 new value"
 
         assert_raises(
-            exc.DBAPIError, s1.refresh, f1s1, lockmode="update_nowait"
+            exc.DBAPIError, s1.refresh, f1s1, with_for_update={"nowait": True}
         )
         s1.rollback()
 
@@ -480,34 +441,6 @@ class VersioningTest(fixtures.MappedTest):
         s1.refresh(f1s1, with_for_update={"nowait": True})
         assert f1s1.version_id == f1s2.version_id
 
-    @engines.close_open_connections
-    @testing.requires.update_nowait
-    def test_versioncheck_for_update_legacy(self):
-        """query.with_lockmode performs a 'version check' on an already loaded
-        instance"""
-
-        Foo = self.classes.Foo
-
-        s1 = self._fixture()
-        f1s1 = Foo(value="f1 value")
-        s1.add(f1s1)
-        s1.commit()
-
-        s2 = create_session(autocommit=False)
-        f1s2 = s2.query(Foo).get(f1s1.id)
-        s2.refresh(f1s2, lockmode="update")
-        f1s2.value = "f1 new value"
-
-        assert_raises(
-            exc.DBAPIError, s1.refresh, f1s1, lockmode="update_nowait"
-        )
-        s1.rollback()
-
-        with conditional_sane_rowcount_warnings(update=True):
-            s2.commit()
-        s1.refresh(f1s1, lockmode="update_nowait")
-        assert f1s1.version_id == f1s2.version_id
-
     def test_update_multi_missing_broken_multi_rowcount(self):
         @util.memoized_property
         def rowcount(self):
index 93b29847fcb77cfb54afff7b33db4b1f803898f2..d641c18e2a457fc94ed3986ac631ddaa49f9b551 100644 (file)
@@ -29,7 +29,6 @@ from sqlalchemy.engine import default
 from sqlalchemy.sql import coercions
 from sqlalchemy.sql import quoted_name
 from sqlalchemy.sql import roles
-from sqlalchemy.sql import util as sql_util
 from sqlalchemy.sql import visitors
 from sqlalchemy.sql.selectable import SelectStatementGrouping
 from sqlalchemy.testing import assert_raises
@@ -94,24 +93,6 @@ class DeprecationWarningsTest(fixtures.TestBase, AssertsCompiledSQL):
         ):
             create_engine("mysql://", convert_unicode=True, module=mock.Mock())
 
-    def test_join_condition_ignore_nonexistent_tables(self):
-        m = MetaData()
-        t1 = Table("t1", m, Column("id", Integer))
-        t2 = Table(
-            "t2", m, Column("id", Integer), Column("t1id", ForeignKey("t1.id"))
-        )
-        with testing.expect_deprecated(
-            "The join_condition.ignore_nonexistent_tables "
-            "parameter is deprecated"
-        ):
-            join_cond = sql_util.join_condition(
-                t1, t2, ignore_nonexistent_tables=True
-            )
-
-        t1t2 = t1.join(t2)
-
-        assert t1t2.onclause.compare(join_cond)
-
     def test_empty_and_or(self):
         with testing.expect_deprecated(
             r"Invoking and_\(\) without arguments is deprecated, and "