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

Ross Patterson <[email protected]>
Newsgroups gmane.comp.web.zope.zope3.cvs
Message-ID <[email protected]>
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)
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.