Source code for animedex.config.profile

"""
Programmatic configuration object for animedex callers.

:class:`Config` is the typed, immutable equivalent of the CLI's flag
stack. Every public API function in :mod:`animedex` accepts an
optional ``config`` keyword argument and falls back to module-level
defaults when not given. The CLI translates flags into a
:class:`Config` instance one-to-one and hands it off; downstream
Python users construct a :class:`Config` directly.

The fields here are deliberately a 1:1 mirror of the CLI flags
defined in ``plans/03 ยง9`` so that "what does this command do" and
"what does this Python call do" stay in lock-step.
"""

from __future__ import annotations

from typing import Optional

try:
    from typing import Literal
except ImportError:  # pragma: no cover - Python <3.8 not supported
    from typing_extensions import Literal  # type: ignore

from pydantic import BaseModel, ConfigDict

from animedex.auth.store import TokenStore


_RateLiteral = Literal["normal", "slow"]


[docs] class Config(BaseModel): """Frozen configuration object. :ivar rate: Voluntary rate-limit slowdown. ``"slow"`` halves the default refill rate; ``"normal"`` is the upstream- sanctioned default. We do not expose a faster mode because that would violate P1 caps. :vartype rate: Literal["normal", "slow"] :ivar cache_ttl_seconds: Override for the per-row TTL applied to new cache entries. ``None`` means each call uses the default for its category. :vartype cache_ttl_seconds: int or None :ivar no_cache: When ``True`` the call bypasses the cache for both reads and writes. :vartype no_cache: bool :ivar source_attribution: When ``True`` (the default) the JSON renderer includes ``_source`` on every field. The TTY renderer always shows the source column. :vartype source_attribution: bool :ivar user_agent: Override for the User-Agent string. ``None`` means the project default (:func:`animedex.transport.useragent.default_user_agent`). :vartype user_agent: str or None :ivar timeout_seconds: HTTP request timeout in seconds. :vartype timeout_seconds: float :ivar token_store: Caller-supplied :class:`~animedex.auth.store.TokenStore`. ``None`` means resolve lazily to a :class:`~animedex.auth.keyring_store.KeyringTokenStore` on first use. :vartype token_store: TokenStore or None """ model_config = ConfigDict( frozen=True, arbitrary_types_allowed=True, extra="forbid", ) rate: _RateLiteral = "normal" cache_ttl_seconds: Optional[int] = None no_cache: bool = False source_attribution: bool = True user_agent: Optional[str] = None timeout_seconds: float = 30.0 token_store: Optional[TokenStore] = None
[docs] def effective_token_store(self) -> TokenStore: """Resolve :attr:`token_store` to a usable :class:`~animedex.auth.store.TokenStore`. Returns the explicitly-supplied store when one was passed, otherwise constructs a fresh :class:`~animedex.auth.keyring_store.KeyringTokenStore`. The construction is deferred to call time so an environment without a real OS keyring backend does not break a code path that never actually needs credentials. :return: A :class:`TokenStore` ready for use. :rtype: TokenStore """ if self.token_store is not None: return self.token_store from animedex.auth.keyring_store import KeyringTokenStore return KeyringTokenStore()
[docs] def selftest() -> bool: """Smoke-test the :class:`Config` object. Constructs the zero-arg default and a fully-populated instance, verifies the rate literal validation, and resolves the default token store; all of this stays in process memory. :return: ``True`` on success. :rtype: bool """ cfg = Config() assert cfg.rate == "normal" full = Config( rate="slow", cache_ttl_seconds=10, no_cache=True, source_attribution=False, user_agent="x/1", timeout_seconds=5.0, ) assert full.timeout_seconds == 5.0 cfg.effective_token_store() return True