[Zope-Checkins] CVS: StandaloneZODB/ZODB - PersistentMapping.py:1.13.2.3
Jeremy Hylton
jeremy@zope.com
Fri, 30 Nov 2001 13:26:01 -0500
Update of /cvs-repository/StandaloneZODB/ZODB
In directory cvs.zope.org:/tmp/cvs-serv6306
Modified Files:
Tag: StandaloneZODB-1_0-branch
PersistentMapping.py
Log Message:
Merge in new __getstate__() and __setstate__() from the trunk.
=== StandaloneZODB/ZODB/PersistentMapping.py 1.13.2.2 => 1.13.2.3 ===
changes are registered. As a side effect, mapping objects may be
subclassed.
+
+ A subclass of PersistentMapping or any code that adds new
+ attributes should not create an attribute named _container. This
+ is reserved for backwards compatibility reasons.
"""
+ # UserDict provides all of the mapping behavior. The
+ # PersistentMapping class is responsible marking the persistent
+ # state as changed when a method actually changes the state. At
+ # the mapping API evolves, we may need to add more methods here.
+
__super_delitem = UserDict.__delitem__
__super_setitem = UserDict.__setitem__
__super_clear = UserDict.clear
@@ -31,21 +40,6 @@
__super_setdefault = UserDict.setdefault
__super_popitem = UserDict.popitem
- def __setstate__(self, state):
- # The old PersistentMapping used _container to hold the data.
- # We need to make the current code work with objects pickled
- # using the old code. Unfortunately, this forces us to expose
- # the rep of UserDict, because __init__() won't be called when
- # a pickled object is being loaded.
- if state.has_key('_container'):
- assert not state.has_key('data'), \
- ("object state has _container and data attributes: %s"
- % repr(state))
- self.data = state['_container']
- del state['_container']
- for k, v in state.items():
- self.__dict__[k] = v
-
def __delitem__(self, key):
self.__super_delitem(key)
self._p_changed = 1
@@ -73,3 +67,31 @@
def popitem(self):
self._p_changed = 1
return self.__super_popitem()
+
+ # If the internal representation of PersistentMapping changes,
+ # it causes compatibility problems for pickles generated by
+ # different versions of the code. Compatibility works in both
+ # directions, because an application may want to share a database
+ # between applications using different versions of the code.
+
+ # Effectively, the original rep is part of the "API." To provide
+ # full compatibility, the getstate and setstate must read and
+ # right objects using the old rep.
+
+ # As a result, the PersistentMapping must save and restore the
+ # actual internal dictionary using the name _container.
+
+ def __getstate__(self):
+ state = {}
+ state.update(self.__dict__)
+ state['_container'] = state['data']
+ del state['data']
+ return state
+
+ def __setstate__(self, state):
+ if state.has_key('_container'):
+ self.data = state['_container']
+ del state['_container']
+ elif not state.has_key('data'):
+ self.data = {}
+ self.__dict__.update(state)