- Python 100%
|
|
||
|---|---|---|
| .forgejo/workflows | ||
| src/contextually_cached_property | ||
| tests | ||
| .gitignore | ||
| .pre-commit-config.yaml | ||
| LICENSE | ||
| poetry.lock | ||
| poetry.toml | ||
| pyproject.toml | ||
| README.md | ||
contextually-cached-property
A Python descriptor that caches property values per context variable, providing isolated caches for concurrent contexts like asyncio tasks.
Why?
Python's built-in functools.cached_property uses a single cache shared across all contexts. This can cause issues in concurrent applications where different tasks or threads need independent cached values.
contextually_cached_property solves this by using contextvars.ContextVar to maintain separate caches per context, while also using weak references to allow proper garbage collection of instances.
Installation
pip install contextually-cached-property
Requires Python 3.14+.
Usage
from contextually_cached_property import contextually_cached_property
class ExpensiveResource:
@contextually_cached_property
def connection(self) -> Connection:
return create_connection()
The cached value is computed once per context per instance. Different asyncio tasks will each get their own cached value:
import asyncio
class TaskLocalData:
@contextually_cached_property
def request_id(self) -> str:
return generate_unique_id()
data = TaskLocalData()
async def task_a():
print(data.request_id) # e.g., "abc123"
async def task_b():
print(data.request_id) # e.g., "xyz789" (different from task_a)
async def main():
await asyncio.gather(task_a(), task_b())
Invalidating the cache
Delete the attribute to clear the cached value for the current context:
del instance.cached_property_name
Development
This project uses Poetry for dependency management.
# Install dependencies
poetry install
# Run tests
pytest
# Run linting
ruff check
# Run type checking
mypy .
Releasing
This project uses git tags for versioning and automated publishing via Forgejo Actions.
Pre-release (TestPyPI)
Create a pre-release tag to publish to TestPyPI for testing:
git tag v1.0.0-rc1
git push origin v1.0.0-rc1
Production release (PyPI)
Create a release tag to publish to PyPI:
git tag v1.0.0
git push origin v1.0.0
The workflow runs tests, linting, and type checking before publishing.
License
See LICENSE for details.