[Zope3-checkins] SVN: Zope3/branches/3.2/src/zope/app/interface/ merge -r72109:72919, backport persistent interface fixes

Ross Patterson me at rpatterson.net
Sat Oct 13 17:09:38 EDT 2007


Log message for revision 80866:
  merge -r72109:72919, backport persistent interface fixes
  

Changed:
  U   Zope3/branches/3.2/src/zope/app/interface/__init__.py
  U   Zope3/branches/3.2/src/zope/app/interface/tests/test_interface.py
  A   Zope3/branches/3.2/src/zope/app/interface/wref.py

-=-
Modified: Zope3/branches/3.2/src/zope/app/interface/__init__.py
===================================================================
--- Zope3/branches/3.2/src/zope/app/interface/__init__.py	2007-10-13 17:26:37 UTC (rev 80865)
+++ Zope3/branches/3.2/src/zope/app/interface/__init__.py	2007-10-13 21:09:38 UTC (rev 80866)
@@ -20,21 +20,22 @@
 __docformat__ = 'restructuredtext'
 
 from persistent import Persistent
-from persistent.dict import PersistentDict
-from zodbcode.patch import registerWrapper, Wrapper
+from zodbcode.patch import registerWrapper, Wrapper, NameFinder
 
 from zope.interface.interface import InterfaceClass
 from zope.interface import Interface
 from zope.security.proxy import removeSecurityProxy
 
+from wref import FlexibleWeakKeyDictionary
+
 class PersistentInterfaceClass(Persistent, InterfaceClass):
 
     def __init__(self, *args, **kw):
         Persistent.__init__(self)
         InterfaceClass.__init__(self, *args, **kw)
+        
+        self.dependents = FlexibleWeakKeyDictionary()
 
-        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 +51,7 @@
 def getInterfaceStateForPersistentInterfaceCreation(iface):
     # Need to convert the dependents weakref dict to a persistent dict
     dict = iface.__dict__.copy()
-    dependents = PersistentDict()
+    dependents = FlexibleWeakKeyDictionary()
     for k, v in dict['dependents'].iteritems():
         dependents[k] = v
     dict['dependents'] = dependents
@@ -61,6 +62,11 @@
                 getInterfaceStateForPersistentInterfaceCreation,
                 )
 
+NameFinder.classTypes[InterfaceClass] = True
+NameFinder.types[InterfaceClass] = True
+NameFinder.classTypes[PersistentInterfaceClass] = True
+NameFinder.types[PersistentInterfaceClass] = True
+
 from zope.interface.declarations import providedBy
 
 def queryType(object, interface):

Modified: Zope3/branches/3.2/src/zope/app/interface/tests/test_interface.py
===================================================================
--- Zope3/branches/3.2/src/zope/app/interface/tests/test_interface.py	2007-10-13 17:26:37 UTC (rev 80865)
+++ Zope3/branches/3.2/src/zope/app/interface/tests/test_interface.py	2007-10-13 21:09:38 UTC (rev 80866)
@@ -19,12 +19,16 @@
 
 import unittest
 
+from gc import collect
+
 import transaction
+from persistent import Persistent
 
 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.interface.interfaces import IInterface
 from zope.app.interface import PersistentInterface
 
 # TODO: for some reason changing this code to use implements() does not
