[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