Zope Configuration Markup Language (ZCML)
zope.configuration provides the Zope Configuration Markup Language (ZCML), a declarative XML-based configuration system used extensively in the Zope and Plone ecosystems. It allows applications to register components, utilities, and services, defining application behavior and structure through XML directives. The current stable version is 7.1, with releases typically tied to Zope/Plone ecosystem needs and Python compatibility.
Warnings
- breaking Python 3.10 or newer is now required. Older Python 3 versions (3.6-3.9) are no longer supported since version 7.0.
- gotcha ZCML directives like `factory` and `provides` reference Python objects (classes, interfaces) by dotted names (e.g., `my.package.MyClass`). These objects must be discoverable and importable by Python's module system when ZCML is processed. If ZCML cannot find the referenced module or class, it will raise an `ImportError` or `ConfigurationError`.
- gotcha Missing or incorrect namespace declarations (`xmlns`, `xmlns:prefix`) in ZCML files can lead to directives not being recognized or parsing errors. Every ZCML file and every custom directive from another package needs its proper namespace declaration.
- gotcha The order of ZCML configuration matters. Later declarations can override earlier ones, particularly when registering utilities, adapters, or views with the same name/interface/for parameters. This can lead to unexpected behavior if not understood.
Install
-
pip install zope.configuration
Imports
- xmlconfig
import zope.configuration.xmlconfig
from zope.configuration import xmlconfig
- ConfigurationContext
from zope.configuration.config import ConfigurationContext
- ConfigurationError
from zope.configuration.exceptions import ConfigurationError
Quickstart
import sys
from zope.interface import Interface, implementer
from zope.configuration import xmlconfig
from zope.component import getUtility, ComponentLookupError
# --- Step 1: Define an interface and an implementation ---
# These would typically reside in a real Python module.
# For this self-contained quickstart, we simulate a module.
class IMyService(Interface):
"""An interface for a dummy service."""
def do_something():
"""Perform a dummy action."""
@implementer(IMyService)
class MyService:
"""A simple implementation of IMyService."""
def do_something(self):
return "Service action complete from ZCML!"
# Simulate a module for ZCML to find the classes
# In a real application, 'quickstart_module' would be a package with your classes.
class DummyModule:
IMyService = IMyService
MyService = MyService
sys.modules['quickstart_module'] = DummyModule
# --- Step 2: Define a ZCML configuration string ---
zcml_content = """
<configure
xmlns="http://namespaces.zope.org/zope"
i18n_domain="my.package">
<utility
factory="quickstart_module.MyService"
provides="quickstart_module.IMyService"
name="my.unique.service"
/>
</configure>
"""
# --- Step 3: Load and process the ZCML configuration ---
try:
# xmlconfig.string processes the ZCML and registers components
context = xmlconfig.string(zcml_content)
# --- Step 4: Verify the utility was registered ---
service = getUtility(IMyService, name="my.unique.service")
print(f"Utility loaded successfully. Action: {service.do_something()}")
except ComponentLookupError:
print("Error: Utility not found after ZCML processing. Check ZCML registration.")
except Exception as e:
print(f"An error occurred during ZCML loading: {e}")
finally:
# Clean up the dummy module to avoid side effects in other tests/runs
if 'quickstart_module' in sys.modules:
del sys.modules['quickstart_module']