[Checkins] SVN: zope.app.principalannotation/trunk/ Fix LP:237985
Dan Korostelev
nadako at gmail.com
Sun Dec 7 14:12:34 EST 2008
Log message for revision 93756:
Fix LP:237985
Changed:
U zope.app.principalannotation/trunk/CHANGES.txt
U zope.app.principalannotation/trunk/setup.py
U zope.app.principalannotation/trunk/src/zope/app/principalannotation/__init__.py
U zope.app.principalannotation/trunk/src/zope/app/principalannotation/tests.py
-=-
Modified: zope.app.principalannotation/trunk/CHANGES.txt
===================================================================
--- zope.app.principalannotation/trunk/CHANGES.txt 2008-12-07 17:41:06 UTC (rev 93755)
+++ zope.app.principalannotation/trunk/CHANGES.txt 2008-12-07 19:12:34 UTC (rev 93756)
@@ -2,6 +2,13 @@
CHANGES
=======
+3.4.1 (unreleased)
+
+- Fix the case described in LP:#237985, when two unstored
+ Annotations are got and then tried to store itself, overriding
+ each other. This is done by caching unstored objects on the
+ utility.
+
3.4.0 (2007-10-26)
------------------
Modified: zope.app.principalannotation/trunk/setup.py
===================================================================
--- zope.app.principalannotation/trunk/setup.py 2008-12-07 17:41:06 UTC (rev 93755)
+++ zope.app.principalannotation/trunk/setup.py 2008-12-07 19:12:34 UTC (rev 93756)
@@ -22,7 +22,7 @@
return open(os.path.join(os.path.dirname(__file__), *rnames)).read()
setup(name='zope.app.principalannotation',
- version = '3.4.0',
+ version = '3.4.1dev',
author='Zope Corporation and Contributors',
author_email='zope3-dev at zope.org',
description='Annotations for Zope Principals',
Modified: zope.app.principalannotation/trunk/src/zope/app/principalannotation/__init__.py
===================================================================
--- zope.app.principalannotation/trunk/src/zope/app/principalannotation/__init__.py 2008-12-07 17:41:06 UTC (rev 93755)
+++ zope.app.principalannotation/trunk/src/zope/app/principalannotation/__init__.py 2008-12-07 19:12:34 UTC (rev 93756)
@@ -42,6 +42,15 @@
def __init__(self):
self.annotations = OOBTree()
+ def __getstate__(self):
+ # We can't use the _v_ attribute because we surely don't want
+ # it to be wiped out from the cache, so we just exclude our
+ # attribute from object's state :)
+ state = super(PrincipalAnnotationUtility, self).__getstate__()
+ if '_newAnnotationsCache' in state:
+ del state['_newAnnotationsCache']
+ return state
+
def getAnnotations(self, principal):
"""Return object implementing IAnnotations for the given principal.
@@ -57,9 +66,15 @@
annotations = self.annotations.get(principalId)
if annotations is None:
- annotations = Annotations(principalId, store=self.annotations)
- annotations.__parent__ = self
- annotations.__name__ = principalId
+ if not hasattr(self, '_newAnnotationsCache'):
+ self._newAnnotationsCache = {}
+ if principalId in self._newAnnotationsCache:
+ return self._newAnnotationsCache[principalId]
+ else:
+ annotations = Annotations(principalId, store=self.annotations, cache=self._newAnnotationsCache)
+ annotations.__parent__ = self
+ annotations.__name__ = principalId
+ self._newAnnotationsCache[principalId] = annotations
return annotations
@@ -73,13 +88,14 @@
interface.implements(IAnnotations)
- def __init__(self, principalId, store=None):
+ def __init__(self, principalId, store=None, cache=None):
self.principalId = principalId
self.data = PersistentDict() # We don't really expect that many
# _v_store is used to remember a mapping object that we should
# be saved in if we ever change
self._v_store = store
+ self._v_cache = cache
def __getitem__(self, key):
try:
@@ -98,6 +114,9 @@
# be saved in if we ever change
self._v_store[self.principalId] = self
del self._v_store
+ if getattr(self, '_v_cache', None) is not None:
+ del self._v_cache[self.principalId]
+ del self._v_cache
self.data[key] = value
Modified: zope.app.principalannotation/trunk/src/zope/app/principalannotation/tests.py
===================================================================
--- zope.app.principalannotation/trunk/src/zope/app/principalannotation/tests.py 2008-12-07 17:41:06 UTC (rev 93755)
+++ zope.app.principalannotation/trunk/src/zope/app/principalannotation/tests.py 2008-12-07 19:12:34 UTC (rev 93756)
@@ -56,6 +56,37 @@
# But now we should have the annotation:
self.assert_(self.util.hasAnnotations(prince))
+ # Another scenery, say we get annotations two
+ # times.
+ king = Principal('somebody2')
+ self.assert_(not self.util.hasAnnotations(king))
+
+ kingAnnotation = self.util.getAnnotations(king)
+ self.assert_(not self.util.hasAnnotations(king))
+
+ kingAnnotation2 = self.util.getAnnotations(king)
+ self.assert_(not self.util.hasAnnotations(king))
+
+ # These objects should be the same
+ self.assert_(kingAnnotation is kingAnnotation2)
+
+ # So this should work:
+ kingAnnotation['something'] = 'whatever'
+ self.assert_(self.util.hasAnnotations(king))
+
+ kingAnnotation2['something2'] = 'whatever2'
+ self.assert_(self.util.hasAnnotations(king))
+
+ # Let's check the results:
+ annot = self.util.getAnnotations(king)
+ self.assert_(annot.get('something2'))
+ self.assert_(annot.get('something'))
+
+ # This is done using the internal cache object in the utility,
+ # but it should not be stored in the database, so it won't be
+ # in object's state:
+ self.assertEquals(self.util.__getstate__().keys(), ['annotations'])
+
def testGetFromLayered(self):
princeSomebody = Principal('somebody')
sm1 = self.makeSite('folder1')
More information about the Checkins
mailing list