Registry / serialization / zope-cachedescriptors

zope-cachedescriptors

JSON →
library6.0pypypi✓ verified 84d ago

Zope Cache Descriptors is a Python library from the Zope Foundation providing `cached` method and `CachedProperty` decorators for easy result caching. It's currently at version 6.0, supports Python 3.9+, and sees active maintenance with releases roughly aligning with major Python version support cycles. It's designed for simple, in-memory caching of computation results.

pip install zope-cachedescriptors
INSTALL
IMPORT
SIG · ZOPE-CACHEDESCRIPT
Z
zope-cachedescriptors
serializationpythonv6.0
Install
1.8s avg
Import
Disk
19MB
Pass rate
10/ 10
Env Coverage10 / 10
glibc
3.93.13
musl
3.93.13
Install & Compatibility
Where this runs
tested against v6.0 · pip install
no network on importno background threads
Install × environment matrix
Each cell = how many times install + import succeeded across repeated harness runs. Partial = flaky.
glibc = Debian/Ubuntu slim · musl = Alpine Linux
musl
py 3.103.910 runs
installs and imports cleanly · install 0.0s · import 0.000s · 17.9MB
glibc
py 3.103.910 runs
installs and imports cleanly · install 1.8s · import 0.000s · 18MB
19MB installed
● package 19MB
Code
Verified usage

Verified import paths — ran on the pinned version, not inferred.

CachedProperty
from zope.cachedescriptors.property import CachedProperty
from zope.cachedescriptors import CachedProperty
CachedProperty is located in the 'property' submodule.
cached
from zope.cachedescriptors.method import cached
from zope.cachedescriptors import cached
The cached decorator is located in the 'method' submodule.

Demonstrates basic usage of `CachedProperty` and `cached` decorators, including how to access cached values and perform explicit invalidation for both properties and methods. Note the distinct invalidation patterns for each.

from zope.cachedescriptors.property import CachedProperty from zope.cachedescriptors.method import cached import time class DataFetcher: def __init__(self, id_val): self.id = id_val self._fetch_count = 0 @CachedProperty def expensive_property(self): self._fetch_count += 1 print(f" [Property] Fetching data for {self.id}... (call {self._fetch_count})") time.sleep(0.1) # Simulate network delay return f"Data for {self.id}-{time.time()}" @cached def expensive_method(self, param): self._fetch_count += 1 print(f" [Method] Fetching data for {self.id} with param {param}... (call {self._fetch_count})") time.sleep(0.1) # Simulate network delay return f"Result for {self.id}-{param}-{time.time()}" # Example Usage fetcher = DataFetcher("user123") print("--- CachedProperty Demo ---") result1 = fetcher.expensive_property print(f"Property 1: {result1}") result2 = fetcher.expensive_property # Should be cached print(f"Property 2: {result2}") assert result1 == result2 # Invalidate the property cache by deleting the attribute del fetcher.expensive_property result3 = fetcher.expensive_property # Should re-calculate print(f"Property 3 (after invalidation): {result3}") assert result1 != result3 print("\n--- CachedMethod Demo ---") method_result1 = fetcher.expensive_method("report_a") print(f"Method 1: {method_result1}") method_result2 = fetcher.expensive_method("report_a") # Should be cached print(f"Method 2: {method_result2}") assert method_result1 == method_result2 # Invalidate a specific method call with arguments fetcher.expensive_method.invalidate(fetcher, "report_a") method_result3 = fetcher.expensive_method("report_a") # Should re-calculate print(f"Method 3 (after invalidation): {method_result3}") assert method_result1 != method_result3 method_result4 = fetcher.expensive_method("report_b") # New argument, new cache entry print(f"Method 4: {method_result4}")
Debug
Known issues
breakingVersion 6.0 drops support for Python 3.8 and Zope 4. Upgrading on older environments will lead to import errors or runtime issues.
fix
Ensure your environment uses Python 3.9+ and Zope 5+ before upgrading to zope-cachedescriptors 6.0.0 or newer.
affects: 6.0.0+
breakingIn version 6.0, `CachedProperty` no longer subclasses Python's built-in `property`. Code relying on `isinstance(obj.my_prop, property)` will now return `False`.
fix
Update any type checks or code that expects `CachedProperty` to inherit from `property`. Consider using `hasattr(obj, 'my_prop')` or checking the specific `CachedProperty` type if necessary.
affects: 6.0.0+
breakingStarting with version 6.0, `cached` methods (e.g., `obj.my_method`) are now instances of `CachedMethod` (a callable object) rather than the raw function. This can impact introspection or direct manipulation of the underlying function.
fix
If you need access to the original unwrapped function, use `obj.my_method.__wrapped__`. Adjust any code that assumed `obj.my_method` would be the plain function object.
affects: 6.0.0+
gotchaCache invalidation is explicit. Forgetting to invalidate a cache entry after the underlying data changes will lead to stale data being returned.
fix
Always remember to explicitly invalidate caches when the source data changes: use `del obj.property_name` for `CachedProperty` and `obj.method_name.invalidate(obj, *args)` or `obj.method_name.invalidate_all(obj)` for `cached` methods.
affects: All versions
gotchaIf the result of a cached method/property is a mutable object (e.g., list, dict), subsequent modifications to that object will be reflected in all cached accesses. This can lead to unexpected side effects or data corruption.
fix
Ensure cached methods/properties return immutable objects, or return a *copy* of a mutable object if modifications are expected elsewhere. E.g., `return my_list[:]` or `return my_dict.copy()`.
affects: All versions
Errors
Common errors & fixes
AttributeError: 'CachedProperty' object has no attribute 'invalidate'
Attempting to invalidate a `CachedProperty` using a method-style invalidation call (like `obj.prop.invalidate()`) which is meant for `cached` methods.
fix
Cached properties are invalidated by deleting the attribute: `del obj.your_property`.
TypeError: cached() missing 1 required positional argument: 'func'
Trying to use `@cached()` without parentheses for the decorator, or trying to call the `cached` decorator directly without providing a function.
fix
`@cached` is a decorator without arguments, so use `@cached` (no parentheses). Ensure it's placed directly above a method definition.
ImportError: cannot import name 'CachedProperty' from 'zope.cachedescriptors'
Incorrect import path. `CachedProperty` and `cached` are in specific submodules, not directly under `zope.cachedescriptors`.
fix
Use the correct import paths: `from zope.cachedescriptors.property import CachedProperty` and `from zope.cachedescriptors.method import cached`.
Upgrade
Version history
6.0latest on PyPI · released Sep 12, 2025
Audit
Dependencies
zope.interfacerequiredRequired for core functionality and introspection within the Zope ecosystem.
zope.securityrequiredRequired for security integration, especially when used in Zope applications. Considered a core dependency.
Agent activity
37 hits · last 30 days
node
30
OpenAI (training)
1
Resources
zope-cachedescriptors — pip install zope-cachedescriptors · libregistry