.. 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
"""
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):
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):
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):
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
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)
_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):
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):
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()
c.info['bar'] = 'zip'
assert c.info['bar'] == 'zip'
-
class CatchAllEventsTest(fixtures.TestBase):
def teardown(self):