acres: Access Resources on Your Terms
acres is a Python library designed to simplify access to package resources, offering a consistent API for reading, filesystem access, and cached filesystem access. It addresses common pitfalls associated with `importlib.resources` by clearly delineating resource scopes and capabilities. The current version is 0.5.0, with releases occurring periodically, typically every few months, for new features, improvements, and bug fixes.
Warnings
- breaking The recommended anchor for `Loader` changed from `Loader(__package__)` to `Loader(__spec__.name)` in version 0.2.0. `__package__` can be `None` during zip imports before Python 3.10 and is deprecated in Python 3.13 (to be removed in 3.15).
- breaking Support for Python 3.8 was dropped in version 0.3.0.
- deprecated The `importlib_resources` backport is no longer a dependency, even for older Python versions, as of version 0.4.0.
- gotcha `Loader(..., list_contents=True)` is now opt-in as of version 0.5.0 to list top-level package contents.
- gotcha When working with resource paths, be mindful of their lifetime. `Loader.readable()` returns a `Traversable` object (which may not represent an actual file on disk), `Loader.as_path()` provides a temporary `pathlib.Path` within a `with` block, and `Loader.cached()` provides a `pathlib.Path` that exists for the interpreter's lifetime. Misunderstanding these can lead to `Path` objects pointing to non-existent files, especially with zipped packages.
Install
-
pip install acres
Imports
- Loader
from acres import Loader
- Traversable
import acres.typ as at # then use at.Traversable
Quickstart
from acres import Loader
import os
# Assuming a package structure like:
# my_package/
# __init__.py
# data/
# resource.txt
# Create dummy package for demonstration
if not os.path.exists('my_package/data'):
os.makedirs('my_package/data')
with open('my_package/data/resource.txt', 'w') as f:
f.write('Hello from acres!')
with open('my_package/__init__.py', 'w') as f: # Ensure it's a package
f.write('')
# The recommended way to anchor the Loader is with __spec__.name
# For a real package, you would pass `__spec__.name` from within that package.
# For this example, we'll simulate it with a string.
package_name = 'my_package'
loader = Loader(package_name)
# Read a text resource
text_content = loader.readable('data/resource.txt').read_text()
print(f"Text resource content: {text_content}")
# Access a resource as a temporary file path using a context manager
with loader.as_path('data/resource.txt') as resource_path:
print(f"Resource path (temporary): {resource_path}")
print(f"Content from path: {resource_path.read_text()}")
# Access a resource that exists for the interpreter's lifetime
cached_path = loader.cached('data/resource.txt')
print(f"Resource path (cached, interpreter lifetime): {cached_path}")
print(f"Content from cached path: {cached_path.read_text()}")
# Clean up dummy package
os.remove('my_package/data/resource.txt')
os.rmdir('my_package/data')
os.remove('my_package/__init__.py')
os.rmdir('my_package')