[Checkins] SVN: zope.locking/branches/patricks-fix/ add tests for generations module, clean up other tests

Patrick Strawderman patrick at zope.com
Tue Mar 15 19:26:29 EDT 2011


Log message for revision 120970:
  add tests for generations module, clean up other tests

Changed:
  U   zope.locking/branches/patricks-fix/buildout.cfg
  U   zope.locking/branches/patricks-fix/setup.py
  U   zope.locking/branches/patricks-fix/src/zope/locking/README.txt
  U   zope.locking/branches/patricks-fix/src/zope/locking/annoying.txt
  U   zope.locking/branches/patricks-fix/src/zope/locking/configure.zcml
  U   zope.locking/branches/patricks-fix/src/zope/locking/generations.py
  A   zope.locking/branches/patricks-fix/src/zope/locking/generations.txt
  U   zope.locking/branches/patricks-fix/src/zope/locking/tests.py
  U   zope.locking/branches/patricks-fix/src/zope/locking/utility.py
  U   zope.locking/branches/patricks-fix/src/zope/locking/utils.py

-=-
Modified: zope.locking/branches/patricks-fix/buildout.cfg
===================================================================
--- zope.locking/branches/patricks-fix/buildout.cfg	2011-03-15 23:06:08 UTC (rev 120969)
+++ zope.locking/branches/patricks-fix/buildout.cfg	2011-03-15 23:26:29 UTC (rev 120970)
@@ -1,4 +1,8 @@
 [buildout]
+extends =
+  http://download.zope.org/zopetoolkit/index/1.1/zopeapp-versions.cfg
+  http://download.zope.org/zopetoolkit/index/1.1/ztk-versions.cfg
+
 develop = .
 parts = py test
 
@@ -6,7 +10,7 @@
 
 [test]
 recipe = zc.recipe.testrunner
-eggs = zope.locking
+eggs = zope.locking [test]
 extra-paths = parts/zope3/src
 defaults = "--tests-pattern [fn]?tests --exit-with-status".split()
 

Modified: zope.locking/branches/patricks-fix/setup.py
===================================================================
--- zope.locking/branches/patricks-fix/setup.py	2011-03-15 23:06:08 UTC (rev 120969)
+++ zope.locking/branches/patricks-fix/setup.py	2011-03-15 23:26:29 UTC (rev 120970)
@@ -28,6 +28,9 @@
         'zope.security',
         'zope.testing',
         ],
+    extras_require=dict(
+       test=["zope.site"],
+        ),
     zip_safe = False,
     description=open("README.txt").read(),
     long_description=(

Modified: zope.locking/branches/patricks-fix/src/zope/locking/README.txt
===================================================================
--- zope.locking/branches/patricks-fix/src/zope/locking/README.txt	2011-03-15 23:06:08 UTC (rev 120969)
+++ zope.locking/branches/patricks-fix/src/zope/locking/README.txt	2011-03-15 23:26:29 UTC (rev 120970)
@@ -49,7 +49,7 @@
     >>> util.register(lock)
     Traceback (most recent call last):
     ...
-    AttributeError: 'NoneType' object has no attribute 'add'
+    TypeError: ...
 
     >>> conn.add(util)
 
@@ -151,17 +151,15 @@
 same object.
 
     >>> util.register(tokens.ExclusiveLock(demo, 'mary'))
-    ... # doctest: +ELLIPSIS
+    ...
     Traceback (most recent call last):
     ...
     RegistrationError: ...
     >>> util.register(tokens.SharedLock(demo, ('mary', 'jane')))
-    ... # doctest: +ELLIPSIS
     Traceback (most recent call last):
     ...
     RegistrationError: ...
     >>> util.register(tokens.Freeze(demo))
-    ... # doctest: +ELLIPSIS
     Traceback (most recent call last):
     ...
     RegistrationError: ...
@@ -331,13 +329,9 @@
 Now we'll hack our code to make it think that it is two hours later, and then
 check and modify the remaining_duration attribute.
 
-    >>> def hackNow():
-    ...     return (datetime.datetime.now(pytz.utc) +
-    ...             datetime.timedelta(hours=2))
-    ...
     >>> import zope.locking.utils
-    >>> oldNow = zope.locking.utils.now
-    >>> zope.locking.utils.now = hackNow # make code think it's 2 hours later
+    >>> now = zope.locking.utils.now()
+    >>> zope.locking.utils.set_now(now + datetime.timedelta(hours=2))
     >>> lock.duration
     datetime.timedelta(0, 14400)
     >>> two >= lock.remaining_duration >= one
@@ -366,11 +360,7 @@
 important to remember that a lock ending with a timeout ends silently--that
 is, no event is fired.
 
-    >>> def hackNow():
-    ...     return (
-    ...         datetime.datetime.now(pytz.utc) + datetime.timedelta(days=1))
-    ...
-    >>> zope.locking.utils.now = hackNow # make code think it is a day later
+    >>> zope.locking.utils.set_now(now + datetime.timedelta(days=1))
     >>> lock.ended == lock.expiration
     True
     >>> util.get(demo) is None
@@ -394,7 +384,7 @@
 We'll undo the hacks, and also end the lock (that is no longer ended once
 the hack is finished).
 
