[Sqlalchemy-tickets] Issue #3297: Custom MutableSet (similar to MutableDict) not pickling (zzzeek/s
Brought to you by:
zzzeek
|
From: Eoghan M. <iss...@bi...> - 2015-01-23 13:06:51
|
New issue 3297: Custom MutableSet (similar to MutableDict) not pickling https://bitbucket.org/zzzeek/sqlalchemy/issue/3297/custom-mutableset-similar-to-mutabledict Eoghan Murray: I've created a MutableSet class, closely following the MutableDict class in ext.mutable. Unfortunately it doesn't pickle correctly and I can't figure out what the problem is. ``` #!python from sqlalchemy import * from sqlalchemy.ext.mutable import Mutable, MutableDict test_table = Table('test_table, metadata, Column('test_pk', String(40), primary_key=True), Column('as_dict', MutableDict.as_mutable(JsonType)), Column('as_set', MutableSet.as_mutable(JsonType)) ``` my error message after using pickle.dumps on an object that contains the MutableSet column. Note the 'remove' function mentioned in the error is to do with _parents WeakRef rather than MutableSet.remove) ``` #!python File "/usr/lib/python2.7/pickle.py", line 748, in save_global (obj, module, name)) PicklingError: Can't pickle <function remove at 0xb48a041c>: it's not found as weakref.remove ``` And the MutableSet class (and JsonType supporting class - included for completeness) ``` #!python class MutableSet(Mutable, set): @classmethod def coerce(cls, key, value): "Convert plain sets to MutableSet." if not isinstance(value, MutableSet): if isinstance(value, set): return MutableSet(value) elif isinstance(value, dict): return MutableDict(value) # this call will raise ValueError return Mutable.coerce(key, value) else: return value def __getstate__(self): return set(self) def __setstate__(self, state): self.update(state) def update(self, *args): set.update(self, *args, **kwargs) self.changed() def intersection_update(self, *args): set.intersection_update(self, *args) self.changed() def difference_update(self, *args): set.difference_update(self, *args) self.changed() def symmetric_difference_update(self, *args): set.symmetric_difference_update(self, *args) self.changed() def add(self, elem): set.add(self, elem) self.changed() def remove(self, elem): set.remove(self, elem) self.changed() def discard(self, elem): set.discard(self, elem) self.changed() def pop(self): set.pop(self) self.changed() def clear(self): set.clear(self) self.changed() ``` ``` #!python class JsonType(types.TypeDecorator): impl = types.Unicode def process_bind_param(self, value, engine): import jsonpickle if isinstance(value, MutableList): value = [v for v in value] if isinstance(value, MutableDict): value = dict(value) if isinstance(value, MutableSet): value = set(value) return unicode(jsonpickle.encode(value)) def process_result_value(self, value, engine): import jsonpickle if value: return jsonpickle.decode(value) else: return {} def copy_value(self, value): return deepcopy(value) def compare_values(self, x, y): return x == y ``` Responsible: zzzeek |