Zope Site
zope.site is a foundational Python library that provides local registries for the Zope Component Architecture (ZCA). It enables the creation and retrieval of localized component managers (site managers) for specific object contexts, allowing components to be registered and looked up dynamically based on their position in an object hierarchy. The current version is 6.0, and its release cadence is tied to the broader Zope ecosystem.
Common errors
-
zope.component.ComponentLookupError: The object has no component site. I tried to look up a local component site for <__main__.MyContext object at 0x...>cause Attempting to register or look up a component locally without an active site manager context, or trying to access a local component outside the `provideSite` block.fixEnsure that operations requiring a local site manager are performed within a `with provideSite(context):` block. Local registrations are temporary for the duration of this block. -
ImportError: cannot import name 'provideSite' from 'zope.site' (path_to_zope_site/__init__.py)
cause `provideSite` is not directly exposed by the `zope.site` package's `__init__.py`.fixCorrect the import statement to `from zope.site.site import provideSite`. -
TypeError: 'NoneType' object has no attribute 'getSiteManager'
cause This error often occurs when `zope.component.getSiteManager()` is called when no site has been set (globally or locally), or when attempting to get the local site manager from a context that hasn't been properly provided with one.fixEnsure a site is active. For local sites, use `with provideSite(context):` which implicitly sets the site manager for the context. For global site managers, ensure `zope.component.setSite()` has been called if not using `provideSite`.
Warnings
- breaking `zope.site` dropped support for Python 3.7 and 3.8 in version 6.0.
- gotcha Registrations made within a `provideSite` context manager block are local to that site and do not persist globally or outside that specific context.
- gotcha When looking up components using `zope.component.getUtility` (or similar) within a local site, the lookup order is local registry first, then the global registry. This can lead to unexpected behavior if a component is registered globally and then also locally with the same name/interface.
- gotcha The `provideSite` function (and other core site-related utilities) is located in the `zope.site.site` submodule, not directly in `zope.site`.
Install
-
pip install zope.site
Imports
- provideSite
from zope.site import provideSite
from zope.site.site import provideSite
- getSiteManager
from zope.site import getSiteManager
from zope.site.site import getSiteManager
- LocalSiteManager
from zope.site.site import LocalSiteManager
Quickstart
import zope.component
import zope.interface
import zope.site.site
from zope.location import Located
# 1. Define an interface for your context and services
class IMyContext(zope.interface.Interface):
"""An interface for objects that can serve as local site contexts."""
class IMyService(zope.interface.Interface):
"""An interface for a service."""
# 2. Implement the context and service
@zope.interface.implementer(IMyContext)
class MyContext(Located): # Inherit from Located for Zope site integration
"""A sample context object that can host a local site."""
def __init__(self, name="Default"):
self.name = name
@zope.interface.implementer(IMyService)
class MyService:
"""A sample service implementation."""
def __init__(self, name):
self.name = name
def __repr__(self):
return f"<MyService: {self.name}>"
# 3. Register a global service
print("--- Global Scope ---")
zope.component.provideUtility(IMyService, MyService("Global Service"), name="shared_service")
print(f"Globally available: {zope.component.getUtility(IMyService, name='shared_service')}")
# 4. Create a context instance and establish a local site
context_a = MyContext("Context A")
print(f"\n--- Inside Local Site for {context_a.name} ---")
with zope.site.site.provideSite(context_a):
# Register a service locally for Context A
zope.component.provideUtility(IMyService, MyService("Local Service A"), name="my_local_service")
print(f"Local to {context_a.name}: {zope.component.getUtility(IMyService, name='my_local_service')}")
# Global service is still accessible
print(f"Global from {context_a.name}: {zope.component.getUtility(IMyService, name='shared_service')}")
# 5. Create another context and establish a different local site
context_b = MyContext("Context B")
print(f"\n--- Inside Local Site for {context_b.name} ---")
with zope.site.site.provideSite(context_b):
# Register a service locally for Context B (different from Context A's local service)
zope.component.provideUtility(IMyService, MyService("Local Service B"), name="my_local_service")
print(f"Local to {context_b.name}: {zope.component.getUtility(IMyService, name='my_local_service')}")
# Global service is still accessible
print(f"Global from {context_b.name}: {zope.component.getUtility(IMyService, name='shared_service')}")
# 6. Outside any local site
print("\n--- Outside any Local Site ---")
try:
# Attempting to access a local service will fail
zope.component.getUtility(IMyService, name="my_local_service")
except zope.component.ComponentLookupError as e:
print(f"Error: {e} (local service not available globally)")
print(f"Globally available: {zope.component.getUtility(IMyService, name='shared_service')}")