ddp_utils.runtime.cache_storage¶
import ddp_utils.runtime.cache_storage
Provide persistent namespaced cache storage over RuntimePaths.
CacheStorage supports JSON, text, and byte values, atomic writes, per-key
locking, expiration times, and removal of stale entries.
Examples
Use this public operation:
from ddp_utils.runtime.cache_storage import CacheStorage
cache = CacheStorage("example")
- class ddp_utils.runtime.cache_storage.CacheStorage(namespace: str, *, create_now: bool = True)¶
Bases:
objectPersistent namespace cache storage.
The storage operates inside
RuntimePaths.cache_rootand provides a small production-oriented API for storing and retrieving structured or raw cache items.Main features:
namespaced cache root;
JSON storage helpers;
text and bytes helpers;
atomic writes;
optional per-key locking;
optional TTL-based validity checks;
cleanup helpers for stale files.
Cache organization:
.ddp/ <namespace>/ cache/ <group>/ <key>.json <key>.txt <key>.binParameters
Name
Type
Description
namespace
str
Nonempty filesystem-safe namespace of the owning component.
create_now
bool
Create the runtime and cache roots immediately when
True.Examples
Create an isolated logical cache namespace:
cache = CacheStorage("reports")
Bind cache operations to one runtime namespace.
Construction also performs the throttled expired-runtime cleanup owned by
RuntimePaths. Whencreate_nowis true, runtime directories and the cache root are created immediately.Parameters
Name
Type
Description
namespace
str
Non-empty filesystem-safe cache namespace.
create_now
bool
Create runtime and cache directories during initialization.
Falsedefers cache-directory creation.Raises
Exception
Description
ValueError
namespaceis empty or invalid.OSError
Required runtime directories cannot be created or expired runtime state cannot be processed.
Examples
Describe a cache without eagerly creating its directories:
cache = CacheStorage("reports", create_now=False)
- property root: Path¶
Return the namespace cache root.
Returns
Absolute namespace path ending in
cache. Accessing this property does not itself create the directory.Examples
Inspect the configured cache root:
root = cache.root
- group_root(group: str) Path¶
Return the root directory for a logical cache group.
Parameters
Name
Type
Description
group
str
Nonempty filesystem-safe group name, such as
drivers.Returns
Type
Description
Path
Group directory below
root. The directory and missing parents are created before return.Raises
Exception
Description
ValueError
groupis empty after normalization.OSError
The group directory cannot be created.
Examples
Create or reuse a logical group:
drivers = cache.group_root("drivers")
- path(key: str, *, group: str = 'default', suffix: str = '.json') Path¶
Build a cache file path.
Parameters
Name
Type
Description
key
str
Nonempty logical cache key normalized for use as a filename.
group
str
Nonempty logical group whose directory is created as needed.
suffix
str
Filename suffix appended unchanged, normally including its leading dot.
Returns
Type
Description
Path
Path below the selected group. The file itself is not created.
Raises
Exception
Description
ValueError
keyorgroupis empty after normalization.OSError
The group directory cannot be created.
Examples
Build a path without writing its cache entry:
target = cache.path("latest", group="reports", suffix=".json")
- hashed_path(value: str, *, group: str = 'default', suffix: str = '.json', algorithm: str = 'sha256') Path¶
Build a cache file path using a hash of the input value.
This is useful for long URLs, query strings, or other values not suitable as a direct file name.
Parameters
Name
Type
Description
value
str
Text encoded as UTF-8 before hashing.
group
str
Nonempty logical group whose directory is created as needed.
suffix
str
Filename suffix appended to the hexadecimal digest.
algorithm
str
Algorithm accepted by
hashlib.new().Returns
Type
Description
Path
Cache path whose filename is the hexadecimal digest plus
suffix.Raises
Exception
Description
ValueError
algorithmis unavailable orgroupis empty.OSError
The group directory cannot be created.
Examples
Derive a stable path for a long URL:
target = cache.hashed_path("https://example.com/report?id=42")
- exists(key: str, *, group: str = 'default', suffix: str = '.json') bool¶
Check whether a cache item exists.
Parameters
Name
Type
Description
key
str
Logical cache key.
group
str
Logical cache group.
suffix
str
Cache filename suffix.
Returns
Type
Description
bool
Truewhen the computed path exists as any filesystem entry; otherwiseFalse.Examples
Test for a JSON entry:
present = cache.exists("latest", group="reports")
- is_fresh(key: str, *, group: str = 'default', suffix: str = '.json', ttl_seconds: float | None = None) bool¶
Check whether a cache item is fresh according to TTL.
If
ttl_secondsisNone, the item is considered fresh if it exists.Parameters
Name
Type
Description
key
str
Logical cache key.
group
str
Logical cache group.
suffix
str
Cache filename suffix.
ttl_seconds
float | None
Maximum age in seconds.
Noneaccepts any existing item; a negative value makes every existing item stale.Returns
Type
Description
bool
Truewhen the path exists and its age does not exceed the supplied TTL, or when no TTL is supplied.Raises
Exception
Description
OSError
Metadata for an existing path cannot be read.
Examples
Accept an entry written within the last hour:
fresh = cache.is_fresh("latest", ttl_seconds=3600)
- read_text(key: str, *, group: str = 'default', encoding: str = 'utf-8', suffix: str = '.txt', ttl_seconds: float | None = None) str | None¶
Read a text cache item.
If the file does not exist or is stale according to TTL, return
None.Parameters
Name
Type
Description
key
str
Logical cache key.
group
str
Logical cache group.
encoding
str
Text codec used to decode the file.
suffix
str
Cache filename suffix.
ttl_seconds
float | None
Maximum accepted age.
Nonedisables age checks.Returns
Type
Description
str | None
Decoded text, or
Nonewhen the entry is missing, stale, unreadable, or cannot be decoded. Read failures are intentionally soft.Examples
Read an optional cached report:
report = cache.read_text("latest", group="reports")
- write_text(key: str, value: str, *, group: str = 'default', encoding: str = 'utf-8', suffix: str = '.txt', use_lock: bool = False) Path¶
Write a text cache item atomically.
Parameters
Name
Type
Description
key
str
Logical cache key.
value
str
Text payload written through a temporary sibling file.
group
str
Logical cache group.
encoding
str
Text codec used for serialization.
suffix
str
Cache filename suffix.
use_lock
bool
Acquire a namespace lock for this group and key before replacing the target when
True.Returns
Type
Description
Path
Final cache path after atomic replacement succeeds.
Raises
Exception
Description
OSError
Directory creation, temporary writing, locking, or atomic replacement fails.
Examples
Atomically store a text report:
target = cache.write_text("latest", "ready", group="reports")
- read_bytes(key: str, *, group: str = 'default', suffix: str = '.bin', ttl_seconds: float | None = None) bytes | None¶
Read a binary cache item.
Parameters
Name
Type
Description
key
str
Logical cache key.
group
str
Logical cache group.
suffix
str
Cache filename suffix.
ttl_seconds
float | None
Maximum accepted age.
Nonedisables age checks.Returns
Type
Description
bytes | None
File bytes, or
Nonewhen the entry is missing, stale, or unreadable. Read failures are intentionally soft.Examples
Read an optional binary artifact:
payload = cache.read_bytes("archive", group="downloads")
- write_bytes(key: str, value: bytes, *, group: str = 'default', suffix: str = '.bin', use_lock: bool = False) Path¶
Write a binary cache item atomically.
Parameters
Name
Type
Description
key
str
Logical cache key.
value
bytes
Binary payload written through a temporary sibling file.
group
str
Logical cache group.
suffix
str
Cache filename suffix.
use_lock
bool
Acquire a namespace lock for this group and key before replacing the target when
True.Returns
Type
Description
Path
Final cache path after atomic replacement succeeds.
Raises
Exception
Description
OSError
Directory creation, temporary writing, locking, or atomic replacement fails.
Examples
Atomically store a binary artifact:
target = cache.write_bytes("archive", b"payload")
- read_json(key: str, *, group: str = 'default', suffix: str = '.json', ttl_seconds: float | None = None) Any | None¶
Read a JSON cache item.
Parameters
Name
Type
Description
key
str
Logical cache key.
group
str
Logical cache group.
suffix
str
Cache filename suffix.
ttl_seconds
float | None
Maximum accepted age.
Nonedisables age checks.Returns
Type
Description
Any | None
Decoded JSON value, or
Nonewhen the entry is missing, stale, unreadable, or invalid JSON. These failures are intentionally soft, so a cached JSONnullis indistinguishable from failure.Examples
Read optional structured state:
state = cache.read_json("state")
- write_json(key: str, value: Any, *, group: str = 'default', suffix: str = '.json', ensure_ascii: bool = False, indent: int | None = None, use_lock: bool = False) Path¶
Write a JSON cache item atomically.
Parameters
Name
Type
Description
key
str
Logical cache key.
value
Any
JSON-serializable value.
group
str
Logical cache group.
suffix
str
Cache filename suffix.
ensure_ascii
bool
Escape non-ASCII characters when
True.indent
int | None
Optional JSON indentation level.
Noneproduces compact output.use_lock
bool
Acquire a namespace lock for this group and key before replacing the target when
True.Returns
Type
Description
Path
Final cache path after serialization and atomic replacement.
Raises
Exception
Description
TypeError
valuecontains an unsupported JSON value.ValueError
JSON serialization rejects a value such as a circular structure.
OSError
Directory creation, locking, writing, or replacement fails.
Examples
Store structured state with readable formatting:
target = cache.write_json("state", {"ready": True}, indent=2)
- delete(key: str, *, group: str = 'default', suffix: str = '.json') bool¶
Delete a cache item.
Parameters
Name
Type
Description
key
str
Logical cache key.
group
str
Logical cache group.
suffix
str
Cache filename suffix.
Returns
Type
Description
bool
Truewhen an existing path was removed;Falsewhen no path existed. The group directory is retained.Raises
Exception
Description
OSError
The existing path cannot be removed.
Examples
Delete an optional entry:
removed = cache.delete("state")
- clear_group(group: str) None¶
Remove a whole cache group and recreate it.
Parameters
Name
Type
Description
group
str
Nonempty logical group to reset.
Note
Removal errors are ignored by
shutil.rmtree. The method then recreates the group directory, so it is not an atomic clear.Raises
Exception
Description
ValueError
groupis empty after normalization.OSError
The group directory cannot be recreated.
Examples
Reset one logical group:
cache.clear_group("reports")
- cleanup_stale(*, older_than_seconds: float, group: str | None = None) int¶
Remove cache files older than the given age.
Parameters
Name
Type
Description
older_than_seconds
float
Inclusive age threshold in seconds. Negative values make every discovered file eligible.
group
str | None
Optional group to scan.
Nonescans every immediate group directory below the cache root.Returns
Type
Description
int
Number of files successfully removed. Per-file metadata and removal failures are skipped and not counted.
Examples
Remove entries at least one day old:
removed = cache.cleanup_stale(older_than_seconds=86400)
- cleanup_empty_dirs() int¶
Remove empty directories inside the cache root.
Returns
Type
Description
int
Number of directories successfully removed, deepest first. The cache root itself is retained, and inspection failures are skipped.
Examples
Prune empty group subdirectories:
removed = cache.cleanup_empty_dirs()