animedex.cache.sqlite

SQLite-backed TTL cache for backend responses.

The cache is the project’s canonical storage for upstream responses; it is consulted before any HTTP call and populated after one. The shape is:

  • Rows are keyed by (backend, signature).

  • The body is stored as raw bytes; pydantic models are persisted as model.model_dump_json().encode("utf-8") and re-hydrated with Model.model_validate_json(raw.decode()).

  • Each row carries a TTL (seconds-since-epoch expires_at); a row whose expires_at is in the past is treated as missing.

The defaults in default_ttl_seconds() come from plans/03 §10: 72 h for metadata, 24 h for list pages, 1 h for schedule / trending, 30 d for offline dumps. Anything else gets the “metadata” default.

The clock primitive (_utcnow) and the cache-dir resolver (_user_cache_dir) are pulled through indirection points so unit tests can substitute deterministic fakes without monkeypatching the standard library globally.

SqliteCache

class animedex.cache.sqlite.SqliteCache(path: Path | str | None = None)[source]

Bases: object

A small SQLite-backed cache with per-row TTL.

Parameters:

path (pathlib.Path or str or None) – Filesystem path to the SQLite database file. Defaults to default_cache_path().

__init__(path: Path | str | None = None) None[source]
close() None[source]

Close the underlying SQLite connection.

Returns:

None.

Return type:

None

__enter__() SqliteCache[source]
__exit__(*_excinfo: object) None[source]
set(backend: str, signature: str, payload: bytes, *, ttl_seconds: int) None[source]

Store or overwrite a row (v1 wrapper).

Exists for callers that don’t need the v2 metadata. Internally delegates to set_with_meta() with response_headers={}, so a subsequent get_with_meta returns a valid row with fetched_at=now and an empty headers dict.

Parameters:
  • backend (str) – Backend identifier (e.g. "anilist").

  • signature (str) – Caller-derived row signature; must be stable across runs for the same logical request.

  • payload (bytes) – Raw bytes to store.

  • ttl_seconds (int) – Lifetime in seconds; get will treat this row as missing once the time elapses.

Returns:

None.

Return type:

None

set_with_meta(backend: str, signature: str, payload: bytes, *, response_headers: Dict[str, str], ttl_seconds: int) None[source]

Store or overwrite a row with v2 metadata.

Parameters:
  • backend (str) – Backend identifier.

  • signature (str) – Caller-derived row signature.

  • payload (bytes) – Raw bytes to store.

  • response_headers (dict[str, str]) – Response headers dict; persisted as JSON-encoded bytes so cache hits in --debug mode can reconstruct the full envelope.

  • ttl_seconds (int) – Lifetime in seconds.

Returns:

None.

Return type:

None

get(backend: str, signature: str) bytes | None[source]

Look up a row.

Returns the payload if the row exists and has not expired; None otherwise. Expired rows are not deleted on read (use purge_expired() for that) so a single get stays a pure read.

Parameters:
  • backend (str) – Backend identifier.

  • signature (str) – Caller-derived row signature.

Returns:

Cached payload or None when missing / expired.

Return type:

bytes or None

get_with_meta(backend: str, signature: str) Tuple[bytes, Dict[str, str], datetime | None] | None[source]

Look up a row including v2 metadata.

Parameters:
  • backend (str) – Backend identifier.

  • signature (str) – Caller-derived row signature.

Returns:

(payload, response_headers, fetched_at) triple on hit, None when missing or expired. Migrated v1 rows return an empty headers dict and fetched_at=None.

Return type:

tuple or None

purge_expired() int[source]

Delete every expired row.

Returns:

Number of rows removed.

Return type:

int

default_ttl_seconds

animedex.cache.sqlite.default_ttl_seconds(category: str) int[source]

Return the project-default TTL for a request category.

Per plans/03 §10:

  • metadata: 72 h

  • list: 24 h

  • schedule / trending: 1 h

  • offline_dump: 30 d

Unknown categories collapse to the metadata default; this keeps the cache useful for one-off entries without forcing every call site to declare a category.

Parameters:

category (str) – Request category.

Returns:

Default TTL in seconds.

Return type:

int

default_cache_path

animedex.cache.sqlite.default_cache_path() Path[source]

Resolve the platform-appropriate cache file path.

Uses platformdirs.user_cache_dir() (via the _user_cache_dir indirection) so the location matches the OS convention: ~/.cache/animedex on Linux, ~/Library/Caches/animedex on macOS, the appropriate LOCALAPPDATA subtree on Windows.

Returns:

Path to cache.sqlite inside the cache dir.

Return type:

pathlib.Path

selftest

animedex.cache.sqlite.selftest() bool[source]

Smoke-test the SQLite cache.

Builds a temporary cache file under _user_cache_dir, writes a row, reads it back, lets the test-supplied clock advance past the TTL, and confirms expiry. Cleans up the temporary file before returning.

Returns:

True on success.

Return type:

bool