zope.component.hooks: The current component registry¶
There can be any number of component registries in an application. One of them
is the global component registry, and there is also the concept of a currently
used component registry. Component registries other than the global one are
associated with objects called sites. The
provides an API to set and access the current site as well as manipulate the
adapter hook associated with it.
As long as we haven’t set a site, none is being considered current:
>>> from zope.component.hooks import getSite >>> print(getSite()) None
We can also ask for the current component registry (aka site manager historically); it will return the global one if no current site is set:
A special hook for getting the site manager.
Here we take the currently set site into account to find the appropriate site manager.
>>> from zope.component.hooks import getSiteManager >>> getSiteManager() <BaseGlobalComponents base>
Let’s set a site now. A site has to be an object that provides the
getSiteManager method, which is specified by
>>> from zope.interface.registry import Components >>> class Site(object): ... def __init__(self): ... self.registry = Components('components') ... def getSiteManager(self): ... return self.registry >>> from zope.component.hooks import setSite >>> site1 = Site() >>> setSite(site1)
After this, the newly set site is considered the currently active one:
>>> getSite() is site1 True >>> getSiteManager() is site1.registry True
If we set another site, that one will be considered current:
>>> site2 = Site() >>> site2.registry is not site1.registry True >>> setSite(site2) >>> getSite() is site2 True >>> getSiteManager() is site2.registry True
However, the default
zope.component.getSiteManager function isn’t
yet aware of this:
>>> from zope.component import getSiteManager as global_getSiteManager >>> global_getSiteManager() <BaseGlobalComponents base>
To integrate that with the notion of the current site, we need to call
zope.component.getSiteManagerand interface adaptation respect the current site.
Most applications will want to be sure te call this early in their startup sequence. Test code that uses these APIs should also arrange to call this.
>>> from zope.component.hooks import setHooks >>> setHooks() >>> getSiteManager() is site2.registry True >>> global_getSiteManager() is site2.registry True
This can be reversed using
zope.component.getSiteManagerand interface adaptation to their original implementations that are unaware of the current site.
Use caution when calling this; most code will not need to call this. If code using the global API executes following this, it will most likely use the base global component registry instead of a site-specific registry it was expected. This can lead to failures in adaptation and utility lookup.
>>> from zope.component.hooks import resetHooks >>> resetHooks() >>> global_getSiteManager() <BaseGlobalComponents base>
Finally we can unset the site and the global component registry is used again:
>>> setSite() >>> print(getSite()) None >>> getSiteManager() <BaseGlobalComponents base>
There also is a context manager for setting the site, which is especially useful when writing tests:
site(site) → None¶
Context manager that sets site as the current site for the duration of the
>>> import zope.component.hooks >>> print(getSite()) None >>> with zope.component.hooks.site(site2): ... getSite() is site2 True >>> print(getSite()) None
The site is properly restored even if the body of the with statement raises an exception:
>>> print(getSite()) None >>> with zope.component.hooks.site(site2): ... getSite() is site2 ... raise ValueError('An error in the body') Traceback (most recent call last): ... ValueError: An error in the body >>> print(getSite()) None