[Zope3-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 Zope3-Checkins
mailing list