From deaefbe748a43b9f84dabc232f0c20e065864a14 Mon Sep 17 00:00:00 2001 From: Gord Thompson Date: Wed, 17 Feb 2021 11:58:27 -0700 Subject: [PATCH] Deprecate and rename schema .copy() methods Fixes: #5953 Change-Id: I1e69a1628e408f06b43efbc0cc52fc0ad1e8cbc4 --- doc/build/changelog/unreleased_14/5953.rst | 6 ++ lib/sqlalchemy/dialects/postgresql/ext.py | 2 +- lib/sqlalchemy/orm/decl_base.py | 2 +- lib/sqlalchemy/sql/schema.py | 76 ++++++++++++++++++++-- test/dialect/postgresql/test_compiler.py | 2 +- test/sql/test_metadata.py | 30 ++++----- 6 files changed, 94 insertions(+), 24 deletions(-) create mode 100644 doc/build/changelog/unreleased_14/5953.rst diff --git a/doc/build/changelog/unreleased_14/5953.rst b/doc/build/changelog/unreleased_14/5953.rst new file mode 100644 index 0000000000..9b559737ae --- /dev/null +++ b/doc/build/changelog/unreleased_14/5953.rst @@ -0,0 +1,6 @@ +.. change:: + :tags: bug, schema + :tickets: 5953 + + Deprecated all schema-level ``.copy()`` methods and renamed to + ``_copy()``. diff --git a/lib/sqlalchemy/dialects/postgresql/ext.py b/lib/sqlalchemy/dialects/postgresql/ext.py index a93a3477df..71a0aa5a68 100644 --- a/lib/sqlalchemy/dialects/postgresql/ext.py +++ b/lib/sqlalchemy/dialects/postgresql/ext.py @@ -241,7 +241,7 @@ class ExcludeConstraint(ColumnCollectionConstraint): ) ] - def copy(self, target_table=None, **kw): + def _copy(self, target_table=None, **kw): elements = [ ( schema._copy_expression(expr, self.parent, target_table), diff --git a/lib/sqlalchemy/orm/decl_base.py b/lib/sqlalchemy/orm/decl_base.py index db7dfebe4a..a21af192e0 100644 --- a/lib/sqlalchemy/orm/decl_base.py +++ b/lib/sqlalchemy/orm/decl_base.py @@ -600,7 +600,7 @@ class _ClassScanMapperConfig(_MapperConfig): "__table__" in dict_ and (obj.name or name) in dict_["__table__"].c ): - column_copies[obj] = copy_ = obj.copy() + column_copies[obj] = copy_ = obj._copy() copy_._creation_order = obj._creation_order setattr(cls, name, copy_) dict_[name] = copy_ diff --git a/lib/sqlalchemy/sql/schema.py b/lib/sqlalchemy/sql/schema.py index 6e3c9dbfbf..9d76173705 100644 --- a/lib/sqlalchemy/sql/schema.py +++ b/lib/sqlalchemy/sql/schema.py @@ -1077,7 +1077,7 @@ class Table(DialectKWArgs, SchemaItem, TableClause): args = [] for c in self.columns: - args.append(c.copy(schema=schema)) + args.append(c._copy(schema=schema)) table = Table( name, metadata, @@ -1098,7 +1098,7 @@ class Table(DialectKWArgs, SchemaItem, TableClause): schema if referred_schema == self.schema else None ) table.append_constraint( - c.copy(schema=fk_constraint_schema, target_table=table) + c._copy(schema=fk_constraint_schema, target_table=table) ) elif not c._type_bound: # skip unique constraints that would be generated @@ -1107,7 +1107,7 @@ class Table(DialectKWArgs, SchemaItem, TableClause): continue table.append_constraint( - c.copy(schema=schema, target_table=table) + c._copy(schema=schema, target_table=table) ) for index in self.indexes: # skip indexes that would be generated @@ -1841,7 +1841,15 @@ class Column(DialectKWArgs, SchemaItem, ColumnClause): else: event.listen(self, "after_parent_attach", fn) + @util.deprecated( + "1.4", + "The :meth:`_schema.Column.copy` method is deprecated " + "and will be removed in a future release.", + ) def copy(self, **kw): + return self._copy(**kw) + + def _copy(self, **kw): """Create a copy of this ``Column``, uninitialized. This is used in :meth:`_schema.Table.to_metadata`. @@ -1850,8 +1858,8 @@ class Column(DialectKWArgs, SchemaItem, ColumnClause): # Constraint objects plus non-constraint-bound ForeignKey objects args = [ - c.copy(**kw) for c in self.constraints if not c._type_bound - ] + [c.copy(**kw) for c in self.foreign_keys if not c.constraint] + c._copy(**kw) for c in self.constraints if not c._type_bound + ] + [c._copy(**kw) for c in self.foreign_keys if not c.constraint] # ticket #5276 column_kwargs = {} @@ -1869,7 +1877,7 @@ class Column(DialectKWArgs, SchemaItem, ColumnClause): server_onupdate = self.server_onupdate if isinstance(server_default, (Computed, Identity)): server_default = server_onupdate = None - args.append(self.server_default.copy(**kw)) + args.append(self.server_default._copy(**kw)) type_ = self.type if isinstance(type_, SchemaEventTarget): @@ -2122,7 +2130,15 @@ class ForeignKey(DialectKWArgs, SchemaItem): def __repr__(self): return "ForeignKey(%r)" % self._get_colspec() + @util.deprecated( + "1.4", + "The :meth:`_schema.ForeignKey.copy` method is deprecated " + "and will be removed in a future release.", + ) def copy(self, schema=None): + return self._copy(schema) + + def _copy(self, schema=None): """Produce a copy of this :class:`_schema.ForeignKey` object. The new :class:`_schema.ForeignKey` will not be bound @@ -3128,7 +3144,15 @@ class Constraint(DialectKWArgs, SchemaItem): self.parent = parent parent.constraints.add(self) + @util.deprecated( + "1.4", + "The :meth:`_schema.Constraint.copy` method is deprecated " + "and will be removed in a future release.", + ) def copy(self, **kw): + return self._copy(**kw) + + def _copy(self, **kw): raise NotImplementedError() @@ -3276,7 +3300,15 @@ class ColumnCollectionConstraint(ColumnCollectionMixin, Constraint): def __contains__(self, x): return x in self.columns + @util.deprecated( + "1.4", + "The :meth:`_schema.ColumnCollectionConstraint.copy` method " + "is deprecated and will be removed in a future release.", + ) def copy(self, target_table=None, **kw): + return self._copy(target_table, **kw) + + def _copy(self, target_table=None, **kw): # ticket #5276 constraint_kwargs = {} for dialect_name in self.dialect_options: @@ -3398,7 +3430,15 @@ class CheckConstraint(ColumnCollectionConstraint): def is_column_level(self): return not isinstance(self.parent, Table) + @util.deprecated( + "1.4", + "The :meth:`_schema.CheckConstraint.copy` method is deprecated " + "and will be removed in a future release.", + ) def copy(self, target_table=None, **kw): + return self._copy(target_table, **kw) + + def _copy(self, target_table=None, **kw): if target_table is not None: # note that target_table is None for the copy process of # a column-bound CheckConstraint, so this path is not reached @@ -3683,7 +3723,15 @@ class ForeignKeyConstraint(ColumnCollectionConstraint): self._validate_dest_table(table) + @util.deprecated( + "1.4", + "The :meth:`_schema.ForeignKeyConstraint.copy` method is deprecated " + "and will be removed in a future release.", + ) def copy(self, schema=None, target_table=None, **kw): + return self._copy(target_table, **kw) + + def _copy(self, schema=None, target_table=None, **kw): fkc = ForeignKeyConstraint( [x.parent.key for x in self.elements], [ @@ -4874,7 +4922,15 @@ class Computed(FetchedValue, SchemaItem): def _as_for_update(self, for_update): return self + @util.deprecated( + "1.4", + "The :meth:`_schema.Computed.copy` method is deprecated " + "and will be removed in a future release.", + ) def copy(self, target_table=None, **kw): + return self._copy(target_table, **kw) + + def _copy(self, target_table=None, **kw): sqltext = _copy_expression( self.sqltext, self.column.table if self.column is not None else None, @@ -5010,7 +5066,15 @@ class Identity(IdentityOptions, FetchedValue, SchemaItem): def _as_for_update(self, for_update): return self + @util.deprecated( + "1.4", + "The :meth:`_schema.Identity.copy` method is deprecated " + "and will be removed in a future release.", + ) def copy(self, **kw): + return self._copy(**kw) + + def _copy(self, **kw): i = Identity( always=self.always, on_null=self.on_null, diff --git a/test/dialect/postgresql/test_compiler.py b/test/dialect/postgresql/test_compiler.py index 5f0c5f3a51..44f8c93986 100644 --- a/test/dialect/postgresql/test_compiler.py +++ b/test/dialect/postgresql/test_compiler.py @@ -900,7 +900,7 @@ class CompileTest(fixtures.TestBase, AssertsCompiledSQL): ) # apparently you can't copy a ColumnCollectionConstraint until # after it has been bound to a table... - cons_copy = cons.copy() + cons_copy = cons._copy() tbl.append_constraint(cons_copy) self.assert_compile( schema.AddConstraint(cons_copy), diff --git a/test/sql/test_metadata.py b/test/sql/test_metadata.py index 1c24cc095a..2e64e0a906 100644 --- a/test/sql/test_metadata.py +++ b/test/sql/test_metadata.py @@ -93,7 +93,7 @@ class MetaDataTest(fixtures.TestBase, ComparesTables): ), Column("bar", Integer(), info={"foo": "bar"}), ]: - c2 = col.copy() + c2 = col._copy() for attr in ( "name", "type", @@ -118,13 +118,13 @@ class MetaDataTest(fixtures.TestBase, ComparesTables): self.widget = kw.pop("widget", None) super(MyColumn, self).__init__(*args, **kw) - def copy(self, *arg, **kw): - c = super(MyColumn, self).copy(*arg, **kw) + def _copy(self, *arg, **kw): + c = super(MyColumn, self)._copy(*arg, **kw) c.widget = self.widget return c c1 = MyColumn("foo", Integer, widget="x") - c2 = c1.copy() + c2 = c1._copy() assert isinstance(c2, MyColumn) eq_(c2.widget, "x") @@ -137,7 +137,7 @@ class MetaDataTest(fixtures.TestBase, ComparesTables): c1 = Column("foo", String()) m = MetaData() for i in range(3): - cx = c1.copy() + cx = c1._copy() # as of 0.7, these events no longer copy. its expected # that listeners will be re-established from the # natural construction of things. @@ -239,8 +239,8 @@ class MetaDataTest(fixtures.TestBase, ComparesTables): fk2 = ForeignKeyConstraint((c1,), (c2,), **kw) t1.append_constraint(fk2) - fk1c = fk1.copy() - fk2c = fk2.copy() + fk1c = fk1._copy() + fk2c = fk2._copy() for k in kw: eq_(getattr(fk1c, k), kw[k]) @@ -257,7 +257,7 @@ class MetaDataTest(fixtures.TestBase, ComparesTables): deferrable=True, _create_rule=r, ) - c2 = c.copy() + c2 = c._copy() eq_(c2.name, "name") eq_(str(c2.sqltext), "foo bar") eq_(c2.initially, True) @@ -2269,7 +2269,7 @@ class SchemaTypeTest(fixtures.TestBase): type_ = self.WrapEnum("a", "b", "c", name="foo") y = Column("y", type_) - y_copy = y.copy() + y_copy = y._copy() t1 = Table("x", m, y_copy) is_true(y_copy.type._create_events) @@ -2287,7 +2287,7 @@ class SchemaTypeTest(fixtures.TestBase): type_ = self.WrapEnum("a", "b", "c", name="foo", native_enum=False) y = Column("y", type_) - y_copy = y.copy() + y_copy = y._copy() t1 = Table("x", m, y_copy) is_true(y_copy.type._create_events) @@ -2307,7 +2307,7 @@ class SchemaTypeTest(fixtures.TestBase): create_constraint=False, ) y = Column("y", type_) - y_copy = y.copy() + y_copy = y._copy() Table("x", m, y_copy) is_false(y_copy.type.create_constraint) @@ -2317,7 +2317,7 @@ class SchemaTypeTest(fixtures.TestBase): type_ = self.WrapBoolean() y = Column("y", type_) - y_copy = y.copy() + y_copy = y._copy() Table("x", m, y_copy) is_true(y_copy.type._create_events) @@ -2327,7 +2327,7 @@ class SchemaTypeTest(fixtures.TestBase): type_ = self.WrapBoolean(create_constraint=False) y = Column("y", type_) - y_copy = y.copy() + y_copy = y._copy() Table("x", m, y_copy) is_false(y_copy.type.create_constraint) @@ -2946,7 +2946,7 @@ class ConstraintTest(fixtures.TestBase): def test_copy_doesnt_reference(self): t1, t2, t3 = self._single_fixture() - a2 = t2.c.a.copy() + a2 = t2.c.a._copy() assert not a2.references(t1.c.a) assert not a2.references(t1.c.b) @@ -3432,7 +3432,7 @@ class ConstraintTest(fixtures.TestBase): m = MetaData() t = Table("tbl", m, Column("a", Integer), Column("b", Integer)) ck = CheckConstraint(t.c.a > 5) - ck2 = ck.copy() + ck2 = ck._copy() assert ck in t.constraints assert ck2 not in t.constraints -- 2.47.2