Zope Annotation
The `zope.annotation` package provides a robust object annotation mechanism, allowing objects to be transparently extended with additional information without modifying their original class. It is part of the Zope Foundation ecosystem, currently at version 6.0, and maintains a stable release cadence aligned with Python and Zope community standards.
Common errors
-
TypeError: Could not adapt <__main__.MyObject object at 0x...> to <InterfaceClass zope.annotation.interfaces.IAnnotations>
cause The object you are trying to annotate does not provide the `IAnnotatable` interface, which is a prerequisite for `zope.annotation` to function.fixBefore attempting to get `IAnnotations(obj)`, ensure `obj` provides `IAnnotatable`. For testing or simple cases, use `from zope.interface import directlyProvides; directlyProvides(obj, IAnnotatable)`. -
ImportError: cannot import name 'IAnnotations' from 'zope.annotation'
cause The `IAnnotations` interface is not directly under the `zope.annotation` package but within its `interfaces` submodule.fixChange your import statement to `from zope.annotation.interfaces import IAnnotations`. -
AttributeError: 'dict' object has no attribute '_p_jar'
cause You are attempting to store a non-persistent Python dictionary (or other non-persistent object) as an annotation on a persistent object within a ZODB, and ZODB is trying to make the *value* persistent but it doesn't know how.fixIf you need a persistent dictionary for annotations, use a persistent collection type from `ZODB.blob` or `BTrees`. For example, `from persistent.mapping import PersistentMapping; annotations['my_persistent_dict'] = PersistentMapping({'key': 'value'})`.
Warnings
- breaking Version 6.0 of `zope.annotation` dropped support for Python 3.8. It now requires Python 3.9 or newer.
- gotcha Objects must explicitly provide the `IAnnotatable` interface to be annotated. If an object does not provide this interface, attempting to adapt it to `IAnnotations` will fail with a `TypeError`.
- gotcha When using `zope.annotation` with persistent objects (e.g., in a ZODB), any values stored as annotations must also be persistent objects themselves (or basic Python types like int, str, dict, list of basic types). Storing non-persistent objects will lead to `TypeError` or `AttributeError` during storage.
Install
-
pip install zope.annotation
Imports
- IAnnotations
from zope.annotation import IAnnotations
from zope.annotation.interfaces import IAnnotations
- IAnnotatable
from zope.annotation.interfaces import IAnnotatable
Quickstart
from zope.interface import directlyProvides
from zope.annotation.interfaces import IAnnotations, IAnnotatable
# Define a simple class that can be annotated
class MyObject:
pass
# Instantiate the object
obj = MyObject()
# An object must provide IAnnotatable to be annotated.
# In a real Zope application, this might be handled by decorators or base classes.
# For a standalone example, we directly provide the interface.
directlyProvides(obj, IAnnotatable)
# Get the annotations adapter for the object
# If no annotations exist, a new empty dictionary-like object is created.
annotations = IAnnotations(obj)
# Store and retrieve data on the object via annotations
annotations['my_data_key'] = 'This is some data stored as an annotation.'
annotations['another_key'] = {'list': [1, 2, 3], 'dict_val': 'value'}
print(f"Annotation 'my_data_key': {annotations['my_data_key']}")
print(f"Annotation 'another_key': {annotations['another_key']}")
# Check if an annotation exists
if 'my_data_key' in annotations:
print("'my_data_key' exists in annotations.")
# Delete an annotation
del annotations['my_data_key']
if 'my_data_key' not in annotations:
print("'my_data_key' successfully deleted.")