]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
- The :meth:`.Table.tometadata` method now produces copies of
authorMike Bayer <mike_mp@zzzcomputing.com>
Sat, 19 Oct 2013 00:01:45 +0000 (20:01 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Sat, 19 Oct 2013 00:01:45 +0000 (20:01 -0400)
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]

doc/build/changelog/changelog_09.rst
lib/sqlalchemy/sql/schema.py
test/sql/test_metadata.py

index 4e7b4e6f45bb12fee6fcb781027f80b741e82a57..51ba9225f6077cb1433c898d8d324fdc425b2436 100644 (file)
 .. 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
index 90c4fb0dd3191d5628147e3bc6e4824787c4ee3a..40bd5b90a1cdf9f881c6f8c6db40f201a2371675 100644 (file)
@@ -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):
index 883d9308c0acf34d7a69a407de3f0289153bf415..d0a79a7bb7ef19e9e466f7e98937582ea02b3a50 100644 (file)
@@ -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):