{"id":10367,"library":"zope-annotation","title":"Zope Annotation","description":"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.","status":"active","version":"6.0","language":"en","source_language":"en","source_url":"https://github.com/zopefoundation/zope.annotation","tags":["zope","annotation","persistent","object-extension","interfaces"],"install":[{"cmd":"pip install zope.annotation","lang":"bash","label":"Install stable version"}],"dependencies":[{"reason":"Provides the core interface (`IAnnotations`, `IAnnotatable`) definitions and implementation features required by `zope.annotation`.","package":"zope.interface"}],"imports":[{"note":"Interfaces are typically found in the `.interfaces` submodule within Zope packages.","wrong":"from zope.annotation import IAnnotations","symbol":"IAnnotations","correct":"from zope.annotation.interfaces import IAnnotations"},{"note":"Required to mark an object as capable of being annotated.","symbol":"IAnnotatable","correct":"from zope.annotation.interfaces import IAnnotatable"}],"quickstart":{"code":"from zope.interface import directlyProvides\nfrom zope.annotation.interfaces import IAnnotations, IAnnotatable\n\n# Define a simple class that can be annotated\nclass MyObject:\n    pass\n\n# Instantiate the object\nobj = MyObject()\n\n# An object must provide IAnnotatable to be annotated.\n# In a real Zope application, this might be handled by decorators or base classes.\n# For a standalone example, we directly provide the interface.\ndirectlyProvides(obj, IAnnotatable)\n\n# Get the annotations adapter for the object\n# If no annotations exist, a new empty dictionary-like object is created.\nannotations = IAnnotations(obj)\n\n# Store and retrieve data on the object via annotations\nannotations['my_data_key'] = 'This is some data stored as an annotation.'\nannotations['another_key'] = {'list': [1, 2, 3], 'dict_val': 'value'}\n\nprint(f\"Annotation 'my_data_key': {annotations['my_data_key']}\")\nprint(f\"Annotation 'another_key': {annotations['another_key']}\")\n\n# Check if an annotation exists\nif 'my_data_key' in annotations:\n    print(\"'my_data_key' exists in annotations.\")\n\n# Delete an annotation\ndel annotations['my_data_key']\n\nif 'my_data_key' not in annotations:\n    print(\"'my_data_key' successfully deleted.\")\n","lang":"python","description":"This example demonstrates how to make an arbitrary object annotatable using `directlyProvides(obj, IAnnotatable)` and then use the `IAnnotations` adapter to store and retrieve key-value data on it. This pattern is fundamental for extending objects without inheritance in Zope-based applications."},"warnings":[{"fix":"Upgrade your Python environment to 3.9 or a newer supported version. Alternatively, pin `zope.annotation` to `<6.0` if you must remain on Python 3.8.","message":"Version 6.0 of `zope.annotation` dropped support for Python 3.8. It now requires Python 3.9 or newer.","severity":"breaking","affected_versions":"6.0+"},{"fix":"Ensure your object provides `IAnnotatable`. In simple cases, use `from zope.interface import directlyProvides; directlyProvides(obj, IAnnotatable)`. In more complex scenarios, objects might inherit from a base class providing `IAnnotatable` or have an adapter registered for it via `zope.component`.","message":"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`.","severity":"gotcha","affected_versions":"all"},{"fix":"Ensure that the values you assign to `IAnnotations` are either basic Python types or objects that are themselves persistent (e.g., ZODB Persistent objects or types that can be pickled by ZODB).","message":"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.","severity":"gotcha","affected_versions":"all"}],"env_vars":null,"last_verified":"2026-04-17T00:00:00.000Z","next_check":"2026-07-16T00:00:00.000Z","problems":[{"fix":"Before attempting to get `IAnnotations(obj)`, ensure `obj` provides `IAnnotatable`. For testing or simple cases, use `from zope.interface import directlyProvides; directlyProvides(obj, IAnnotatable)`.","cause":"The object you are trying to annotate does not provide the `IAnnotatable` interface, which is a prerequisite for `zope.annotation` to function.","error":"TypeError: Could not adapt <__main__.MyObject object at 0x...> to <InterfaceClass zope.annotation.interfaces.IAnnotations>"},{"fix":"Change your import statement to `from zope.annotation.interfaces import IAnnotations`.","cause":"The `IAnnotations` interface is not directly under the `zope.annotation` package but within its `interfaces` submodule.","error":"ImportError: cannot import name 'IAnnotations' from 'zope.annotation'"},{"fix":"If 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'})`.","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.","error":"AttributeError: 'dict' object has no attribute '_p_jar'"}]}