]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
Deprecate bound metadata
authorMike Bayer <mike_mp@zzzcomputing.com>
Mon, 12 Oct 2020 17:16:14 +0000 (13:16 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Mon, 12 Oct 2020 17:57:43 +0000 (13:57 -0400)
The :paramref:`_schema.MetaData.bind` argument as well as the overall
concept of "bound metadata" is deprecated in SQLAlchemy 1.4 and will be
removed in SQLAlchemy 2.0.  The parameter as well as related functions now
emit a :class:`_exc.RemovedIn20Warning` when :ref:`deprecation_20_mode` is
in use.

Added new parameter :paramref:`_automap.AutomapBase.prepare.autoload_with`
which supersedes :paramref:`_automap.AutomapBase.prepare.reflect`
and :paramref:`_automap.AutomapBase.prepare.engine`.

Fixes: #4634
Fixes: #5142
Change-Id: Iaabf9b481931e2fb68b97b5954c32e65772a298e

doc/build/changelog/unreleased_14/4634.rst [new file with mode: 0644]
lib/sqlalchemy/ext/automap.py
lib/sqlalchemy/sql/base.py
lib/sqlalchemy/sql/schema.py
lib/sqlalchemy/testing/warnings.py
test/ext/test_automap.py
test/ext/test_deprecations.py
test/sql/test_deprecations.py

diff --git a/doc/build/changelog/unreleased_14/4634.rst b/doc/build/changelog/unreleased_14/4634.rst
new file mode 100644 (file)
index 0000000..2beaae8
--- /dev/null
@@ -0,0 +1,25 @@
+.. change::
+    :tags: change, engine
+    :tickets: 4634
+
+    The :paramref:`_schema.MetaData.bind` argument as well as the overall
+    concept of "bound metadata" is deprecated in SQLAlchemy 1.4 and will be
+    removed in SQLAlchemy 2.0.  The parameter as well as related functions now
+    emit a :class:`_exc.RemovedIn20Warning` when :ref:`deprecation_20_mode` is
+    in use.
+
+    .. seealso::
+
+        :ref:`migration_20_implicit_execution`
+
+
+
+.. change::
+    :tags: change, ext
+    :tickets: 5142
+
+    Added new parameter :paramref:`_automap.AutomapBase.prepare.autoload_with`
+    which supersedes :paramref:`_automap.AutomapBase.prepare.reflect`
+    and :paramref:`_automap.AutomapBase.prepare.engine`.
+
+
index 2dc7d54debc7498e3d1c254e9c0657d4bfd10fa7..97dff7f4ec0d72d7befd7530e44f66c4450a7820 100644 (file)
@@ -720,16 +720,35 @@ class AutomapBase(object):
     """
 
     @classmethod
+    @util.deprecated_params(
+        engine=(
+            "2.0",
+            "The :paramref:`_automap.AutomapBase.prepare.engine` parameter "
+            "is deprecated and will be removed in a future release.  "
+            "Please use the "
+            ":paramref:`_automap.AutomapBase.prepare.autoload_with` "
+            "parameter.",
+        ),
+        reflect=(
+            "2.0",
+            "The :paramref:`_automap.AutomapBase.prepare.reflect` "
+            "parameter is deprecated and will be removed in a future "
+            "release.  Reflection is enabled when "
+            ":paramref:`_automap.AutomapBase.prepare.autoload_with` "
+            "is passed.",
+        ),
+    )
     def prepare(
         cls,
+        autoload_with=None,
         engine=None,
         reflect=False,
         schema=None,
-        classname_for_table=classname_for_table,
-        collection_class=list,
-        name_for_scalar_relationship=name_for_scalar_relationship,
-        name_for_collection_relationship=name_for_collection_relationship,
-        generate_relationship=generate_relationship,
+        classname_for_table=None,
+        collection_class=None,
+        name_for_scalar_relationship=None,
+        name_for_collection_relationship=None,
+        generate_relationship=None,
     ):
         """Extract mapped classes and relationships from the
         :class:`_schema.MetaData` and
@@ -782,9 +801,31 @@ class AutomapBase(object):
          .. versionadded:: 1.1
 
         """
+        glbls = globals()
+        if classname_for_table is None:
+            classname_for_table = glbls["classname_for_table"]
+        if name_for_scalar_relationship is None:
+            name_for_scalar_relationship = glbls[
+                "name_for_scalar_relationship"
+            ]
+        if name_for_collection_relationship is None:
+            name_for_collection_relationship = glbls[
+                "name_for_collection_relationship"
+            ]
+        if generate_relationship is None:
+            generate_relationship = glbls["generate_relationship"]
+        if collection_class is None:
+            collection_class = list
+
+        if autoload_with:
+            reflect = True
+
+        if engine:
+            autoload_with = engine
+
         if reflect:
             cls.metadata.reflect(
-                engine,
+                autoload_with,
                 schema=schema,
                 extend_existing=True,
                 autoload_replace=False,
index f9b5ce7e19338d1f0420de1fe1a06b89bf4a3c9b..93d6dcd84f25d64cec21a3fbeee3e8750d42448d 100644 (file)
@@ -1475,6 +1475,11 @@ class ColumnSet(util.ordered_column_set):
 
 
 def _bind_or_error(schemaitem, msg=None):
+
+    util.warn_deprecated_20(
+        "The ``bind`` argument for schema methods that invoke SQL "
+        "against an engine or connection will be required in SQLAlchemy 2.0."
+    )
     bind = schemaitem.bind
     if not bind:
         name = schemaitem.__class__.__name__
index 50d7d1f5b8808e7e9dd073ccd8c3146b1064391f..770c02ef5b9678754a1cfc44cd58590dad442a64 100644 (file)
@@ -843,6 +843,9 @@ class Table(DialectKWArgs, SchemaItem, TableClause):
         :class:`_schema.Table`, using the given :class:`.Connectable`
         for connectivity.
 
+        .. note:: the "bind" argument will be required in
+           SQLAlchemy 2.0.
+
         .. seealso::
 
             :meth:`_schema.MetaData.create_all`.
@@ -858,6 +861,9 @@ class Table(DialectKWArgs, SchemaItem, TableClause):
         :class:`_schema.Table`, using the given :class:`.Connectable`
         for connectivity.
 
+        .. note:: the "bind" argument will be required in
+           SQLAlchemy 2.0.
+
         .. seealso::
 
             :meth:`_schema.MetaData.drop_all`.
@@ -2672,14 +2678,24 @@ class Sequence(IdentityOptions, roles.StatementRole, DefaultGenerator):
             return None
 
     def create(self, bind=None, checkfirst=True):
-        """Creates this sequence in the database."""
+        """Creates this sequence in the database.
+
+        .. note:: the "bind" argument will be required in
+           SQLAlchemy 2.0.
+
+        """
 
         if bind is None:
             bind = _bind_or_error(self)
         bind._run_ddl_visitor(ddl.SchemaGenerator, self, checkfirst=checkfirst)
 
     def drop(self, bind=None, checkfirst=True):
-        """Drops this sequence from the database."""
+        """Drops this sequence from the database.
+
+        .. note:: the "bind" argument will be required in
+           SQLAlchemy 2.0.
+
+        """
 
         if bind is None:
             bind = _bind_or_error(self)
@@ -3904,6 +3920,13 @@ class MetaData(SchemaItem):
 
     __visit_name__ = "metadata"
 
+    @util.deprecated_params(
+        bind=(
+            "2.0",
+            "The :paramref:`_schema.MetaData.bind` argument is deprecated and "
+            "will be removed in SQLAlchemy 2.0.",
+        ),
+    )
     def __init__(
         self,
         bind=None,
@@ -4431,6 +4454,9 @@ class MetaData(SchemaItem):
           database; if None, uses the existing bind on this ``MetaData``, if
           any.
 
+          .. note:: the "bind" argument will be required in
+             SQLAlchemy 2.0.
+
         :param tables:
           Optional list of ``Table`` objects, which is a subset of the total
           tables in the ``MetaData`` (others are ignored).
@@ -4457,6 +4483,9 @@ class MetaData(SchemaItem):
           database; if None, uses the existing bind on this ``MetaData``, if
           any.
 
+          .. note:: the "bind" argument will be required in
+             SQLAlchemy 2.0.
+
         :param tables:
           Optional list of ``Table`` objects, which is a subset of the
           total tables in the ``MetaData`` (others are ignored).
index 5704cf2a6e459be935b886f2069109916d981cfa..bfa09d00a6004b0866b43dbce1ff23c0ae570bf2 100644 (file)
@@ -60,6 +60,12 @@ def setup_filters():
         r".*DefaultGenerator.execute\(\)",
         r"The autoload parameter is deprecated and will be removed ",
         #
+        #
+        # bound metadaa
+        #
+        r"The MetaData.bind argument is deprecated",
+        r"The ``bind`` argument for schema methods that invoke SQL ",
+        #
         # result sets
         #
         r"The Row.keys\(\) function/method",
index b022f0357ded9bd6bccc139d6cb113c06737883d..da0e7c1338ba1c1b39c3b292993fa0b6c47ebfab 100644 (file)
@@ -113,7 +113,7 @@ class AutomapTest(fixtures.MappedTest):
         Base = automap_base(metadata=self.metadata)
         engine_mock = Mock()
         with patch.object(Base.metadata, "reflect") as reflect_mock:
-            Base.prepare(engine_mock, reflect=True, schema="some_schema")
+            Base.prepare(autoload_with=engine_mock, schema="some_schema")
             reflect_mock.assert_called_once_with(
                 engine_mock,
                 schema="some_schema",
@@ -131,7 +131,7 @@ class AutomapTest(fixtures.MappedTest):
         Base = automap_base(metadata=self.metadata)
         engine_mock = Mock()
         with patch.object(Base.metadata, "reflect") as reflect_mock:
-            Base.prepare(engine_mock, reflect=True)
+            Base.prepare(autoload_with=engine_mock)
             reflect_mock.assert_called_once_with(
                 engine_mock,
                 schema=None,
@@ -352,7 +352,7 @@ class AutomapInhTest(fixtures.MappedTest):
         class SubUser2(Single):
             __mapper_args__ = {"polymorphic_identity": "u2"}
 
-        Base.prepare(engine=testing.db, reflect=True)
+        Base.prepare(autoload_with=testing.db)
 
         assert SubUser2.__mapper__.inherits is Single.__mapper__
 
@@ -373,7 +373,7 @@ class AutomapInhTest(fixtures.MappedTest):
             __tablename__ = "joined_inh"
             __mapper_args__ = {"polymorphic_identity": "u1"}
 
-        Base.prepare(engine=testing.db, reflect=True)
+        Base.prepare(autoload_with=testing.db)
 
         assert SubJoined.__mapper__.inherits is Joined.__mapper__
 
@@ -387,8 +387,7 @@ class AutomapInhTest(fixtures.MappedTest):
             return None
 
         Base.prepare(
-            engine=testing.db,
-            reflect=True,
+            autoload_with=testing.db,
             generate_relationship=_gen_relationship,
         )
 
@@ -416,7 +415,7 @@ class ConcurrentAutomapTest(fixtures.TestBase):
     def _automap(self, e):
         Base = automap_base()
 
-        Base.prepare(e, reflect=True)
+        Base.prepare(autoload_with=e)
 
         time.sleep(0.01)
         configure_mappers()
index 510f5f415a4dfd566104fc14e1a0cfb226dae77b..b209de36d70320ec6f7858d9c07645c88bb6ea39 100644 (file)
@@ -1,4 +1,5 @@
 from sqlalchemy import testing
+from sqlalchemy.ext.automap import automap_base
 from sqlalchemy.ext.horizontal_shard import ShardedSession
 from sqlalchemy.orm import mapper
 from sqlalchemy.testing import eq_
@@ -6,6 +7,31 @@ from sqlalchemy.testing import fixtures
 from sqlalchemy.testing import mock
 from . import test_mutable
 from .test_mutable import Foo
+from ..orm._fixtures import FixtureTest
+
+
+class AutomapTest(fixtures.MappedTest):
+    @classmethod
+    def define_tables(cls, metadata):
+        FixtureTest.define_tables(metadata)
+
+    def test_reflect_true(self):
+        Base = automap_base(metadata=self.metadata)
+        engine_mock = mock.Mock()
+        with mock.patch.object(Base.metadata, "reflect") as reflect_mock:
+            with testing.expect_deprecated(
+                "The AutomapBase.prepare.reflect parameter is deprecated",
+                "The AutomapBase.prepare.engine parameter is deprecated",
+            ):
+                Base.prepare(
+                    engine=engine_mock, reflect=True, schema="some_schema"
+                )
+            reflect_mock.assert_called_once_with(
+                engine_mock,
+                schema="some_schema",
+                extend_existing=True,
+                autoload_replace=False,
+            )
 
 
 class MutableIncludeNonPrimaryTest(test_mutable.MutableWithScalarJSONTest):
index f418eab6b90cb1b3f7faccb1120834ec44002d65..176c16208ae90919f66972ed267683ba82a9386d 100644 (file)
@@ -14,6 +14,7 @@ from sqlalchemy import exc
 from sqlalchemy import exists
 from sqlalchemy import ForeignKey
 from sqlalchemy import func
+from sqlalchemy import inspect
 from sqlalchemy import INT
 from sqlalchemy import Integer
 from sqlalchemy import join
@@ -67,6 +68,28 @@ class ToMetaDataTest(fixtures.TestBase):
             eq_(t2.name, "t")
 
 
+class BoundMetadataTest(fixtures.TestBase):
+    def test_arg_deprecated(self):
+        with testing.expect_deprecated_20(
+            "The MetaData.bind argument is deprecated"
+        ):
+            m1 = MetaData(testing.db)
+
+        Table("t", m1, Column("q", Integer))
+
+        with testing.expect_deprecated_20(
+            "The ``bind`` argument for schema methods that invoke SQL "
+            "against an engine or connection will be required"
+        ):
+            m1.create_all()
+        try:
+            assert "t" in inspect(testing.db).get_table_names()
+        finally:
+            m1.drop_all(testing.db)
+
+        assert "t" not in inspect(testing.db).get_table_names()
+
+
 class DeprecationWarningsTest(fixtures.TestBase, AssertsCompiledSQL):
     __backend__ = True