[Zope3-checkins] SVN: Zope3/trunk/src/zope/app/uniqueid/ Added an
implementation of the unique id utility, which is the first step
Albertas Agejevas
alga at pov.lt
Thu Jun 10 10:32:55 EDT 2004
Log message for revision 25333:
Added an implementation of the unique id utility, which is the first step
in resurrecting the cataloging code.
-=-
Added: Zope3/trunk/src/zope/app/uniqueid/__init__.py
===================================================================
--- Zope3/trunk/src/zope/app/uniqueid/__init__.py 2004-06-10 14:27:17 UTC (rev 25332)
+++ Zope3/trunk/src/zope/app/uniqueid/__init__.py 2004-06-10 14:32:54 UTC (rev 25333)
@@ -0,0 +1,108 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Corporation 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.
+# 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.
+#
+##############################################################################
+"""
+Unique id utility.
+
+This utility assigns unique integer ids to objects and allows lookups
+by object and by id.
+
+This functionality can be used in cataloging.
+
+$Id$
+"""
+import random
+from zope.app.uniqueid.interfaces import IUniqueIdUtility, IReference
+from zope.interface import implements
+from ZODB.interfaces import IConnection
+from BTrees import OIBTree, IOBTree
+from zope.app import zapi
+
+
+class UniqueIdUtility:
+ """This utility provides a two way mapping between objects and
+ integer ids.
+
+ IReferences to objects are stored in the indexes.
+ """
+ implements(IUniqueIdUtility)
+
+ def __init__(self):
+ self.ids = OIBTree.OIBTree()
+ self.refs = IOBTree.IOBTree()
+
+ def getObject(self, id):
+ return self.refs[id]()
+
+ def getId(self, ob):
+ ref = zapi.getAdapter(ob, IReference)
+ return self.ids[ref]
+
+ def _generateId(self):
+ while True:
+ uid = random.randint(0, 2**31)
+ if uid not in self.ids:
+ return uid
+
+ def register(self, ob):
+ ref = zapi.getAdapter(ob, IReference)
+ if ref in self.ids:
+ return self.ids[ref]
+ uid = self._generateId()
+ self.refs[uid] = ref
+ self.ids[ref] = uid
+ return uid
+
+ def unregister(self, ob):
+ ref = zapi.getAdapter(ob, IReference)
+ uid = self.ids[ref]
+ del self.refs[uid]
+ del self.ids[ref]
+
+
+class ReferenceToPersistent:
+ """An IReference for persistent object which is comparable.
+
+ These references compare by _p_oids of the objects they reference.
+ """
+ implements(IReference)
+
+ def __init__(self, object):
+ self.object = object
+ if not getattr(object, '_p_oid', None):
+ zapi.getAdapter(object, IConnection).add(object)
+
+ def __call__(self):
+ return self.object
+
+ def __cmp__(self, other):
+ if not isinstance(other, ReferenceToPersistent):
+ raise TypeError("Cannot compare ReferenceToPersistent with %r" %
+ (other,))
+ return cmp(self.object._p_oid, other.object._p_oid)
+
+
+def connectionOfPersistent(ob):
+ """An adapter which gets a ZODB connection of a persistent object.
+
+ We are assuming the object has a parent if it has been created in
+ this transaction.
+
+ Raises ValueError if it is impossible to get a connection.
+ """
+ cur = ob
+ while not getattr(cur, '_p_jar', None):
+ cur = getattr(cur, '__parent__', None)
+ if cur is None:
+ raise ValueError('Can not get connection of %r', (ob,))
+ return cur._p_jar
Property changes on: Zope3/trunk/src/zope/app/uniqueid/__init__.py
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
Added: Zope3/trunk/src/zope/app/uniqueid/interfaces.py
===================================================================
--- Zope3/trunk/src/zope/app/uniqueid/interfaces.py 2004-06-10 14:27:17 UTC (rev 25332)
+++ Zope3/trunk/src/zope/app/uniqueid/interfaces.py 2004-06-10 14:32:54 UTC (rev 25333)
@@ -0,0 +1,49 @@
+"""
+Interfaces for the unique id utility.
+
+$Id$
+"""
+from zope.interface import Interface
+
+
+class IReference(Interface):
+ """A reference to an object (like a weak ref)
+
+ Have to be orderable. The references are only equal if they
+ reference the same object.
+ """
+
+ def __call__():
+ """Get the object this reference is linking to"""
+
+
+class IUniqueIdUtilityQuery(Interface):
+
+ def getObject(uid):
+ """Return an object by its unique id"""
+
+ def getId(ob):
+ """Get a unique id of an object.
+
+ If the id for an object is unknown, ValueError is raised.
+ """
+
+class IUniqueIdUtilitySet(Interface):
+
+ def register(ob):
+ """Registers an object and returns a unique id generated for it.
+
+ If the object is already registered, its id is returned anyway.
+ """
+
+ def unregister(ob):
+ """Remove the object from the indexes.
+
+ ValueError is raised if ob is not registered previously.
+ """
+
+class IUniqueIdUtility(IUniqueIdUtilitySet, IUniqueIdUtilityQuery):
+ """A utility that assigns unique ids to the objects
+
+ Allows to query object by id and id by object.
+ """
Property changes on: Zope3/trunk/src/zope/app/uniqueid/interfaces.py
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
Added: Zope3/trunk/src/zope/app/uniqueid/tests.py
===================================================================
--- Zope3/trunk/src/zope/app/uniqueid/tests.py 2004-06-10 14:27:17 UTC (rev 25332)
+++ Zope3/trunk/src/zope/app/uniqueid/tests.py 2004-06-10 14:32:54 UTC (rev 25333)
@@ -0,0 +1,152 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Corporation 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.
+# 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.
+#
+##############################################################################
+"""
+Tests for the unique id utility.
+
+$Id$
+"""
+import unittest
+from zope.interface.verify import verifyObject
+from persistent import Persistent
+from persistent.interfaces import IPersistent
+from zope.app.tests import setup, ztapi
+from zope.interface import implements
+from ZODB.interfaces import IConnection
+from zope.app.location.interfaces import ILocation
+
+
+class P(Persistent):
+ implements(ILocation)
+
+
+class ConnectionStub:
+ next = 1
+ def add(self, ob):
+ ob._p_jar = self
+ ob._p_oid = self.next
+ self.next += 1
+
+
+class ReferenceSetupMixin:
+ """Registers adapters ILocation->IConnection and IPersistent->IReference"""
+ def setUp(self):
+ from zope.app.uniqueid import connectionOfPersistent
+ from zope.app.uniqueid import ReferenceToPersistent
+ from zope.app.uniqueid.interfaces import IReference
+ root = setup.placefulSetUp(site=True)
+ ztapi.provideAdapter(ILocation, IConnection, connectionOfPersistent)
+ ztapi.provideAdapter(IPersistent, IReference, ReferenceToPersistent)
+
+ def tearDown(self):
+ setup.placefulTearDown()
+
+
+class TestUniqueIdUtility(ReferenceSetupMixin, unittest.TestCase):
+
+ def test_interface(self):
+ from zope.app.uniqueid.interfaces import IUniqueIdUtility
+ from zope.app.uniqueid import UniqueIdUtility
+
+ verifyObject(IUniqueIdUtility, UniqueIdUtility())
+
+ def test(self):
+ from zope.app.uniqueid import UniqueIdUtility
+
+ u = UniqueIdUtility()
+ obj = P()
+ obj._p_jar = ConnectionStub()
+ uid = u.register(obj)
+ self.assert_(u.getObject(uid) is obj)
+ self.assertEquals(u.getId(obj), uid)
+
+ uid2 = u.register(obj)
+ self.assertEquals(uid, uid2)
+
+ u.unregister(obj)
+ self.assertRaises(KeyError, u.getObject, uid)
+ self.assertRaises(KeyError, u.getId, obj)
+
+
+class TestReferenceToPersistent(ReferenceSetupMixin, unittest.TestCase):
+
+ def test(self):
+ from zope.app.uniqueid.interfaces import IReference
+ from zope.app.uniqueid import ReferenceToPersistent
+
+ ob = P()
+ ob._p_oid = 'x' * 20
+ ref = ReferenceToPersistent(ob)
+ verifyObject(IReference, ref)
+ self.assert_(ref() is ob)
+
+ parent = P()
+ conn = ConnectionStub()
+ parent._p_jar = conn
+ ob2 = P()
+ ob2.__parent__ = parent
+ ref = ReferenceToPersistent(ob2)
+ ob = ref()
+ self.assert_(ob is ob2)
+ self.assertEquals(ob._p_jar, conn)
+
+ def test_compare(self):
+ from zope.app.uniqueid import ReferenceToPersistent
+
+ ob1 = Persistent()
+ ob2 = Persistent()
+ ob3 = Persistent()
+ ob1._p_oid = 'x' * 20
+ ob2._p_oid = ob3._p_oid = 'y' * 20
+ ref1 = ReferenceToPersistent(ob1)
+ ref2 = ReferenceToPersistent(ob2)
+ ref3 = ReferenceToPersistent(ob3)
+ self.assert_(ref1 < ref2)
+ self.assert_(ref2 == ref3)
+ self.assertRaises(TypeError, ref1.__cmp__, object())
+
+
+class TestConnectionOfPersistent(unittest.TestCase):
+
+ def test(self):
+ from zope.app.uniqueid import connectionOfPersistent
+
+ conn = object()
+
+ ob1 = P()
+ ob1._p_jar = conn
+
+ ob2 = P()
+ ob2.__parent__ = ob1
+
+ ob3 = P()
+
+ self.assertEquals(connectionOfPersistent(ob1), conn)
+ self.assertEquals(connectionOfPersistent(ob2), conn)
+ self.assertRaises(ValueError, connectionOfPersistent, ob3)
+
+ ob3.__parent__ = object()
+ self.assertRaises(ValueError, connectionOfPersistent, ob3)
+ self.assertRaises(ValueError, connectionOfPersistent, object())
+
+
+
+def test_suite():
+ suite = unittest.TestSuite()
+ suite.addTest(unittest.makeSuite(TestUniqueIdUtility))
+ suite.addTest(unittest.makeSuite(TestReferenceToPersistent))
+ suite.addTest(unittest.makeSuite(TestConnectionOfPersistent))
+ return suite
+
+if __name__ == '__main__':
+ unittest.main()
Property changes on: Zope3/trunk/src/zope/app/uniqueid/tests.py
___________________________________________________________________
Name: svn:keywords
+ Id
Name: svn:eol-style
+ native
More information about the Zope3-Checkins
mailing list