From: Mike Bayer Date: Sat, 19 Oct 2013 00:01:45 +0000 (-0400) Subject: - The :meth:`.Table.tometadata` method now produces copies of X-Git-Tag: rel_0_9_0b1~28 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=73669c7284548d0e5ab2147f66174c301e732650;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git - The :meth:`.Table.tometadata` method now produces copies of all :attr:`.SchemaItem.info` dictionaries from all :class:`.SchemaItem` objects within the structure including columns, constraints, foreign keys, etc. As these dictionaries are copies, they are independent of the original dictionary. Previously, only the ``.info`` dictionary of :class:`.Column` was transferred within this operation, and it was only linked in place, not copied. [ticket:2716] --- diff --git a/doc/build/changelog/changelog_09.rst b/doc/build/changelog/changelog_09.rst index 4e7b4e6f45..51ba9225f6 100644 --- a/doc/build/changelog/changelog_09.rst +++ b/doc/build/changelog/changelog_09.rst @@ -12,6 +12,18 @@ .. changelog:: :version: 0.9.0 + .. change:: + :tags: feature, sql + :tickets: 2716 + + The :meth:`.Table.tometadata` method now produces copies of + all :attr:`.SchemaItem.info` dictionaries from all :class:`.SchemaItem` + objects within the structure including columns, constraints, + foreign keys, etc. As these dictionaries + are copies, they are independent of the original dictionary. + Previously, only the ``.info`` dictionary of :class:`.Column` was transferred + within this operation, and it was only linked in place, not copied. + .. change:: :tags: feature, postgresql :tickets: 2840 diff --git a/lib/sqlalchemy/sql/schema.py b/lib/sqlalchemy/sql/schema.py index 90c4fb0dd3..40bd5b90a1 100644 --- a/lib/sqlalchemy/sql/schema.py +++ b/lib/sqlalchemy/sql/schema.py @@ -108,6 +108,11 @@ class SchemaItem(SchemaEventTarget, visitors.Visitable): """ return {} + def _schema_item_copy(self, schema_item): + if 'info' in self.__dict__: + schema_item.info = self.info.copy() + schema_item.dispatch._update(self.dispatch) + return schema_item class Table(SchemaItem, TableClause): @@ -718,8 +723,7 @@ class Table(SchemaItem, TableClause): unique=index.unique, *[table.c[col] for col in index.columns.keys()], **index.kwargs) - table.dispatch._update(self.dispatch) - return table + return self._schema_item_copy(table) class Column(SchemaItem, ColumnClause): @@ -1183,12 +1187,10 @@ class Column(SchemaItem, ColumnClause): server_default=self.server_default, onupdate=self.onupdate, server_onupdate=self.server_onupdate, - info=self.info, doc=self.doc, *args ) - c.dispatch._update(self.dispatch) - return c + return self._schema_item_copy(c) def _make_proxy(self, selectable, name=None, key=None, name_is_truncatable=False, **kw): @@ -1384,8 +1386,7 @@ class ForeignKey(SchemaItem): link_to_name=self.link_to_name, match=self.match ) - fk.dispatch._update(self.dispatch) - return fk + return self._schema_item_copy(fk) def _get_colspec(self, schema=None): """Return a string based 'column specification' for this @@ -2228,8 +2229,7 @@ class ColumnCollectionConstraint(ColumnCollectionMixin, Constraint): def copy(self, **kw): c = self.__class__(name=self.name, deferrable=self.deferrable, initially=self.initially, *self.columns.keys()) - c.dispatch._update(self.dispatch) - return c + return self._schema_item_copy(c) def contains_column(self, col): return self.columns.contains_column(col) @@ -2310,8 +2310,7 @@ class CheckConstraint(Constraint): _create_rule=self._create_rule, table=target_table, _autoattach=False) - c.dispatch._update(self.dispatch) - return c + return self._schema_item_copy(c) class ForeignKeyConstraint(Constraint): @@ -2480,8 +2479,11 @@ class ForeignKeyConstraint(Constraint): link_to_name=self.link_to_name, match=self.match ) - fkc.dispatch._update(self.dispatch) - return fkc + for self_fk, other_fk in zip( + self._elements.values(), + fkc._elements.values()): + self_fk._schema_item_copy(other_fk) + return self._schema_item_copy(fkc) class PrimaryKeyConstraint(ColumnCollectionConstraint): diff --git a/test/sql/test_metadata.py b/test/sql/test_metadata.py index 883d9308c0..d0a79a7bb7 100644 --- a/test/sql/test_metadata.py +++ b/test/sql/test_metadata.py @@ -494,6 +494,47 @@ class MetaDataTest(fixtures.TestBase, ComparesTables): eq_(str(table_c.join(table2_c).onclause), 'myschema.mytable.myid = myschema.othertable.myid') + def test_tometadata_copy_info(self): + m = MetaData() + fk = ForeignKey('t2.id') + c = Column('c', Integer, fk) + ck = CheckConstraint('c > 5') + t = Table('t', m, c, ck) + + m.info['minfo'] = True + fk.info['fkinfo'] = True + c.info['cinfo'] = True + ck.info['ckinfo'] = True + t.info['tinfo'] = True + t.primary_key.info['pkinfo'] = True + fkc = [const for const in t.constraints if + isinstance(const, ForeignKeyConstraint)][0] + fkc.info['fkcinfo'] = True + + m2 = MetaData() + t2 = t.tometadata(m2) + + m.info['minfo'] = False + fk.info['fkinfo'] = False + c.info['cinfo'] = False + ck.info['ckinfo'] = False + t.primary_key.info['pkinfo'] = False + fkc.info['fkcinfo'] = False + + eq_(m2.info, {}) + eq_(t2.info, {"tinfo": True}) + eq_(t2.c.c.info, {"cinfo": True}) + eq_(list(t2.c.c.foreign_keys)[0].info, {"fkinfo": True}) + eq_(t2.primary_key.info, {"pkinfo": True}) + + fkc2 = [const for const in t2.constraints + if isinstance(const, ForeignKeyConstraint)][0] + eq_(fkc2.info, {"fkcinfo": True}) + + ck2 = [const for const in + t2.constraints if isinstance(const, CheckConstraint)][0] + eq_(ck2.info, {"ckinfo": True}) + def test_tometadata_kwargs(self): meta = MetaData() @@ -1877,7 +1918,6 @@ class ColumnOptionsTest(fixtures.TestBase): c.info['bar'] = 'zip' assert c.info['bar'] == 'zip' - class CatchAllEventsTest(fixtures.TestBase): def teardown(self):