[Checkins] SVN: Zope3/branches/3.3/src/zope/app/ Merge PersistentInterfaceClass fix from trunk r72109 as described in

Ross Patterson me at rpatterson.net
Fri Jan 19 16:58:53 EST 2007


Log message for revision 72110:
  Merge PersistentInterfaceClass fix from trunk r72109 as described in
  http://www.zope.org/Collectors/Zope3-dev/747.
  

Changed:
  U   Zope3/branches/3.3/src/zope/app/component/tests/test_registration.py
  U   Zope3/branches/3.3/src/zope/app/interface/__init__.py
  U   Zope3/branches/3.3/src/zope/app/interface/tests/test_interface.py

-=-
Modified: Zope3/branches/3.3/src/zope/app/component/tests/test_registration.py
===================================================================
--- Zope3/branches/3.3/src/zope/app/component/tests/test_registration.py	2007-01-19 21:06:58 UTC (rev 72109)
+++ Zope3/branches/3.3/src/zope/app/component/tests/test_registration.py	2007-01-19 21:58:52 UTC (rev 72110)
@@ -419,7 +419,81 @@
 
     """
 
+barcode = """
+from zope.interface import Interface
+class IBar(Interface): pass
+class IBaz(Interface): pass
+"""
 
+class Bar(persistent.Persistent): pass
+class Baz(persistent.Persistent): pass
+
+def test_persistent_interfaces():
+    """
+Registrations for persistent interfaces are accessible from separate
+connections.
+
+Setup the DB and our first connection::
+
+    >>> import ZODB.tests.util
+    >>> db = ZODB.tests.util.DB()
+    >>> conn1 = db.open()
+    >>> root1 = conn1.root()
+
+Setup the persistent module registry and the local component
+registry::
+
+    >>> from zodbcode.module import ManagedRegistry
+    >>> registry = root1['registry'] = ManagedRegistry()
+    >>> from zope.component.persistentregistry import PersistentComponents
+    >>> manager = root1['manager'] = PersistentComponents()
+
+Create a persistent module::
+
+    >>> registry.newModule('barmodule', barcode)
+    >>> barmodule = registry.findModule('barmodule')
+
+Create a persistent instance::
+
+    >>> bar = root1['bar'] = Bar()
+    >>> from zope.interface import directlyProvides
+    >>> directlyProvides(bar, barmodule.IBar)
+    >>> from transaction import commit
+    >>> commit()
+
+Register an adapter::
+
+    >>> manager.queryAdapter(bar, barmodule.IBaz)
+    >>> manager.registerAdapter(Baz, [barmodule.IBar], barmodule.IBaz)
+    >>> manager.getAdapter(bar, barmodule.IBaz) # doctest: +ELLIPSIS
+    <zope.app.component.tests.test_registration.Baz object at ...>
+
+Before commit, the adapter is not available from another connection::
+
+    >>> conn2 = db.open()
+    >>> root2 = conn2.root()
+    >>> registry2 = root2['registry']
+    >>> barmodule2 = registry2.findModule('barmodule')
+    >>> bar2 = root2['bar']
+    >>> manager2 = root2['manager']
+    >>> manager2.queryAdapter(bar2, barmodule2.IBaz)
+
+After commit, it is::
+
+    >>> commit()
+    >>> conn2.sync()
+    >>> manager2.getAdapter(bar2, barmodule2.IBaz)
+    ... # doctest: +ELLIPSIS
+    <zope.app.component.tests.test_registration.Baz object at ...>
+
+Cleanup::
+
+    >>> conn1.close()
+    >>> conn2.close()
+    >>> db.close()
+"""
+
+
 def test_suite():
     suite = unittest.TestSuite((
         doctest.DocFileSuite('deprecated35_statusproperty.txt',

Modified: Zope3/branches/3.3/src/zope/app/interface/__init__.py
===================================================================
--- Zope3/branches/3.3/src/zope/app/interface/__init__.py	2007-01-19 21:06:58 UTC (rev 72109)
+++ Zope3/branches/3.3/src/zope/app/interface/__init__.py	2007-01-19 21:58:52 UTC (rev 72110)
@@ -19,22 +19,90 @@
 """
 __docformat__ = 'restructuredtext'
 
+
 from persistent import Persistent
-from persistent.dict import PersistentDict
+from persistent.wref import PersistentWeakKeyDictionary
 from zodbcode.patch import registerWrapper, Wrapper
 
 from zope.interface.interface import InterfaceClass
 from zope.interface import Interface
 from zope.security.proxy import removeSecurityProxy
 