-    >>> zope.locking.utils.now = oldNow # undo the hack
+    >>> zope.locking.utils.reset()
     >>> lock.end()
 
 Make sure to register tokens.  Creating a lock but not registering it puts it
@@ -406,44 +396,44 @@
 
     >>> lock.duration = datetime.timedelta(1)
 
-    >>> lock.started # doctest: +ELLIPSIS
+    >>> lock.started
     Traceback (most recent call last):
     ...
     UnregisteredError: ...
-    >>> lock.ended # doctest: +ELLIPSIS
+    >>> lock.ended
     Traceback (most recent call last):
     ...
     UnregisteredError: ...
 
-    >>> lock.expiration # doctest: +ELLIPSIS
+    >>> lock.expiration
     Traceback (most recent call last):
     ...
     UnregisteredError: ...
 
-    >>> lock.remaining_duration # doctest: +ELLIPSIS
+    >>> lock.remaining_duration
     Traceback (most recent call last):
     ...
     UnregisteredError: ...
 
     >>> t = datetime.datetime.utcnow().replace(tzinfo=pytz.UTC)
-    >>> lock.expiration = t # doctest: +ELLIPSIS
+    >>> lock.expiration = t
     Traceback (most recent call last):
     ...
     UnregisteredError: ...
 
-    >>> lock.remaining_duration = datetime.timedelta(1) # doctest: +ELLIPSIS
+    >>> lock.remaining_duration = datetime.timedelta(1)
     Traceback (most recent call last):
     ...
     UnregisteredError: ...
 
     >>> lock = util.register(lock)
     >>> lock.end()
-    >>> lock.expiration = t # doctest: +ELLIPSIS
+    >>> lock.expiration = t
     Traceback (most recent call last):
     ...
     EndedError
 
-    >>> lock.remaining_duration = datetime.timedelta(1) # doctest: +ELLIPSIS
+    >>> lock.remaining_duration = datetime.timedelta(1)
     Traceback (most recent call last):
     ...
     EndedError
@@ -585,17 +575,14 @@
     >>> list(util) == [lock]
     True
     >>> util.register(tokens.ExclusiveLock(demo, 'mary'))
-    ... # doctest: +ELLIPSIS
     Traceback (most recent call last):
     ...
     RegistrationError: ...
     >>> util.register(tokens.SharedLock(demo, ('mary', 'jane')))
-    ... # doctest: +ELLIPSIS
     Traceback (most recent call last):
     ...
     RegistrationError: ...
     >>> util.register(tokens.Freeze(demo))
-    ... # doctest: +ELLIPSIS
     Traceback (most recent call last):
     ...
     RegistrationError: ...
