- rework ColumnCollection to no longer persist "all_col_set"; we don't

need this collection except in the extend/update uses where we
create it ad-hoc.  simplifies pickling.  Compatibility with 1.0
should be OK as ColumnColleciton uses __getstate__ in any case
and the __setstate__ contract hasn't changed.
- Fixed bug in :class:`.Table` metadata construct which appeared
around the 0.9 series where adding columns to a :class:`.Table`
that was unpickled would fail to correctly establish the
:class:`.Column` within the 'c' collection, leading to issues in
areas such as ORM configuration.   This could impact use cases such
as ``extend_existing`` and others.  fixes #3632

(cherry picked from commit 8163de4cc9)
This commit is contained in:
Mike Bayer
2016-01-26 16:41:26 -05:00
parent 7d70dfd412
commit c7ddf26dd2
3 changed files with 39 additions and 20 deletions
+11
View File
@@ -19,6 +19,17 @@
:version: 1.0.12
:released:
.. change::
:tags: bug, sql
:tickets: 3632
Fixed bug in :class:`.Table` metadata construct which appeared
around the 0.9 series where adding columns to a :class:`.Table`
that was unpickled would fail to correctly establish the
:class:`.Column` within the 'c' collection, leading to issues in
areas such as ORM configuration. This could impact use cases such
as ``extend_existing`` and others.
.. change::
:tags: bug, py3k
:tickets: 3625
+9 -20
View File
@@ -449,11 +449,10 @@ class ColumnCollection(util.OrderedProperties):
"""
__slots__ = '_all_col_set', '_all_columns'
__slots__ = '_all_columns'
def __init__(self, *columns):
super(ColumnCollection, self).__init__()
object.__setattr__(self, '_all_col_set', util.column_set())
object.__setattr__(self, '_all_columns', [])
for c in columns:
self.add(c)
@@ -482,14 +481,11 @@ class ColumnCollection(util.OrderedProperties):
other = self[column.name]
if other.name == other.key:
remove_col = other
self._all_col_set.remove(other)
del self._data[other.key]
if column.key in self._data:
remove_col = self._data[column.key]
self._all_col_set.remove(remove_col)
self._all_col_set.add(column)
self._data[column.key] = column
if remove_col is not None:
self._all_columns[:] = [column if c is remove_col
@@ -534,7 +530,6 @@ class ColumnCollection(util.OrderedProperties):
# in a _make_proxy operation
util.memoized_property.reset(value, "proxy_set")
self._all_col_set.add(value)
self._all_columns.append(value)
self._data[key] = value
@@ -543,22 +538,20 @@ class ColumnCollection(util.OrderedProperties):
def remove(self, column):
del self._data[column.key]
self._all_col_set.remove(column)
self._all_columns[:] = [
c for c in self._all_columns if c is not column]
def update(self, iter):
cols = list(iter)
all_col_set = set(self._all_columns)
self._all_columns.extend(
c for label, c in cols if c not in self._all_col_set)
self._all_col_set.update(c for label, c in cols)
c for label, c in cols if c not in all_col_set)
self._data.update((label, c) for label, c in cols)
def extend(self, iter):
cols = list(iter)
self._all_columns.extend(c for c in cols if c not in
self._all_col_set)
self._all_col_set.update(cols)
all_col_set = set(self._all_columns)
self._all_columns.extend(c for c in cols if c not in all_col_set)
self._data.update((c.key, c) for c in cols)
__hash__ = None
@@ -584,22 +577,18 @@ class ColumnCollection(util.OrderedProperties):
def __setstate__(self, state):
object.__setattr__(self, '_data', state['_data'])
object.__setattr__(self, '_all_columns', state['_all_columns'])
object.__setattr__(
self, '_all_col_set', util.column_set(state['_all_columns']))
def contains_column(self, col):
# this has to be done via set() membership
return col in self._all_col_set
existing = self._data.get(col.key)
return existing is not None and hash(existing) == hash(col)
def as_immutable(self):
return ImmutableColumnCollection(
self._data, self._all_col_set, self._all_columns)
return ImmutableColumnCollection(self._data, self._all_columns)
class ImmutableColumnCollection(util.ImmutableProperties, ColumnCollection):
def __init__(self, data, colset, all_columns):
def __init__(self, data, all_columns):
util.ImmutableProperties.__init__(self, data)
object.__setattr__(self, '_all_col_set', colset)
object.__setattr__(self, '_all_columns', all_columns)
extend = remove = util.ImmutableProperties._immutable
+19
View File
@@ -1257,6 +1257,25 @@ class TableTest(fixtures.TestBase, AssertsCompiledSQL):
assign2
)
def test_c_mutate_after_unpickle(self):
m = MetaData()
y = Column('y', Integer)
t1 = Table('t', m, Column('x', Integer), y)
t2 = pickle.loads(pickle.dumps(t1))
z = Column('z', Integer)
g = Column('g', Integer)
t2.append_column(z)
is_(t1.c.contains_column(y), True)
is_(t2.c.contains_column(y), False)
y2 = t2.c.y
is_(t2.c.contains_column(y2), True)
is_(t2.c.contains_column(z), True)
is_(t2.c.contains_column(g), False)
def test_autoincrement_replace(self):
m = MetaData()