@@ -42,6 +46,36 @@
 aFoo = Foo()
 """
 
+class IQuux(Interface): pass
+
+bar_code = """\
+from zope.interface import Interface
+from zope.app.interface.tests.test_interface import IQuux
+
+class IBar(Interface): pass
+class IBah(IQuux): pass
+class IBaz(Interface): pass
+class IBlah(IBaz): pass
+
+"""
+
+provide_iface_code = """\
+from zope.interface import Interface
+from zope.app.component.interface import provideInterface
+from zope.app.interface.tests.test_interface import IBarInterface
+
+class IBar(Interface): pass
+provideInterface('', IBar, iface_type=IBarInterface)
+
+"""
+
+class IBarInterface(IInterface): pass
+
+class Bar(Persistent): pass
+class Baz(Persistent): pass
+
+class IQux(Interface): pass
+
 class PersistentInterfaceTest(unittest.TestCase):
 
     def setUp(self):
@@ -76,6 +110,82 @@
         # 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))
+
+        bah = Bar()
+        directlyProvides(bah, barmodule.IBah)
+        self.root['bah'] = bah
+        self.assertTrue(barmodule.IBah.providedBy(bah))
+
+        blah = Bar()
+        directlyProvides(blah, barmodule.IBlah)
+        self.root['blah'] = blah
+        self.assertTrue(barmodule.IBlah.providedBy(blah))
+
+        # Update the code to make sure everything works on update
+        self.registry.updateModule('barmodule',
+                                   bar_code + '\nfoo = 1')
+
+        transaction.commit()
+        self.db.close()
+        root = self.db.open().root()
+
+        barmodule = root['registry'].findModule("barmodule")
+
+        bar = root['bar']
+        self.assertTrue(barmodule.IBar.providedBy(bar))
+
+        bah = root['bah']
+        self.assertTrue(barmodule.IBah.providedBy(bah))
+
+        blah = root['blah']
+        self.assertTrue(barmodule.IBlah.providedBy(blah))
+
+    def test_persistentWeakref(self):
+        """Verify interacton of declaration weak refs with ZODB
+
+        Weak references to persistent objects don't remain after ZODB
+        pack and garbage collection."""
+
+        bar = self.root['bar'] = Bar()
+        self.registry.newModule("barmodule", bar_code)
+        barmodule = self.registry.findModule("barmodule")
+        self.assertEqual(barmodule.IBar.dependents.keys(), [])
+        directlyProvides(bar, barmodule.IBar)
+        self.assertEqual(len(barmodule.IBar.dependents), 1)
+
+        transaction.commit()
+        del bar
+        del self.root['bar']
+        self.db.pack()
+        transaction.commit()
+        collect()
+
+        root = self.db.open().root()
+        barmodule = root['registry'].findModule("barmodule")
+        self.assertEqual(barmodule.IBar.dependents.keys(), [])
+
+    def test_persistentProvides(self):
+        """Verify that provideInterface works."""
+
+        self.registry.newModule("barmodule", provide_iface_code)
+        barmodule = self.registry.findModule("barmodule")
+        self.assertTrue(IBarInterface.providedBy(barmodule.IBar))
+
+        self.registry.updateModule('barmodule',
+                                   provide_iface_code + '\nfoo = 1')
+        transaction.commit()
+        barmodule = self.registry.findModule("barmodule")
+        self.assertTrue(IBarInterface.providedBy(barmodule.IBar))
+        
 def test_suite():
     return unittest.makeSuite(PersistentInterfaceTest)

Copied: Zope3/branches/3.2/src/zope/app/interface/wref.py (from rev 72919, Zope3/trunk/src/zope/app/interface/wref.py)
===================================================================
--- Zope3/branches/3.2/src/zope/app/interface/wref.py	                        (rev 0)
+++ Zope3/branches/3.2/src/zope/app/interface/wref.py	2007-10-13 21:09:38 UTC (rev 80866)
@@ -0,0 +1,52 @@
+from weakref import ref
+
+from persistent.interfaces import IPersistent
+from persistent.wref import (WeakRef, WeakRefMarker,
+                             PersistentWeakKeyDictionary)
+
+class wref(ref):
+    def __reduce_ex__(self, proto):
+        return _wref_reconstructor, ()
+
+class Dummy(object): pass
+
+def _wref_reconstructor():
+    """Return a dead reference on reconstruction"""
+    return wref(Dummy())
+
+def getWeakRef(ob):
+    """Get either a persistent or non-presistent weakref"""
+    if IPersistent.providedBy(ob):
+        return WeakRef(ob)
+    else:
+        return wref(ob)
+
+class FlexibleWeakKeyDictionary(PersistentWeakKeyDictionary):
+
+    def __setitem__(self, key, value):
+        self.data[getWeakRef(key)] = value
+
+    def __getitem__(self, key):
+        return self.data[getWeakRef(key)]
+
+    def __delitem__(self, key):
+        del self.data[getWeakRef(key)]
+
+    def get(self, key, default=None):
+        return self.data.get(getWeakRef(key), default)
+
+    def __contains__(self, key):
+        return getWeakRef(key) in self.data
+
+    def update(self, adict):
+        if isinstance(adict, PersistentWeakKeyDictionary):
+            self.data.update(adict.update)
+        else:
+            for k, v in adict.items():
+                self.data[getWeakRef(k)] = v
+
+    def keys(self):
+        return [k() for k in self.data.keys()]
+
+    def __len__(self):
+        return len(self.data)



More information about the Zope3-Checkins mailing list