@@ -777,7 +764,6 @@
     >>> token.end()
 
 You can only specify principals that are in the current interaction.
-# doctest + ELLIPSIS
 
     >>> token = broker.lock('joe')
     >>> sorted(token.principal_ids)
@@ -1009,19 +995,19 @@
     True
     >>> lock = util.register(tokens.ExclusiveLock(demo, 'mary'))
     >>> handler = interfaces.ITokenHandler(lock) # for joe's interaction still
-    >>> handler.duration = two # doctest: +ELLIPSIS
+    >>> handler.duration = two
     Traceback (most recent call last):
     ...
     ParticipationError: ...
-    >>> handler.expiration = handler.started + three # doctest: +ELLIPSIS
+    >>> handler.expiration = handler.started + three
     Traceback (most recent call last):
     ...
     ParticipationError: ...
-    >>> handler.remaining_duration = two # doctest: +ELLIPSIS
+    >>> handler.remaining_duration = two
     Traceback (most recent call last):
     ...
     ParticipationError: ...
-    >>> handler.release() # doctest: +ELLIPSIS
+    >>> handler.release()
     Traceback (most recent call last):
     ...
     ParticipationError: ...
@@ -1074,24 +1060,24 @@
     >>> handler.release()
     >>> sorted(handler.principal_ids)
     ['mary']
-    >>> handler.duration = two # doctest: +ELLIPSIS
+    >>> handler.duration = two
     Traceback (most recent call last):
     ...
     ParticipationError: ...
-    >>> handler.expiration = handler.started + three # doctest: +ELLIPSIS
+    >>> handler.expiration = handler.started + three
     Traceback (most recent call last):
     ...
     ParticipationError: ...
-    >>> handler.remaining_duration = two # doctest: +ELLIPSIS
+    >>> handler.remaining_duration = two
     Traceback (most recent call last):
     ...
     ParticipationError: ...
-    >>> handler.release() # doctest: +ELLIPSIS
+    >>> handler.release()
     Traceback (most recent call last):
     ...
     ParticipationError: ...
 
-    >>> handler.release(("joe",)) # doctest: +ELLIPSIS
+    >>> handler.release(("joe",))
     Traceback (most recent call last):
     ...
     ParticipationError: ...
@@ -1116,7 +1102,7 @@
     >>> sorted(handler.principal_ids)
     ['joe', 'mary', 'susan']
     >>> handler.release()
-    >>> handler.add('jake') # doctest: +ELLIPSIS
+    >>> handler.add('jake')
     Traceback (most recent call last):
     ...
     ParticipationError: ...

Modified: zope.locking/branches/patricks-fix/src/zope/locking/annoying.txt
===================================================================
--- zope.locking/branches/patricks-fix/src/zope/locking/annoying.txt	2011-03-15 23:06:08 UTC (rev 120969)
+++ zope.locking/branches/patricks-fix/src/zope/locking/annoying.txt	2011-03-15 23:26:29 UTC (rev 120970)
@@ -87,13 +87,9 @@
 Now we'll hack our code to make it think that it is two hours later, and then
 check and modify the remaining_duration attribute.
 
-    >>> def hackNow():
-    ...     return (datetime.datetime.now(pytz.utc) +
-    ...             datetime.timedelta(hours=2))
-    ...
     >>> import zope.locking.utils
-    >>> oldNow = zope.locking.utils.now
-    >>> zope.locking.utils.now = hackNow # make code think it's 2 hours later
+    >>> now = zope.locking.utils.now()
+    >>> zope.locking.utils.set_now(now + datetime.timedelta(hours=2))
     >>> lock.duration
     datetime.timedelta(0, 14400)
     >>> two >= lock.remaining_duration >= one
@@ -119,7 +115,7 @@
     ...     return (
     ...         datetime.datetime.now(pytz.utc) + datetime.timedelta(days=1))
     ...
