Commit abc8eb11 authored by Jeremy Hylton's avatar Jeremy Hylton

Simplify and cleanup implementation of PersistentMapping.

The implementation now defers all implementation decisions to UserDict
and merely handles updates to _p_changed in the PersistentMapping
implementation.  This change simplifies the implementation and ensures
that it implements all the new methods of dictionaries like popitem()
and setdefault().

There is one (important?) behavioral change:  The old implementation
of the keys() method did not return keys that were strings starting
with underscore.  This behavior was undocumented and could lead to
problems for implementations that expect keys() to working like a
regular mapping.

    The feature was removed after verifying that the Zope test suite
    does not depend on this behavior.

An internal implementation change is that the PersistentMapping does
not keep a copy of the keys() of the dict.  It simplifies the
implementation a lot to remove the cacheing and the benefit is
unclear.  It only benefits applications that call keys() frequently
without modifying the dict.  And it requires that two copies of the
list exist for each call to keys() which may require a lot of space.
parent 4f769306
...@@ -85,79 +85,54 @@ ...@@ -85,79 +85,54 @@
__doc__='''Python implementation of persistent base types __doc__='''Python implementation of persistent base types
$Id: PersistentMapping.py,v 1.11 2001/08/16 17:25:41 jim Exp $''' $Id: PersistentMapping.py,v 1.12 2001/11/27 21:38:06 jeremy Exp $'''
__version__='$Revision: 1.11 $'[11:-2] __version__='$Revision: 1.12 $'[11:-2]
import Persistence import Persistence
import types import types
from UserDict import UserDict
_marker=[] _marker=[]
class PersistentMapping(Persistence.Persistent):
class PersistentMapping(UserDict, Persistence.Persistent):
"""A persistent wrapper for mapping objects. """A persistent wrapper for mapping objects.
This class allows wrapping of mapping objects so that This class allows wrapping of mapping objects so that object
object changes are registered. As a side effect, changes are registered. As a side effect, mapping objects may be
mapping objects may be subclassed. subclassed.
""" """
def __init__(self,container=None): __super_delitem = UserDict.__delitem__
if container is None: container={} __super_setitem = UserDict.__setitem__
self._container=container __super_clear = UserDict.clear
__super_update = UserDict.update
__super_setdefault = UserDict.setdefault
__super_popitem = UserDict.popitem
def __delitem__(self, key): def __delitem__(self, key):
del self._container[key] self.__super_delitem(key)
try: del self._v_keys
except: pass
self.__changed__(1) self.__changed__(1)
def __getitem__(self, key):
return self._container[key]
def __len__(self): return len(self._container)
def __setitem__(self, key, v): def __setitem__(self, key, v):
self._container[key]=v self.__super_setitem(key, v)
try: del self._v_keys
except: pass
self.__changed__(1) self.__changed__(1)
def clear(self): def clear(self):
self._container.clear() self.__super_clear()
self._p_changed=1 self._p_changed = 1
if hasattr(self,'_v_keys'): del self._v_keys
def copy(self): return self.__class__(self._container.copy())
def get(self, key, default=_marker):
if default is _marker:
return self._container.get(key)
else:
return self._container.get(key, default)
def has_key(self,key): return self._container.has_key(key)
def items(self):
return map(lambda k, d=self: (k,d[k]), self.keys())
def keys(self):
try: return list(self._v_keys) # return a copy (Collector 2283)
except: pass
keys=self._v_keys=filter(
lambda k: not isinstance(k,types.StringType) or k[:1]!='_',
self._container.keys())
keys.sort()
return list(keys)
def update(self, b): def update(self, b):
a=self._container self.__super_update(b)
for k, v in b.items(): a[k] = v self._p_changed = 1
try: del self._v_keys
except: pass def setdefault(self, key, failobj=None):
self._p_changed=1 # We could inline all of UserDict's implementation into the
# method here, but I'd rather not depend at all on the
def values(self): # implementation in UserDict (simple as it is).
return map(lambda k, d=self: d[k], self.keys()) if not self.has_key(key):
self._p_changed = 1
def __cmp__(self,other): return self.__super_setdefault(key, failobj)
return cmp(self._container, other._container)
def popitem(self):
self._p_changed = 1
return self.__super_popitem()
...@@ -84,8 +84,8 @@ ...@@ -84,8 +84,8 @@
############################################################################## ##############################################################################
"""Database objects """Database objects
$Id: DB.py,v 1.34 2001/11/06 17:52:38 jeremy Exp $""" $Id: DB.py,v 1.35 2001/11/27 21:38:06 jeremy Exp $"""
__version__='$Revision: 1.34 $'[11:-2] __version__='$Revision: 1.35 $'[11:-2]
import cPickle, cStringIO, sys, POSException, UndoLogCompatible import cPickle, cStringIO, sys, POSException, UndoLogCompatible
from Connection import Connection from Connection import Connection
...@@ -144,15 +144,20 @@ class DB(UndoLogCompatible.UndoLogCompatible): ...@@ -144,15 +144,20 @@ class DB(UndoLogCompatible.UndoLogCompatible):
self._storage=storage self._storage=storage
storage.registerDB(self, None) storage.registerDB(self, None)
if not hasattr(storage,'tpc_vote'): storage.tpc_vote=lambda *args: None if not hasattr(storage,'tpc_vote'): storage.tpc_vote=lambda *args: None
try: storage.load('\0\0\0\0\0\0\0\0','') try:
except: storage.load('\0\0\0\0\0\0\0\0','')
except KeyError:
# Create the database's root in the storage if it doesn't exist
import PersistentMapping import PersistentMapping
file=cStringIO.StringIO() root = PersistentMapping.PersistentMapping()
p=cPickle.Pickler(file,1) # Manually create a pickle for the root to put in the storage.
p.dump((PersistentMapping.PersistentMapping,None)) # The pickle must be in the special ZODB format.
p.dump({'_container': {}}) file = cStringIO.StringIO()
t=Transaction() p = cPickle.Pickler(file, 1)
t.description='initial database creation' p.dump((root.__class__, None))
p.dump(root.__getstate__())
t = Transaction()
t.description = 'initial database creation'
storage.tpc_begin(t) storage.tpc_begin(t)
storage.store('\0\0\0\0\0\0\0\0', None, file.getvalue(), '', t) storage.store('\0\0\0\0\0\0\0\0', None, file.getvalue(), '', t)
storage.tpc_vote(t) storage.tpc_vote(t)
......
...@@ -85,79 +85,54 @@ ...@@ -85,79 +85,54 @@
__doc__='''Python implementation of persistent base types __doc__='''Python implementation of persistent base types
$Id: PersistentMapping.py,v 1.11 2001/08/16 17:25:41 jim Exp $''' $Id: PersistentMapping.py,v 1.12 2001/11/27 21:38:06 jeremy Exp $'''
__version__='$Revision: 1.11 $'[11:-2] __version__='$Revision: 1.12 $'[11:-2]
import Persistence import Persistence
import types import types
from UserDict import UserDict
_marker=[] _marker=[]
class PersistentMapping(Persistence.Persistent):
class PersistentMapping(UserDict, Persistence.Persistent):
"""A persistent wrapper for mapping objects. """A persistent wrapper for mapping objects.
This class allows wrapping of mapping objects so that This class allows wrapping of mapping objects so that object
object changes are registered. As a side effect, changes are registered. As a side effect, mapping objects may be
mapping objects may be subclassed. subclassed.
""" """
def __init__(self,container=None): __super_delitem = UserDict.__delitem__
if container is None: container={} __super_setitem = UserDict.__setitem__
self._container=container __super_clear = UserDict.clear
__super_update = UserDict.update
__super_setdefault = UserDict.setdefault
__super_popitem = UserDict.popitem
def __delitem__(self, key): def __delitem__(self, key):
del self._container[key] self.__super_delitem(key)
try: del self._v_keys
except: pass
self.__changed__(1) self.__changed__(1)
def __getitem__(self, key):
return self._container[key]
def __len__(self): return len(self._container)
def __setitem__(self, key, v): def __setitem__(self, key, v):
self._container[key]=v self.__super_setitem(key, v)
try: del self._v_keys
except: pass
self.__changed__(1) self.__changed__(1)
def clear(self): def clear(self):
self._container.clear() self.__super_clear()
self._p_changed=1 self._p_changed = 1
if hasattr(self,'_v_keys'): del self._v_keys
def copy(self): return self.__class__(self._container.copy())
def get(self, key, default=_marker):
if default is _marker:
return self._container.get(key)
else:
return self._container.get(key, default)
def has_key(self,key): return self._container.has_key(key)
def items(self):
return map(lambda k, d=self: (k,d[k]), self.keys())
def keys(self):
try: return list(self._v_keys) # return a copy (Collector 2283)
except: pass
keys=self._v_keys=filter(
lambda k: not isinstance(k,types.StringType) or k[:1]!='_',
self._container.keys())
keys.sort()
return list(keys)
def update(self, b): def update(self, b):
a=self._container self.__super_update(b)
for k, v in b.items(): a[k] = v self._p_changed = 1
try: del self._v_keys
except: pass def setdefault(self, key, failobj=None):
self._p_changed=1 # We could inline all of UserDict's implementation into the
# method here, but I'd rather not depend at all on the
def values(self): # implementation in UserDict (simple as it is).
return map(lambda k, d=self: d[k], self.keys()) if not self.has_key(key):
self._p_changed = 1
def __cmp__(self,other): return self.__super_setdefault(key, failobj)
return cmp(self._container, other._container)
def popitem(self):
self._p_changed = 1
return self.__super_popitem()
...@@ -85,79 +85,54 @@ ...@@ -85,79 +85,54 @@
__doc__='''Python implementation of persistent base types __doc__='''Python implementation of persistent base types
$Id: mapping.py,v 1.11 2001/08/16 17:25:41 jim Exp $''' $Id: mapping.py,v 1.12 2001/11/27 21:38:06 jeremy Exp $'''
__version__='$Revision: 1.11 $'[11:-2] __version__='$Revision: 1.12 $'[11:-2]
import Persistence import Persistence
import types import types
from UserDict import UserDict
_marker=[] _marker=[]
class PersistentMapping(Persistence.Persistent):
class PersistentMapping(UserDict, Persistence.Persistent):
"""A persistent wrapper for mapping objects. """A persistent wrapper for mapping objects.
This class allows wrapping of mapping objects so that This class allows wrapping of mapping objects so that object
object changes are registered. As a side effect, changes are registered. As a side effect, mapping objects may be
mapping objects may be subclassed. subclassed.
""" """
def __init__(self,container=None): __super_delitem = UserDict.__delitem__
if container is None: container={} __super_setitem = UserDict.__setitem__
self._container=container __super_clear = UserDict.clear
__super_update = UserDict.update
__super_setdefault = UserDict.setdefault
__super_popitem = UserDict.popitem
def __delitem__(self, key): def __delitem__(self, key):
del self._container[key] self.__super_delitem(key)
try: del self._v_keys
except: pass
self.__changed__(1) self.__changed__(1)
def __getitem__(self, key):
return self._container[key]
def __len__(self): return len(self._container)
def __setitem__(self, key, v): def __setitem__(self, key, v):
self._container[key]=v self.__super_setitem(key, v)
try: del self._v_keys
except: pass
self.__changed__(1) self.__changed__(1)
def clear(self): def clear(self):
self._container.clear() self.__super_clear()
self._p_changed=1 self._p_changed = 1
if hasattr(self,'_v_keys'): del self._v_keys
def copy(self): return self.__class__(self._container.copy())
def get(self, key, default=_marker):
if default is _marker:
return self._container.get(key)
else:
return self._container.get(key, default)
def has_key(self,key): return self._container.has_key(key)
def items(self):
return map(lambda k, d=self: (k,d[k]), self.keys())
def keys(self):
try: return list(self._v_keys) # return a copy (Collector 2283)
except: pass
keys=self._v_keys=filter(
lambda k: not isinstance(k,types.StringType) or k[:1]!='_',
self._container.keys())
keys.sort()
return list(keys)
def update(self, b): def update(self, b):
a=self._container self.__super_update(b)
for k, v in b.items(): a[k] = v self._p_changed = 1
try: del self._v_keys
except: pass def setdefault(self, key, failobj=None):
self._p_changed=1 # We could inline all of UserDict's implementation into the
# method here, but I'd rather not depend at all on the
def values(self): # implementation in UserDict (simple as it is).
return map(lambda k, d=self: d[k], self.keys()) if not self.has_key(key):
self._p_changed = 1
def __cmp__(self,other): return self.__super_setdefault(key, failobj)
return cmp(self._container, other._container)
def popitem(self):
self._p_changed = 1
return self.__super_popitem()
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment