skip to navigation
skip to content

zope.app.module 3.5.0

Zope 3 persistent code/module support

Persistent Python modules allow us to develop and store Python modules in the ZODB in contrast to storing them on the filesystem. You might want to look at the zodbcode package for the details of the implementation. In Zope 3 we implemented persistent modules as utilities. These utilities are known as module managers that manage the source code, compiled module and name of the module. We then provide a special module registry that looks up the utilities to find modules.

Detailed Documentation

Persistent Python Modules

Persistent Python modules allow us to develop and store Python modules in the ZODB in contrast to storing them on the filesystem. You might want to look at the zodbcode package for the details of the implementation. In Zope 3 we implemented persistent modules as utilities. These utilities are known as module managers that manage the source code, compiled module and name of the module. We then provide a special module registry that looks up the utilities to find modules.

The Module Manager

One can simply create a new module manager by instantiating it:

>>> from zope.app.module.manager import ModuleManager
>>> manager = ModuleManager()

If I create the manager without an argument, there is no source code:

>>> manager.source
''

When we add some code

>>> manager.source = """\n
... foo = 1
... def bar(): return foo
... class Blah(object):
...     def __init__(self, id): self.id = id
...     def __repr__(self): return 'Blah(id=%s)' % self.id
... """

we can get the compiled module and use the created objects:

>>> module = manager.getModule()
>>> module.foo
1
>>> module.bar()
1
>>> module.Blah('blah')
Blah(id=blah)

We can also ask for the name of the module:

>>> manager.name
>>> module.__name__

But why is it None? Because we have no registered it yet. Once we register and activate the registration a name will be set:

>>> from zope.app.testing import setup
>>> root = setup.buildSampleFolderTree()
>>> root_sm = setup.createSiteManager(root)
>>> from zope.app.module import interfaces
>>> manager = setup.addUtility(root_sm, 'mymodule',
...                            interfaces.IModuleManager, manager)
>>> manager.name
'mymodule'
>>> manager.getModule().__name__
'mymodule'

Next, let’s ensure that the module’s persistence works correctly. To do that let’s create a database and add the root folder to it:

>>> from ZODB.tests.util import DB
>>> db = DB()
>>> conn = db.open()
>>> conn.root()['Application'] = root
>>> import transaction
>>> transaction.commit()

Let’s now reopen the database to test that the module can be seen from a different connection.

>>> conn2 = db.open()
>>> root2 = conn2.root()['Application']
>>> module2 = root2.getSiteManager().queryUtility(
...     interfaces.IModuleManager, 'mymodule').getModule()
>>> module2.foo
1
>>> module2.bar()
1
>>> module2.Blah('blah')
Blah(id=blah)

Module Lookup API

The way the persistent module framework hooks into Python is via module registires that behave pretty much like sys.modules. Zope 3 provides its own module registry that uses the registered utilities to look up modules:

>>> from zope.app.module import ZopeModuleRegistry
>>> ZopeModuleRegistry.findModule('mymodule')

But why did we not get the module back? Because we have not set the site yet:

>>> from zope.app.component import hooks
>>> hooks.setSite(root)

Now it will find the module and we can retrieve a list of all persistent module names:

>>> ZopeModuleRegistry.findModule('mymodule') is module
True
>>> ZopeModuleRegistry.modules()
[u'mymodule']

Additionally, the package provides two API functions that look up a module in the registry and then in sys.modules:

>>> import zope.app.module
>>> zope.app.module.findModule('mymodule') is module
True
>>> zope.app.module.findModule('zope.app.module') is zope.app.module
True

The second function can be used to lookup objects inside any module:

>>> zope.app.module.resolve('mymodule.foo')
1
>>> zope.app.module.resolve('zope.app.module.foo.resolve')

In order to use this framework in real Python code import statements, we need to install the importer hook, which is commonly done with an event subscriber:

>>> import __builtin__
>>> event = object()
>>> zope.app.module.installPersistentModuleImporter(event)
>>> __builtin__.__import__ # doctest: +ELLIPSIS
<bound method ZopePersistentModuleImporter.__import__ of ...>

Now we can simply import the persistent module:

>>> import mymodule
>>> mymodule.Blah('my id')
Blah(id=my id)

Finally, we unregister the hook again:

>>> zope.app.module.uninstallPersistentModuleImporter(event)
>>> __builtin__.__import__
<built-in function __import__>

Persistent Interfaces

zope.app.module’s ModuleManagers behave a little differently when interfaces are involved:

>>> from zope.app.module.manager import ModuleManager
>>> manager = ModuleManager()
>>> source = """\n
... from zope.interface import Interface
... class IFoo(Interface): pass
... class IBar(IFoo): pass
... """
>>> manager.source = source

A ModuleManager doesn’t get a name until it’s registered and the zodbcode wrappers break without a name, so we can’t retrieve our module until our manager is registered:

>>> from zope.app.testing import setup
>>> from zope.app.module import interfaces
>>> root = setup.buildSampleFolderTree()
>>> root_sm = setup.createSiteManager(root)
>>> manager = setup.addUtility(root_sm, u'foo',
...                            interfaces.IModuleManager, manager)

Now we can compile a module with interfaces and access everything appropriately:

>>> module = manager.getModule()
>>> module
<PersistentModule foo>
>>> module.IFoo
<PersistentInterfaceClass foo.IFoo>
>>> module.IBar
<PersistentInterfaceClass foo.IBar>

CHANGES

3.5.0 (2009-02-01)

  • Use zope.container instead of zope.app.container.

3.4.0 (2007-10-25)

  • Initial release independent of the main Zope tree.
 
File Type Py Version Uploaded on Size
zope.app.module-3.5.0.tar.gz (md5) Source 2009-02-01 9KB