-    >>> zope.locking.utils.now = hackNow # make code think it is a day later
+    >>> zope.locking.utils.set_now(now + datetime.timedelta(days=1))
     >>> lock.ended >= lock.started
     True
     >>> util.get(demo) is None
@@ -147,7 +143,7 @@
 We'll undo the hacks, and also end the lock (that is no longer ended once
 the hack is finished).
 
-    >>> zope.locking.utils.now = oldNow # undo the hack
+    >>> zope.locking.utils.reset()
     >>> lock.end()
 
 --------------
@@ -209,17 +205,14 @@
 object.
 
     >>> util.register(tokens.ExclusiveLock(demo, 'mary'))
-    ... # doctest: +ELLIPSIS
     Traceback (most recent call last):
     ...
     RegistrationError: ...
     >>> util.register(tokens.SharedLock(demo, ('mary', 'jane')))
-    ... # doctest: +ELLIPSIS
     Traceback (most recent call last):
     ...
     RegistrationError: ...
     >>> util.register(tokens.EndableFreeze(demo))
-    ... # doctest: +ELLIPSIS
     Traceback (most recent call last):
     ...
     RegistrationError: ...
@@ -384,32 +377,32 @@
     ...
     NotImplementedError
 
-    >>> token.duration = "" # doctest: +ELLIPSIS
+    >>> token.duration = ""
     Traceback (most recent call last):
     ...
     ValueError: duration must be datetime.timedelta
 
-    >>> token.remaining_duration = "" # doctest: +ELLIPSIS
+    >>> token.remaining_duration = ""
     Traceback (most recent call last):
     ...
     ValueError: duration must be datetime.timedelta
 
-    >>> token.duration = datetime.timedelta(-1) # doctest: +ELLIPSIS
+    >>> token.duration = datetime.timedelta(-1)
     Traceback (most recent call last):
     ...
     ValueError: duration may not be negative
 
-    >>> token.remaining_duration = datetime.timedelta(-1) # doctest: +ELLIPSIS
+    >>> token.remaining_duration = datetime.timedelta(-1)
     Traceback (most recent call last):
     ...
     ValueError: duration may not be negative
 
-    >>> token.expiration = "" # doctest: +ELLIPSIS
+    >>> token.expiration = ""
     Traceback (most recent call last):
     ...
     ValueError: expiration must be datetime.datetime
 
-    >>> token.expiration = datetime.datetime.utcnow() # doctest: +ELLIPSIS
+    >>> token.expiration = datetime.datetime.utcnow()
     Traceback (most recent call last):
     ...
     ValueError: expiration must be timezone-aware

Modified: zope.locking/branches/patricks-fix/src/zope/locking/configure.zcml
===================================================================
--- zope.locking/branches/patricks-fix/src/zope/locking/configure.zcml	2011-03-15 23:06:08 UTC (rev 120969)
+++ zope.locking/branches/patricks-fix/src/zope/locking/configure.zcml	2011-03-15 23:26:29 UTC (rev 120970)
@@ -79,6 +79,8 @@
 
   <include file="generations.zcml" />
 
+  <include package="zope.keyreference"/>
+
   <configure
     xmlns:zcml="http://namespaces.zope.org/zcml"
     zcml:condition="have apidoc"

