I'm working on zope.app.module.ZopePersistentModuleImporter. As noted
in zodbcode.module.PersistentModuleImporter.__doc__, if the persistent
module registry which is consulted on import queries a persistent site
manager then the site manager must be activated before being queried or
a circular import problem occurs when the ZODB attempts to import the
globals necessary to activate the site manager.
The site manager will, however, eventually be deactivated, by a
transaction.abort() for example. So I'm looking for a way that the
importer can know whether or now it's being called as a part of
activating the site manager. I've written (and attached diffs for) a
very ugly function that inspects the frame stack to detect if the site
manager is being activated just to demonstrate what I'm looking for.
Is there a way to ask an object if it's being activated? Or what might
be a better approach to solving this problem?
Ross
Index: __init__.py
===================================================================
--- __init__.py (revision 78553)
+++ __init__.py (working copy)
@@ -17,6 +17,7 @@
"""
__docformat__ = 'restructuredtext'
import sys
+import ZODB.Connection
import zodbcode.interfaces
import zodbcode.module
@@ -24,6 +25,16 @@
import zope.component
from zope.app.module.interfaces import IModuleManager
+def isActivating(obj):
+ if hasattr(obj, '_p_jar'):
+ frame = sys._getframe(1)
+ while frame is not None:
+ if (frame.f_code is
+ ZODB.Connection.Connection.setstate.func_code):
+ if frame.f_locals['obj'] is obj:
+ return True
+ frame = frame.f_back
+ return False
class ZopeModuleRegistry(object):
"""Zope-specific registry of persistent modules.
@@ -44,6 +55,9 @@
for name,
modulemgr in zope.component.getUtilitiesFor(IModuleManager)]
+ def isActivating(self):
+ return isActivating(zope.component.getSiteManager().utilities)
+
# Make Zope Module Registry a singelton
ZopeModuleRegistry = ZopeModuleRegistry()
@@ -66,10 +80,11 @@
self._registry = registry
def __import__(self, name, globals={}, locals={}, fromlist=[]):
- mod = self._import(self._registry, name, self._get_parent(globals),
- fromlist)
- if mod is not None:
- return mod
+ if not self._registry.isActivating():
+ mod = self._import(self._registry, name, self._get_parent(globals),
+ fromlist)
+ if mod is not None:
+ return mod
return self._saved_import(name, globals, locals, fromlist)
Index: persistence.txt
===================================================================
--- persistence.txt (revision 0)
+++ persistence.txt (revision 0)
@@ -0,0 +1,80 @@
+;-*-Doctest-*-
+===========
+Persistencs
+===========
+
+If the site manager is persistent and is a ghost when an import is
+executed, then it will need to be activated before the import can be
+completed. Activating the site manager requires importing the
+necessary globals so the importer needs to fallback to the builtin
+__import__ while the site manager is being activated.
+
+Setup a persistent module with a name in it.
+
+ >>> import zope.app.module.manager
+ >>> foo_manager = zope.app.module.manager.ModuleManager()
+ >>> source = """\n
+ ... foo = 'foo'\n
+ ... """
+ >>> foo_manager.source = source
+
+ >>> bar_manager = zope.app.module.manager.ModuleManager()
+ >>> source = """\n
+ ... bar = 'bar'\n
+ ... """
+ >>> bar_manager.source = source
+
+Register the module with a persistent site manager that has been added
+to a ZODB.
+
+ >>> import zope.app.testing
+ >>> from zope.app.module import interfaces
+ >>> from ZODB.DB import DB
+ >>> from ZODB.DemoStorage import DemoStorage
+ >>> root = zope.app.testing.setup.buildSampleFolderTree()
+ >>> db = DB(DemoStorage())
+ >>> connection = db.open()
+ >>> connection.root()['root'] = root
+ >>> root_sm = zope.app.testing.setup.createSiteManager(
+ ... root, setsite=True)
+ >>> foo_manager = zope.app.testing.setup.addUtility(
+ ... root_sm, u'foo', interfaces.IModuleManager, foo_manager)
+ >>> bar_manager = zope.app.testing.setup.addUtility(
+ ... root_sm, u'bar', interfaces.IModuleManager, bar_manager)
+
+Install the importer.
+
+ >>> import zope.app.module
+ >>> zope.app.module.importer.install()
+
+Now we can import the module.
+
+ >>> import foo
+ >>> foo.foo
+ 'foo'
+
+Commit everything.
+
+ >>> import transaction
+ >>> transaction.commit()
+
+Deactivate the site manager and the utilities registry to turn them
+into ghosts by aborting a transaction.
+
+ >>> from zope import interface, component
+ >>> sm = component.getSiteManager()
+ >>> ignored = zope.app.testing.setup.addUtility(
+ ... root_sm, u'baz', interface.Interface, lambda: 'baz')
+ >>> transaction.abort()
+
+We can still import persistent modules.
+
+ >>> import bar
+ >>> bar.bar
+ 'bar'
+
+Cleanup.
+
+ >>> transaction.abort()
+ >>> connection.close()
+ >>> db.close()
Index: tests.py
===================================================================
--- tests.py (revision 78553)
+++ tests.py (working copy)
@@ -35,6 +35,7 @@
def test_suite():
return unittest.TestSuite((
doctest.DocFileSuite('README.txt', 'interfaces.txt',
+ 'persistence.txt',
setUp=setUp, tearDown=tearDown),
))
_______________________________________________
Zope-Dev maillist - [email protected]
http://mail.zope.org/mailman/listinfo/zope-dev
** No cross posts or HTML encoding! **
(Related lists -
http://mail.zope.org/mailman/listinfo/zope-announce
http://mail.zope.org/mailman/listinfo/zope )