[Zodb-checkins] SVN: ZODB/trunk/src/ Officially deprecated PersistentDict
Jim Fulton
jim at zope.com
Sat Aug 22 09:36:28 EDT 2009
Log message for revision 103082:
Officially deprecated PersistentDict
(https://bugs.launchpad.net/zodb/+bug/400775)
Also, stop producing legacy PersistentMapping state, while still
accepting it.
Changed:
U ZODB/trunk/src/CHANGES.txt
U ZODB/trunk/src/ZEO/tests/testZEO.py
U ZODB/trunk/src/ZODB/FileStorage/iterator.test
U ZODB/trunk/src/ZODB/scripts/fstail.txt
U ZODB/trunk/src/ZODB/tests/testCache.py
U ZODB/trunk/src/ZODB/tests/testConnectionSavepoint.py
U ZODB/trunk/src/ZODB/tests/testFileStorage.py
U ZODB/trunk/src/ZODB/tests/test_fsdump.py
U ZODB/trunk/src/ZODB/tests/testfsoids.py
U ZODB/trunk/src/persistent/dict.py
U ZODB/trunk/src/persistent/mapping.py
U ZODB/trunk/src/persistent/tests/test_mapping.py
-=-
Modified: ZODB/trunk/src/CHANGES.txt
===================================================================
--- ZODB/trunk/src/CHANGES.txt 2009-08-22 12:21:41 UTC (rev 103081)
+++ ZODB/trunk/src/CHANGES.txt 2009-08-22 13:36:27 UTC (rev 103082)
@@ -9,7 +9,11 @@
----------
- The runzeo script didn't work without a configuration file.
+ (https://bugs.launchpad.net/zodb/+bug/410571)
+- Officially deprecated PersistentDict
+ (https://bugs.launchpad.net/zodb/+bug/400775)
+
3.9.0b5 (2009-08-06)
====================
Modified: ZODB/trunk/src/ZEO/tests/testZEO.py
===================================================================
--- ZODB/trunk/src/ZEO/tests/testZEO.py 2009-08-22 12:21:41 UTC (rev 103081)
+++ ZODB/trunk/src/ZEO/tests/testZEO.py 2009-08-22 13:36:27 UTC (rev 103082)
@@ -774,7 +774,7 @@
>>> from ZEO.StorageServer import StorageServer, ZEOStorage
>>> from ZODB.FileStorage import FileStorage
>>> from ZODB.DB import DB
- >>> from persistent.dict import PersistentDict
+ >>> from persistent.mapping import PersistentMapping
>>> from transaction import commit
>>> fs1 = FileStorage('t1.fs')
>>> fs2 = FileStorage('t2.fs')
@@ -789,17 +789,17 @@
>>> commit()
>>> o1 = conn1.root()
>>> for i in range(10):
- ... o1.x = PersistentDict(); o1 = o1.x
+ ... o1.x = PersistentMapping(); o1 = o1.x
... commit()
>>> last = fs1.lastTransaction()
>>> for i in range(5):
- ... o1.x = PersistentDict(); o1 = o1.x
+ ... o1.x = PersistentMapping(); o1 = o1.x
... commit()
>>> o2 = conn2.root()
>>> for i in range(20):
- ... o2.x = PersistentDict(); o2 = o2.x
+ ... o2.x = PersistentMapping(); o2 = o2.x
... commit()
>>> trans, oids = s1.getInvalidations(last)
@@ -822,14 +822,14 @@
>>> from ZEO.StorageServer import StorageServer, ZEOStorage
>>> from ZODB.FileStorage import FileStorage
>>> from ZODB.DB import DB
- >>> from persistent.dict import PersistentDict
+ >>> from persistent.mapping import PersistentMapping
>>> fs = FileStorage('t.fs')
>>> db = DB(fs)
>>> conn = db.open()
>>> from transaction import commit
>>> last = []
>>> for i in range(100):
- ... conn.root()[i] = PersistentDict()
+ ... conn.root()[i] = PersistentMapping()
... commit()
... last.append(fs.lastTransaction())
>>> db.close()
@@ -898,7 +898,7 @@
>>> db = DB(st); conn = db.open()
>>> ob = conn.root()
>>> for i in range(5):
- ... ob.x = PersistentDict(); ob = ob.x
+ ... ob.x = PersistentMapping(); ob = ob.x
... commit()
... last.append(fs.lastTransaction())
Modified: ZODB/trunk/src/ZODB/FileStorage/iterator.test
===================================================================
--- ZODB/trunk/src/ZODB/FileStorage/iterator.test 2009-08-22 12:21:41 UTC (rev 103081)
+++ ZODB/trunk/src/ZODB/FileStorage/iterator.test 2009-08-22 13:36:27 UTC (rev 103082)
@@ -66,12 +66,12 @@
True
>>> it = ZODB.FileStorage.FileIterator('data.fs', tids[70])
- Scan backward data.fs:118274 looking for '\x03z\xbd\xd8\xed\xa7>\xcc'
+ Scan backward data.fs:117080 looking for '\x03z\xbd\xd8\xed\xa7>\xcc'
>>> it.next().tid == tids[70]
True
>>> it = ZODB.FileStorage.FileIterator('data.fs', tids[-2])
- Scan backward data.fs:118274 looking for '\x03z\xbd\xd8\xfa\x06\xd0\xcc'
+ Scan backward data.fs:117080 looking for '\x03z\xbd\xd8\xfa\x06\xd0\xcc'
>>> it.next().tid == tids[-2]
True
@@ -95,12 +95,12 @@
True
>>> it = ZODB.FileStorage.FileIterator('data.fs', tids[50], pos=poss[50])
- Scan backward data.fs:36542 looking for '\x03z\xbd\xd8\xe5\x1e\xb6\xcc'
+ Scan backward data.fs:35936 looking for '\x03z\xbd\xd8\xe5\x1e\xb6\xcc'
>>> it.next().tid == tids[50]
True
>>> it = ZODB.FileStorage.FileIterator('data.fs', tids[49], pos=poss[50])
- Scan backward data.fs:36542 looking for '\x03z\xbd\xd8\xe4\xb1|\xcc'
+ Scan backward data.fs:35936 looking for '\x03z\xbd\xd8\xe4\xb1|\xcc'
>>> it.next().tid == tids[49]
True
Modified: ZODB/trunk/src/ZODB/scripts/fstail.txt
===================================================================
--- ZODB/trunk/src/ZODB/scripts/fstail.txt 2009-08-22 12:21:41 UTC (rev 103081)
+++ ZODB/trunk/src/ZODB/scripts/fstail.txt 2009-08-22 13:36:27 UTC (rev 103082)
@@ -24,10 +24,10 @@
>>> from ZODB.scripts.fstail import main
>>> main(storagefile, 5)
2007-11-10 15:18:48.543001: hash=b16422d09fabdb45d4e4325e4b42d7d6f021d3c3
- user='' description='' length=138 offset=191
+ user='' description='' length=132 offset=185
<BLANKLINE>
2007-11-10 15:18:48.543001: hash=b16422d09fabdb45d4e4325e4b42d7d6f021d3c3
- user='' description='initial database creation' length=156 offset=52
+ user='' description='initial database creation' length=150 offset=52
<BLANKLINE>
Now clean up the storage again:
Modified: ZODB/trunk/src/ZODB/tests/testCache.py
===================================================================
--- ZODB/trunk/src/ZODB/tests/testCache.py 2009-08-22 12:21:41 UTC (rev 103081)
+++ ZODB/trunk/src/ZODB/tests/testCache.py 2009-08-22 13:36:27 UTC (rev 103082)
@@ -433,7 +433,7 @@
>>> getattr(conn.root, 'z', None)
>>> conn._cache.total_estimated_size
- 128
+ 64
We add some data and the cache grows:
Modified: ZODB/trunk/src/ZODB/tests/testConnectionSavepoint.py
===================================================================
--- ZODB/trunk/src/ZODB/tests/testConnectionSavepoint.py 2009-08-22 12:21:41 UTC (rev 103081)
+++ ZODB/trunk/src/ZODB/tests/testConnectionSavepoint.py 2009-08-22 13:36:27 UTC (rev 103082)
@@ -17,7 +17,7 @@
"""
import unittest
from zope.testing import doctest
-import persistent.dict
+import persistent.mapping
import transaction
def testAddingThenModifyThenAbort():
@@ -39,7 +39,7 @@
>>> connection = db.open()
>>> root = connection.root()
- >>> ob = persistent.dict.PersistentDict()
+ >>> ob = persistent.mapping.PersistentMapping()
>>> root['ob'] = ob
>>> sp = transaction.savepoint()
>>> ob.x = 1
Modified: ZODB/trunk/src/ZODB/tests/testFileStorage.py
===================================================================
--- ZODB/trunk/src/ZODB/tests/testFileStorage.py 2009-08-22 12:21:41 UTC (rev 103081)
+++ ZODB/trunk/src/ZODB/tests/testFileStorage.py 2009-08-22 13:36:27 UTC (rev 103082)
@@ -509,10 +509,10 @@
>>> fs = ZODB.FileStorage.FileStorage('t.fs', create=True)
>>> db = DB(fs)
>>> conn = db.open()
- >>> from persistent.dict import PersistentDict
+ >>> from persistent.mapping import PersistentMapping
>>> last = []
>>> for i in range(100):
- ... conn.root()[i] = PersistentDict()
+ ... conn.root()[i] = PersistentMapping()
... transaction.commit()
... last.append(fs.lastTransaction())
Modified: ZODB/trunk/src/ZODB/tests/test_fsdump.py
===================================================================
--- ZODB/trunk/src/ZODB/tests/test_fsdump.py 2009-08-22 12:21:41 UTC (rev 103081)
+++ ZODB/trunk/src/ZODB/tests/test_fsdump.py 2009-08-22 13:36:27 UTC (rev 103082)
@@ -41,7 +41,7 @@
>>> fsdump(path) #doctest: +ELLIPSIS
Trans #00000 tid=... time=... offset=52
status=' ' user='' description='initial database creation'
- data #00000 oid=0000000000000000 size=66 class=persistent.mapping.PersistentMapping
+ data #00000 oid=0000000000000000 size=60 class=persistent.mapping.PersistentMapping
Now we see first transaction with root object.
@@ -54,10 +54,10 @@
>>> fsdump(path) #doctest: +ELLIPSIS
Trans #00000 tid=... time=... offset=52
status=' ' user='' description='initial database creation'
- data #00000 oid=0000000000000000 size=66 class=persistent.mapping.PersistentMapping
-Trans #00001 tid=... time=... offset=207
+ data #00000 oid=0000000000000000 size=60 class=persistent.mapping.PersistentMapping
+Trans #00001 tid=... time=... offset=201
status=' ' user='' description='added an OOBTree'
- data #00000 oid=0000000000000000 size=113 class=persistent.mapping.PersistentMapping
+ data #00000 oid=0000000000000000 size=107 class=persistent.mapping.PersistentMapping
data #00001 oid=0000000000000001 size=29 class=BTrees.OOBTree.OOBTree
Now we see two transactions and two changed objects.
Modified: ZODB/trunk/src/ZODB/tests/testfsoids.py
===================================================================
--- ZODB/trunk/src/ZODB/tests/testfsoids.py 2009-08-22 12:21:41 UTC (rev 103081)
+++ ZODB/trunk/src/ZODB/tests/testfsoids.py 2009-08-22 13:36:27 UTC (rev 103082)
@@ -87,17 +87,17 @@
tid user=''
tid description='initial database creation'
new revision persistent.mapping.PersistentMapping at 52
- tid 0x... offset=168 ...
+ tid 0x... offset=162 ...
tid user=''
tid description='added an OOBTree'
- new revision persistent.mapping.PersistentMapping at 207
- references 0x01 BTrees.OOBTree.OOBTree at 207
+ new revision persistent.mapping.PersistentMapping at 201
+ references 0x01 BTrees.OOBTree.OOBTree at 201
oid 0x01 BTrees.OOBTree.OOBTree 1 revision
- tid 0x... offset=168 ...
+ tid 0x... offset=162 ...
tid user=''
tid description='added an OOBTree'
- new revision BTrees.OOBTree.OOBTree at 362
- referenced by 0x00 persistent.mapping.PersistentMapping at 207
+ new revision BTrees.OOBTree.OOBTree at 350
+ referenced by 0x00 persistent.mapping.PersistentMapping at 201
So there are two revisions of oid 0 now, and the second references oid 1.
@@ -115,26 +115,26 @@
tid user=''
tid description='initial database creation'
new revision persistent.mapping.PersistentMapping at 52
- tid 0x... offset=168 ...
+ tid 0x... offset=162 ...
tid user=''
tid description='added an OOBTree'
- new revision persistent.mapping.PersistentMapping at 207
- references 0x01 BTrees.OOBTree.OOBTree at 207
- tid 0x... offset=441 ...
+ new revision persistent.mapping.PersistentMapping at 201
+ references 0x01 BTrees.OOBTree.OOBTree at 201
+ tid 0x... offset=429 ...
tid user=''
tid description='circling back to the root'
- referenced by 0x01 BTrees.OOBTree.OOBTree at 489
+ referenced by 0x01 BTrees.OOBTree.OOBTree at 477
oid 0x01 BTrees.OOBTree.OOBTree 2 revisions
- tid 0x... offset=168 ...
+ tid 0x... offset=162 ...
tid user=''
tid description='added an OOBTree'
- new revision BTrees.OOBTree.OOBTree at 362
- referenced by 0x00 persistent.mapping.PersistentMapping at 207
- tid 0x... offset=441 ...
+ new revision BTrees.OOBTree.OOBTree at 350
+ referenced by 0x00 persistent.mapping.PersistentMapping at 201
+ tid 0x... offset=429 ...
tid user=''
tid description='circling back to the root'
- new revision BTrees.OOBTree.OOBTree at 489
- references 0x00 persistent.mapping.PersistentMapping at 489
+ new revision BTrees.OOBTree.OOBTree at 477
+ references 0x00 persistent.mapping.PersistentMapping at 477
oid 0x02 <unknown> 0 revisions
this oid was not defined (no data record for it found)
Modified: ZODB/trunk/src/persistent/dict.py
===================================================================
--- ZODB/trunk/src/persistent/dict.py 2009-08-22 12:21:41 UTC (rev 103081)
+++ ZODB/trunk/src/persistent/dict.py 2009-08-22 13:36:27 UTC (rev 103082)
@@ -1,6 +1,6 @@
##############################################################################
#
-# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# Copyright Zope Foundation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
@@ -11,72 +11,6 @@
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
-"""Python implementation of persistent container type
-$Id$
-"""
-
-import persistent
-from UserDict import IterableUserDict
-
-__metaclass__ = type
-
-class PersistentDict(persistent.Persistent, IterableUserDict):
- """A persistent wrapper for mapping objects.
-
- This class allows wrapping of mapping objects so that object
- changes are registered. As a side effect, mapping objects may be
- subclassed.
- """
-
- # IterableUserDict provides all of the mapping behavior. The
- # PersistentDict 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 = IterableUserDict.__delitem__
- __super_setitem = IterableUserDict.__setitem__
- __super_clear = IterableUserDict.clear
- __super_update = IterableUserDict.update
- __super_setdefault = IterableUserDict.setdefault
- __super_pop = IterableUserDict.pop
- __super_popitem = IterableUserDict.popitem
-
- __super_p_init = persistent.Persistent.__init__
- __super_init = IterableUserDict.__init__
-
- def __init__(self, dict=None):
- self.__super_init(dict)
- self.__super_p_init()
-
- def __delitem__(self, key):
- self.__super_delitem(key)
- self._p_changed = True
-
- def __setitem__(self, key, v):
- self.__super_setitem(key, v)
- self._p_changed = True
-
- def clear(self):
- self.__super_clear()
- self._p_changed = True
-
- def update(self, b):
- self.__super_update(b)
- self._p_changed = True
-
- def setdefault(self, key, failobj=None):
- # We could inline all of UserDict's implementation into the
- # method here, but I'd rather not depend at all on the
- # implementation in UserDict (simple as it is).
- if not self.has_key(key):
- self._p_changed = True
- return self.__super_setdefault(key, failobj)
-
- def pop(self, key, *args):
- self._p_changed = True
- return self.__super_pop(key, *args)
-
- def popitem(self):
- self._p_changed = True
- return self.__super_popitem()
+# persistent.dict is deprecated. User persistent.mapping
+from persistent.mapping import PersistentMapping as PersistentDict
Modified: ZODB/trunk/src/persistent/mapping.py
===================================================================
--- ZODB/trunk/src/persistent/mapping.py 2009-08-22 12:21:41 UTC (rev 103081)
+++ ZODB/trunk/src/persistent/mapping.py 2009-08-22 13:36:27 UTC (rev 103082)
@@ -17,9 +17,20 @@
$Id$"""
import persistent
-from UserDict import UserDict
+import UserDict
-class PersistentMapping(UserDict, persistent.Persistent):
+class default(object):
+
+ def __init__(self, func):
+ self.func = func
+
+ def __get__(self, inst, class_):
+ if inst is None:
+ return self
+ return self.func(inst)
+
+
+class PersistentMapping(UserDict.IterableUserDict, persistent.Persistent):
"""A persistent wrapper for mapping objects.
This class allows wrapping of mapping objects so that object
@@ -36,13 +47,13 @@
# 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
- __super_update = UserDict.update
- __super_setdefault = UserDict.setdefault
- __super_pop = UserDict.pop
- __super_popitem = UserDict.popitem
+ __super_delitem = UserDict.IterableUserDict.__delitem__
+ __super_setitem = UserDict.IterableUserDict.__setitem__
+ __super_clear = UserDict.IterableUserDict.clear
+ __super_update = UserDict.IterableUserDict.update
+ __super_setdefault = UserDict.IterableUserDict.setdefault
+ __super_pop = UserDict.IterableUserDict.pop
+ __super_popitem = UserDict.IterableUserDict.popitem
def __delitem__(self, key):
self.__super_delitem(key)
@@ -76,38 +87,16 @@
self._p_changed = 1
return self.__super_popitem()
- # __iter__ was added in ZODB 3.4.2, but should have been added long
- # before. We could inherit from Python's IterableUserDict instead
- # (which just adds __iter__ to Python's UserDict), but that class isn't
- # documented, and it would add another level of lookup for all the
- # other methods.
- def __iter__(self):
- return iter(self.data)
+ # Old implementations used _container rather than data.
+ # Use a descriptor to provide data when we have _container instead
- # 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.
+ @default
+ def data(self):
+ # We don't want to cause a write on read, so wer're careful not to
+ # do anything that would cause us to become marked as changed, however,
+ # if we're modified, then the saved record will have data, not
+ # _container.
+ data = self.__dict__.pop('_container')
+ self.__dict__['data'] = data
- # Effectively, the original rep is part of the "API." To provide
- # full compatibility, the getstate and setstate must read and
- # write 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 = dict([x for x in self.__dict__.items()
- if not x[0].startswith('_v_')])
- 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)
+ return data
Modified: ZODB/trunk/src/persistent/tests/test_mapping.py
===================================================================
--- ZODB/trunk/src/persistent/tests/test_mapping.py 2009-08-22 12:21:41 UTC (rev 103081)
+++ ZODB/trunk/src/persistent/tests/test_mapping.py 2009-08-22 13:36:27 UTC (rev 103082)
@@ -1,21 +1,25 @@
##############################################################################
#
-# Copyright (c) 2006 Zope Corporation and Contributors.
+# Copyright (c) Zope Foundation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
-# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
-"""Test PersistentMapping
-"""
-
import unittest
+from zope.testing import doctest, setupstack
+def test_suite():
+ return unittest.TestSuite((
+ doctest.DocFileSuite('README.txt'),
+ ))
+
+
l0 = {}
l1 = {0:0}
l2 = {0:0, 1:1}
@@ -164,8 +168,54 @@
u2.clear()
eq(u2, {}, "u2 == {}")
+def test_legacy_data():
+ """
+We've deprecated PersistentDict. If you import
+persistent.dict.PersistentDict, you'll get
+persistent.mapping.PersistentMapping.
+
+ >>> import persistent.dict, persistent.mapping
+ >>> persistent.dict.PersistentDict is persistent.mapping.PersistentMapping
+ True
+
+PersistentMapping uses a data attribute for it's mapping data:
+
+ >>> m = persistent.mapping.PersistentMapping()
+ >>> m.__dict__
+ {'data': {}}
+
+In the past, it used a _container attribute. For some time, the
+implementation continued to use a _container attribute in pickles
+(__get/setstate__) to be compatible with older releases. This isn't
+really necessary any more. In fact, releases for which this might
+matter can no longer share databases with current releases. Because
+releases as recent as 3.9.0b5 still use _container in saved state, we
+need to accept such state, but we stop producing it.
+
+If we reset it's __dict__ with legacy data:
+
+ >>> m.__dict__.clear()
+ >>> m.__dict__['_container'] = {'a': 1}
+ >>> m.__dict__
+ {'_container': {'a': 1}}
+ >>> m._p_changed = 0
+
+But when we perform any operations on it, the data will be converted
+without marking the object as changed:
+
+ >>> m
+ {'a': 1}
+ >>> m.__dict__
+ {'data': {'a': 1}}
+ >>> m._p_changed
+ 0
+
+ >>> m.__getstate__()
+ {'data': {'a': 1}}
+ """
+
def test_suite():
- return unittest.makeSuite(MappingTests)
-
-if __name__ == '__main__':
- unittest.main(defaultTest='test_suite')
+ return unittest.TestSuite((
+ doctest.DocTestSuite(),
+ unittest.makeSuite(MappingTests),
+ ))
More information about the Zodb-checkins
mailing list