Modified: zope.locking/branches/patricks-fix/src/zope/locking/generations.py
===================================================================
--- zope.locking/branches/patricks-fix/src/zope/locking/generations.py	2011-03-15 23:06:08 UTC (rev 120969)
+++ zope.locking/branches/patricks-fix/src/zope/locking/generations.py	2011-03-15 23:26:29 UTC (rev 120970)
@@ -61,11 +61,10 @@
         utility due to this issue.
     """
     for pid in list(util._principal_ids):
-        # iterForPrincipalId only returns non-ended locks, so we know
-        # they're still good.
         new_tree = BTrees.OOBTree.OOTreeSet()
-        for token in util.iterForPrincipalId(pid):
-            new_tree.add(zope.keyreference.interfaces.IKeyReference(token))
+        for token in util._principal_ids[pid]:
+            if not token.ended:
+                new_tree.add(zope.keyreference.interfaces.IKeyReference(token))
         if new_tree:
             util._principal_ids[pid] = new_tree
         else:

Added: zope.locking/branches/patricks-fix/src/zope/locking/generations.txt
===================================================================
--- zope.locking/branches/patricks-fix/src/zope/locking/generations.txt	                        (rev 0)
+++ zope.locking/branches/patricks-fix/src/zope/locking/generations.txt	2011-03-15 23:26:29 UTC (rev 120970)
@@ -0,0 +1,171 @@
+===========
+Generations
+===========
+
+The format of the internal data structures the token utility uses has
+changed a few times in 1.2.x due to bugs and other issues;
+therefore the zope.locking package includes a zope.generations schema
+manager to evolve the old data structures.
+
+Note that the schema manager is optional, and can be excluded by
+excluding `generations.zcml`.  Token utilities can be evolved manually
+using the helper functions in zope.locking.generations that are
+tested below.
+
+IMPORTANT: If the token utility is not registered in any site manager,
+it will also need to be evolved manually.
+
+Set Up
+------
+
+    >>> import datetime
+    >>> import random
+    >>> import zope.keyreference.interfaces
+    >>> import zope.location.traversing
+    >>> import zope.locking.generations
+    >>> import zope.locking.tokens
+    >>> import zope.locking.utils
+    >>> import zope.locking.utility
+    >>> import zope.site.folder
+    >>> import zope.site.hooks
+    >>> import zope.site.testing
+
+    >>> import BTrees.check
+    >>> import BTrees.OOBTree
+
+    >>> root = conn.root()
+    >>> gsm = zope.component.getGlobalSiteManager()
+    >>> gsm.registerAdapter(
+    ...     zope.location.traversing.LocationPhysicallyLocatable)
+
+To test the `get_site_managers` function used by the schema manager,
+we add a host of sites to the database.
+
+    >>> app = root["Application"] = zope.site.folder.rootFolder()
+    >>> root._p_jar.add(app)
+
+    >>> sms = []
+    >>> sms.append(zope.site.testing.createSiteManager(app))
+    >>> zope.site.hooks.setSite(app)
+    >>> app["site1"] = zope.site.folder.Folder()
+    >>> sms.append(zope.site.testing.createSiteManager(app["site1"]))
+    >>> app["site1a"] = zope.site.folder.Folder()
+    >>> sms.append(zope.site.testing.createSiteManager(app["site1a"]))
+    >>> app["site2"] = zope.site.folder.Folder()
+    >>> sms.append(zope.site.testing.createSiteManager(app["site2"]))
+
+`get_site_managers` returns all of the site managers for the sites we
+created.
+
+    >>> sms == list(zope.locking.generations.get_site_managers(app))
+    True
+
+    >>> app["site3"] = zope.site.folder.Folder()
+    >>> sms.append(zope.site.testing.createSiteManager(app["site3"]))
+
+    >>> sms == list(zope.locking.generations.get_site_managers(app))
+    True
+
+The `find_token_utilities` function returns all of the token utilities
+from all of the sites.
+
+    >>> list(zope.locking.generations.find_token_utilities(app))
+    []
+
+
+    >>> iface = zope.locking.interfaces.ITokenUtility
+    >>> sm = app["site1a"].getSiteManager()
+    >>> util = zope.locking.utility.TokenUtility()
+    >>> util2 = zope.locking.utility.TokenUtility()
+    >>> zope.site.testing.addUtility(sm, "", iface, util) and None
+    >>> zope.site.testing.addUtility(sm, "named", iface, util2) and None
+    >>> utils = list(zope.locking.generations.find_token_utilities(app))
+    >>> utils == [util, util2]
+    True
+
+    >>> sm = app["site3"].getSiteManager()
+    >>> util3 = zope.locking.utility.TokenUtility()
+    >>> zope.site.testing.addUtility(sm, "", iface, util3) and None
+    >>> utils = list(zope.locking.generations.find_token_utilities(app))
+    >>> utils == [util, util2, util3]
+    True
+
+    >>> app["util"] = zope.locking.utility.TokenUtility()
+
+app["util"] isn't registered in any site manager, so it isn't found.
+
+    >>> app["util"] in list(
+    ...     zope.locking.generations.find_token_utilities(app))
+    False
+
+The `fix_token_utility` function converts legacy utilities to the new
+format.  We'll add tokens to the utilities to emulate the legacy
+behavior of storing Tokens directly as keys in TreeSets (bad idea). 
+
+    >>> principals = ("henry", "mario", "edwige",)
+    >>> now = zope.locking.utils.now()
+    >>> def add_bad_tokens(util):
+    ...     _now = zope.locking.utils.now()
+    ...     for i in range(10):
+    ...         obj = Demo()
+    ...         pid = random.choice(principals)
+    ...         token = zope.locking.tokens.ExclusiveLock(obj, pid)
+    ...         if pid not in util._principal_ids:
+    ...             util._principal_ids[pid] = BTrees.OOBTree.TreeSet()
+    ...         util._principal_ids[pid].insert(token)
+    ...         key = zope.keyreference.interfaces.IKeyReference(obj)
+    ...         expiration = _now + datetime.timedelta(minutes=i+1)
+    ...         util._locks[key] = (token, frozenset([pid]), expiration)
+    ...         token.utility = util
+    ...         token.expiration = expiration
+    ...         if expiration not in util._expirations:
+    ...             util._expirations[expiration] = BTrees.OOBTree.TreeSet()
+    ...         util._expirations[expiration].insert(token)
+    ...         util._principal_ids["louis"] = BTrees.OOBTree.TreeSet()
+
+    >>> add_bad_tokens(util)
+
+    >>> now = zope.locking.utils.now()
+
+Let's travel 5 minutes into the future, and call the fixer; it will only
+leave non-expired tokens in the utility.
+
+    >>> zope.locking.utils.set_now(now + datetime.timedelta(minutes=5))
+    >>> zope.locking.generations.fix_token_utility(util)
+    >>> len(util._locks)
+    5
+
+    >>> "louis" in util._principal_ids
+    False
+
+    >>> def check_util(util):
+    ...     for tree in util._principal_ids.values():
+    ...         BTrees.check.check(tree)
+    ...         for keyref in tree:
+    ...             if not (
+    ...         zope.keyreference.interfaces.IKeyReference.providedBy(keyref)):
+    ...                 raise Exception(
+    ...                     "Expected keyreference, got: %r" % (keyref,))
+
+    >>> check_util(util)
+
+    >>> util.__init__() # reset
+
+    >>> add_bad_tokens(util2)
+    >>> add_bad_tokens(util3)
+    >>> check_util(util2)
+    Traceback (most recent call last):
+    ...
+    Exception: Expected keyreference, got: ...
+
+The `clean_locks` function is used by the schema manager to find all
+token utilities and run `fix_token_utility` on them.
+
+    >>> class Context(object):
+    ...     pass
+
+    >>> context = Context()
+    >>> context.connection = conn
+    >>> zope.locking.generations.clean_locks(context)
+    >>> for util in (util2, util3):
+    ...     check_util(util)


Property changes on: zope.locking/branches/patricks-fix/src/zope/locking/generations.txt
___________________________________________________________________
Added: svn:eol-style
   + native

Modified: zope.locking/branches/patricks-fix/src/zope/locking/tests.py
===================================================================
--- zope.locking/branches/patricks-fix/src/zope/locking/tests.py	2011-03-15 23:06:08 UTC (rev 120969)
+++ zope.locking/branches/patricks-fix/src/zope/locking/tests.py	2011-03-15 23:26:29 UTC (rev 120970)
@@ -11,11 +11,13 @@
 import zope.event
 
 import zope.locking.testing
+import zope.site.testing
 
 from zope.testing import doctest
 
 
 def setUp(test):
+    zope.site.testing.siteSetUp()
     zope.app.testing.placelesssetup.setUp(test)
     db = test.globs['db'] = ZODB.DB(ZODB.MappingStorage.MappingStorage())
     test.globs['conn'] = db.open()
@@ -25,10 +27,14 @@
         zope.app.keyreference.persistent.KeyReferenceToPersistent,
         [persistent.interfaces.IPersistent],
         zope.app.keyreference.interfaces.IKeyReference)
+    zope.component.provideAdapter(
+        zope.app.keyreference.persistent.connectionOfPersistent,
+        [persistent.interfaces.IPersistent])
     events = test.globs['events'] = []
     zope.event.subscribers.append(events.append)
 
 def tearDown(test):
+    zope.site.testing.siteTearDown()
     zope.app.testing.placelesssetup.tearDown(test)
     transaction.abort()
     test.globs['conn'].close()
@@ -38,17 +44,16 @@
     del events[:] # being paranoid
 
 def test_suite():
-    return unittest.TestSuite((
+    optionflags = doctest.ELLIPSIS
+    return unittest.TestSuite(
         doctest.DocFileSuite(
             'README.txt',
-            setUp=setUp, tearDown=tearDown),
-        doctest.DocFileSuite(
             'annoying.txt',
-            setUp=setUp, tearDown=tearDown),
-        doctest.DocFileSuite(
             'cleanup.txt',
+            'generations.txt',
+            optionflags=optionflags,
             setUp=setUp, tearDown=tearDown),
-        ))
+       )
 
 if __name__ == '__main__':
     unittest.main(defaultTest='test_suite')

Modified: zope.locking/branches/patricks-fix/src/zope/locking/utility.py
===================================================================
--- zope.locking/branches/patricks-fix/src/zope/locking/utility.py	2011-03-15 23:06:08 UTC (rev 120969)
+++ zope.locking/branches/patricks-fix/src/zope/locking/utility.py	2011-03-15 23:26:29 UTC (rev 120970)
@@ -1,5 +1,6 @@
 import persistent
 import persistent.interfaces
+import ZODB.interfaces
 
 from BTrees.OOBTree import OOBTree, OOTreeSet
 from zope import interface, component, event
@@ -54,8 +55,10 @@
             token.utility = self
         elif token.utility is not self:
             raise ValueError('Lock is already registered with another utility')
-        if persistent.interfaces.IPersistent.providedBy(token):
-            self._p_jar.add(token)
+        if (persistent.interfaces.IPersistent.providedBy(token) and
+            not getattr(token, "_p_jar", None)):
+            conn = ZODB.interfaces.IConnection(self)
+            conn.add(token)
         key_ref = IKeyReference(token.context)
         current = self._locks.get(key_ref)
         if current is not None:

Modified: zope.locking/branches/patricks-fix/src/zope/locking/utils.py
===================================================================
--- zope.locking/branches/patricks-fix/src/zope/locking/utils.py	2011-03-15 23:06:08 UTC (rev 120969)
+++ zope.locking/branches/patricks-fix/src/zope/locking/utils.py	2011-03-15 23:26:29 UTC (rev 120970)
@@ -2,7 +2,27 @@
 import datetime
 import pytz
 
-# this is a small convenience, but is more important as a convenient monkey-
-# patch opportunity for the package's README.txt doctest.
+# this is a small convenience, but is more important as a
+# convenient monkey-patch opportunity for the package's doctests.
+
+_now = None
+
 def now():
+    if _now is not None:
+        return _now
     return datetime.datetime.now(pytz.utc)
+
+def set_now(dt):
+    global _now
+    _now = dt
+
+def reset():
+    global _now
+    _now = None
+
+try:
+    import zope.testing.cleanup
+except ImportError:
+    pass
+else:
+    zope.testing.cleanup.addCleanUp(reset)



More information about the checkins mailing list