[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