+persistentFactories = {}
+def getPersistentKey(v_key):
+    if not hasattr(v_key, '__reduce__'):
+        return
+    reduce = v_key.__reduce__()
+    lookups = reduce[0], type(v_key), getattr(v_key, '__class__')
+    for lookup in lookups:
+        p_factory = persistentFactories.get(lookup, None)
+        if p_factory is not None:
+            return p_factory(v_key)
+
+class DependentsDict(PersistentWeakKeyDictionary):
+    """Intercept non-persistent keys and swap in persistent
+    equivalents."""
+
+    def __setstate__(self, state):
+        data = state['data']
+        for v_key, value in data:
+            p_key = getPersistentKey(v_key)
+            if p_key is not None:
+                data[p_key] = data[v_key]
+        state['data'] = data
+        return super(DependentsDict, self).__setstate__(state)
+                
+    def __setitem__(self, key, value):
+        p_key = getPersistentKey(key)
+        if p_key is not None: key = p_key
+        return super(DependentsDict, self).__setitem__(key, value)
+
+    def __len__(self): return len(self.data)
+
+    def get(self, key, default=None):
+        if not hasattr(key, '_p_oid') or not hasattr(key, '_p_jar'):
+            return default
+        return super(DependentsDict, self).get(key, default)
+
+    def update(self, adict):
+        for v_key in adict.keys():
+            p_key = getPersistentKey(v_key)
+            if p_key is not None:
+                adict[p_key] = adict[v_key]
+        return super(DependentsDict, self).update(adict)
+
+    def keys(self): return [k() for k in self.data.keys()]
+
+from zope.interface.declarations import ProvidesClass, Provides
+class PersistentProvidesClass(Persistent, ProvidesClass):
+    """A persistent Provides class."""
+    def __init__(self, *args, **kw):
+        Persistent.__init__(self)
+        ProvidesClass.__init__(self, *args, **kw)
+        self.dependents = DependentsDict()
+def persistentProvides(obj):
+    return PersistentProvidesClass(*obj.__reduce__()[1:])
+persistentFactories[Provides] = persistentProvides
+
+from zope.interface.declarations import Implements
+class PersistentImplements(Persistent, Implements):
+    """A persistent Implements class."""
+    def __init__(self, *args, **kw):
+        Persistent.__init__(self)
+        Implements.__init__(self, *args, **kw)
+        self.dependents = DependentsDict()
+def persistentImplements(obj):
+    return PersistentImplements(*obj.__bases__)
+persistentFactories[Implements] = persistentImplements
+
 class PersistentInterfaceClass(Persistent, InterfaceClass):
 
     def __init__(self, *args, **kw):
         Persistent.__init__(self)
         InterfaceClass.__init__(self, *args, **kw)
+        
+        self.dependents = DependentsDict()
 
-        self.dependents = PersistentDict()
-
 # PersistentInterface is equivalent to the zope.interface.Interface object
 # except that it is also persistent.  It is used in conjunction with
 # zodb.code to support interfaces in persistent modules.
@@ -50,7 +118,7 @@
 def getInterfaceStateForPersistentInterfaceCreation(iface):
     # Need to convert the dependents weakref dict to a persistent dict
     dict = iface.__dict__.copy()
-    dependents = PersistentDict()
+    dependents = DependentsDict()
     for k, v in dict['dependents'].iteritems():
         dependents[k] = v
     dict['dependents'] = dependents

Modified: Zope3/branches/3.3/src/zope/app/interface/tests/test_interface.py
===================================================================
--- Zope3/branches/3.3/src/zope/app/interface/tests/test_interface.py	2007-01-19 21:06:58 UTC (rev 72109)
+++ Zope3/branches/3.3/src/zope/app/interface/tests/test_interface.py	2007-01-19 21:58:52 UTC (rev 72110)
@@ -17,14 +17,18 @@
 """
 __docformat__ = 'restructuredtext'
 
+from gc import collect
+
 import unittest
 
+from persistent import Persistent
+
 import transaction
 
 from ZODB.tests.util import DB
 from zodbcode.module import ManagedRegistry
 
-from zope.interface import Interface, implements
+from zope.interface import Interface, implements, directlyProvides
 from zope.app.interface import PersistentInterface
 
 # TODO: for some reason changing this code to use implements() does not
@@ -42,11 +46,24 @@
 aFoo = Foo()
 """
 
+bar_code = """\
+from zope.interface import Interface
+class IBar(Interface): pass
+class IBaz(Interface): pass
+"""
+
+class Bar(Persistent): pass
+class Baz(Persistent): pass
+
+class IQux(Interface): pass
+
 class PersistentInterfaceTest(unittest.TestCase):
 
     def setUp(self):
+
         self.db = DB()
-        self.root = self.db.open().root()
+        self.conn = self.db.open()
+        self.root = self.conn.root()
         self.registry = ManagedRegistry()
         self.root["registry"] = self.registry
         transaction.commit()
@@ -76,6 +93,55 @@
         # the conversion should not affect Interface
         self.assert_(imodule.Interface is Interface)
 
+    def test_provides(self):
+        """Provides are persistent."""
+        
+        self.registry.newModule("barmodule", bar_code)
+        barmodule = self.registry.findModule("barmodule")
+        bar = Bar()
+        directlyProvides(bar, barmodule.IBar)
+        self.root['bar'] = bar
+        self.assertTrue(barmodule.IBar.providedBy(bar))
+        transaction.commit()
+        self.db.close()
 
+        root = self.db.open().root()
+        barmodule = root['registry'].findModule("barmodule")
+        bar = root['bar']
+        self.assertTrue(barmodule.IBar.providedBy(bar))
+
+    def test_weakref(self):
+        """Weak references to persistent objects don't remain after
+        ZODB pack and garbage collection."""
+
+        bar = self.root['bar'] = Bar()
+        baz = self.root['baz'] = Baz()
+
+        self.registry.newModule("barmodule", bar_code)
+        barmodule = self.registry.findModule("barmodule")
+
+        self.assertEqual(IQux.dependents.keys(), [])
+        self.assertEqual(barmodule.IBar.dependents.keys(), [])
+        
+        directlyProvides(baz, IQux)
+        directlyProvides(bar, barmodule.IBar)
+
+        self.assertEqual(len(IQux.dependents), 1)
+        self.assertEqual(len(barmodule.IBar.dependents), 1)
+
+        transaction.commit()
+        del bar
+        del self.root['bar']
+        del baz
+        del self.root['baz']
+        self.db.pack()
+        transaction.commit()
+        collect()
+
+        root = self.db.open().root()
+        barmodule = root['registry'].findModule("barmodule")
+
+        self.assertEqual(barmodule.IBar.dependents.keys(), [])
+        
 def test_suite():
     return unittest.makeSuite(PersistentInterfaceTest)



More information about the Checkins mailing list