Zope Traversing
Zope Traversing (current version 6.0) provides a robust and extensible mechanism for resolving paths within an object hierarchy, common in Zope-based applications and web frameworks. It allows developers to define how objects are looked up by name or through adapters, enabling flexible URL dispatching and content navigation. It has a steady release cadence, typically releasing new major versions every few years, with minor releases and bug fixes more frequently.
Common errors
-
ImportError: cannot import name 'AbsoluteURL' from 'zope.traversing.browser'
cause Attempting to import the `AbsoluteURL` class, which was deprecated and removed in `zope.traversing` version 4.0.fixInstead of `from zope.traversing.browser import AbsoluteURL`, use the utility function: `from zope.traversing.browser import absoluteURL`. -
TypeError: traverse() missing 1 required positional argument: 'path'
cause The `zope.traversing.api.traverse` function requires at least two arguments: the object to start traversing from and the path string.fixEnsure you call `traverse` with both the root object and the path, e.g., `traverse(root_object, 'segment1/segment2')`. -
KeyError: 'some_missing_name'
cause The traversal mechanism (`ITraversable`'s `traverse` method or `IPathAdapter`) could not find an object matching the current path segment.fixThis is often expected behavior. If it's not, verify the path string is correct, ensure the intermediate objects in the hierarchy are correctly set up and implement `ITraversable` (or have registered `IPathAdapter`s), and that the names exist within their respective containers.
Warnings
- breaking zope.traversing version 6.0 and higher require Python 3.9 or newer. Running on older Python versions will result in `ImportError` or `SyntaxError` depending on the exact Python features used by the package.
- deprecated The `zope.traversing.browser.AbsoluteURL` class and the `zope.traversing.browser.interfaces.IAbsoluteURL` interface were removed in version 4.0. Direct instantiation of `AbsoluteURL` or implementing `IAbsoluteURL` will no longer work.
- gotcha When implementing custom traversal logic using `ITraversable` or `IPathAdapter`, incorrect handling of names or edge cases can lead to `KeyError`, `AttributeError`, or even infinite recursion if not carefully managed. Ensure your `traverse` method explicitly raises `KeyError` (or an appropriate `NotFound` exception) for unresolvable names.
Install
-
pip install zope-traversing
Imports
- traverse
from zope.traversing.api import traverse
- ITraversable
from zope.traversing.interfaces import ITraversable
- IPathAdapter
from zope.traversing.interfaces import IPathAdapter
- absoluteURL
from zope.traversing.browser import AbsoluteURL
from zope.traversing.browser import absoluteURL
Quickstart
from zope.interface import implementer
from zope.traversing.interfaces import ITraversable
from zope.traversing.api import traverse
# Define a simple traversable object (e.g., a Folder)
@implementer(ITraversable)
class Folder:
def __init__(self, name, parent=None):
self.__name__ = name
self.__parent__ = parent
self.contents = {}
def __setitem__(self, name, item):
item.__name__ = name
item.__parent__ = self
self.contents[name] = item
def __getitem__(self, name):
if name in self.contents:
return self.contents[name]
raise KeyError(f"No item named '{name}'")
def traverse(self, name, furtherPath): # furtherPath is usually ignored for simple dict-like traversal
# Default traversal: look up in contents
return self.contents[name]
def __repr__(self):
return f"<Folder '{self.__name__}'>"
class Document:
def __init__(self, name, content="", parent=None):
self.__name__ = name
self.__parent__ = parent
self.content = content
def __repr__(self):
return f"<Document '{self.__name__}'>"
# Build a hierarchy
root = Folder('')
products_folder = Folder('products')
root['products'] = products_folder
products_folder['book1'] = Document('book1', "The first book.")
products_folder['book2'] = Document('book2', "The second book.")
# Traverse to an item
try:
item = traverse(root, 'products/book1')
print(f"Found item at 'products/book1': {item}")
# Attempt to traverse to a non-existent item
non_existent_item = traverse(root, 'products/nonexistent')
print(f"Found non-existent item: {non_existent_item}") # This line won't be reached
except KeyError as e:
print(f"Error traversing to 'products/nonexistent': {e} (expected behavior)")
# Traverse to a sub-path within an item if it also implements ITraversable
# (not shown in this basic example for Document, but would work for nested Folders)