animedex.models.anime

Anime domain models.

The records in this module compose SourceTag provenance into the typed shape AniList, Jikan, Kitsu, and Shikimori backends populate.

The Anime class is intentionally a common projection: it holds the fields that are reasonably comparable across at least three of the upstreams we target. Per plans/05-python-api.md and the design discussion in #1’s the initial scaffolding closeout, each backend will ship a richer per-backend dataclass under animedex.backends.<name>.models (e.g. AnilistAnime) that exposes the long tail of upstream-specific fields, plus a to_common() -> Anime mapping. Single-backend commands return the rich type; cross-source aggregate commands return Anime.

Per plans/03 §5 every record carries source so attribution survives every later hop (cache, render, JSON pipeline).

AnimeStatus

animedex.models.anime.AnimeStatus

Canonical airing-status enum. Per-backend mappings normalise to these values; an unrecognised upstream status maps to "unknown".

alias of Literal[‘airing’, ‘finished’, ‘upcoming’, ‘cancelled’, ‘hiatus’, ‘unknown’]

AnimeFormat

animedex.models.anime.AnimeFormat

Canonical media-format enum. Per-backend mappings normalise to these values. Unrecognised formats are dropped (left as None).

alias of Literal[‘TV’, ‘TV_SHORT’, ‘MOVIE’, ‘OVA’, ‘ONA’, ‘SPECIAL’, ‘MUSIC’]

AnimeSeason

animedex.models.anime.AnimeSeason

Broadcast season. The ISO seasons map cleanly across AniList, Kitsu, MAL/Jikan, Shikimori.

alias of Literal[‘WINTER’, ‘SPRING’, ‘SUMMER’, ‘FALL’]

AnimeTitle

class animedex.models.anime.AnimeTitle(*, romaji: str, english: str | None = None, native: str | None = None)[source]

Bases: AnimedexModel

Multi-locale title block.

Variables:
  • romaji (str) – Romanised Japanese title; the canonical machine form for fuzzy match.

  • english (str or None) – Localised English title when one exists.

  • native (str or None) – Native-script title (typically Japanese).

romaji: str
english: str | None
native: str | None

AnimeRating

class animedex.models.anime.AnimeRating(*, score: float, scale: float, votes: int | None = None)[source]

Bases: AnimedexModel

Numeric score from one upstream.

Variables:
  • score (float) – Reported rating, in the upstream’s native scale.

  • scale (float) – Maximum possible score (e.g. 10.0 or 100.0). Stored explicitly so cross-source comparisons can normalise.

  • votes (int or None) – Total ratings cast when the upstream exposes the count.

score: float
scale: float
votes: int | None

NextAiringEpisode

class animedex.models.anime.NextAiringEpisode(*, airing_at: datetime, time_until_airing_seconds: int, episode: int)[source]

Bases: AnimedexModel

The next-up unaired episode for a currently-airing series.

Populated from AniList’s nextAiringEpisode block. The same information is occasionally available via Jikan’s broadcast field but with less precision (a weekday + time-of-day, not an absolute timestamp); the mapper for Jikan leaves this field None and surfaces broadcast info via JikanAnime.broadcast.

Variables:
  • airing_at (datetime.datetime) – Exact UTC timestamp the episode airs.

  • time_until_airing_seconds (int) – Server-computed delta from the moment of the API call. The receiver should treat this as advisory; airing_at is the authoritative value.

  • episode (int) – Sequence number of the upcoming episode.

airing_at: datetime
time_until_airing_seconds: int
episode: int

AiringScheduleRow

class animedex.models.anime.AiringScheduleRow(*, title: str, airing_at: ~datetime.datetime | None = None, episode: int | None = None, weekday: str | None = None, local_time: str | None = None, source: ~animedex.models.common.SourceTag, core: ~typing.Dict[str, ~typing.Any] = <factory>, details: ~typing.Dict[str, ~typing.Any] = <factory>, source_payload: ~typing.Dict[str, ~typing.Any] = <factory>)[source]

Bases: AnimedexModel

Common projection for a single airing schedule row.

Variables:
  • title (str) – Display title of the airing series.

  • airing_at (datetime.datetime or None) – Exact UTC airing instant when available.

  • episode (int or None) – Episode number when reported.

  • weekday (str or None) – Lowercase weekday name when the upstream only reports a weekly schedule.

  • local_time (str or None) – Local clock time string from the upstream.

  • source (SourceTag) – Provenance tag.

  • core (dict) – Compact aggregate-facing summary. JSON consumers can read this first and then inspect details / source_payload for the full source-specific row.

  • details (dict) – Additional source-specific schedule fields kept in a namespaced dictionary for aggregate consumers.

  • source_payload (dict) – Full backend row payload when an aggregate command can preserve it.

title: str
airing_at: datetime | None
episode: int | None
weekday: str | None
local_time: str | None
source: SourceTag
core: Dict[str, Any]
details: Dict[str, Any]
source_payload: Dict[str, Any]

Anime

class animedex.models.anime.Anime(*, id: str, title: AnimeTitle, score: AnimeRating | None = None, episodes: int | None = None, studios: List[str] = [], streaming: List[AnimeStreamingLink] = [], description: str | None = None, genres: List[str] = [], tags: List[str] = [], status: Literal['airing', 'finished', 'upcoming', 'cancelled', 'hiatus', 'unknown'] | None = None, format: Literal['TV', 'TV_SHORT', 'MOVIE', 'OVA', 'ONA', 'SPECIAL', 'MUSIC'] | None = None, season: Literal['WINTER', 'SPRING', 'SUMMER', 'FALL'] | None = None, season_year: int | None = None, aired_from: date | None = None, aired_to: date | None = None, duration_minutes: int | None = None, cover_image_url: str | None = None, banner_image_url: str | None = None, trailer_url: str | None = None, source_material: str | None = None, country_of_origin: str | None = None, is_adult: bool | None = None, age_rating: str | None = None, title_synonyms: List[str] = [], popularity: int | None = None, favourites: int | None = None, trending: int | None = None, next_airing_episode: NextAiringEpisode | None = None, ids: Dict[str, str], source: SourceTag)[source]

Bases: AnimedexModel

An anime record as returned by any single backend.

The field set is the cross-source projection: every field is expected to be populated by at least three of the upstreams we target (AniList, Jikan, Kitsu, Shikimori, ANN, AniDB), or is a backend-specific value that an aggregate consumer can ignore (e.g. streaming, which is effectively Kitsu-only).

Backends that expose richer data ship per-backend dataclasses under animedex.backends.<name>.models and provide to_common() -> Anime to project onto this shape.

Variables:
  • id (str) – Canonical "<source>:<id>" identifier.

  • title (AnimeTitle) – Multi-locale title block.

  • score (AnimeRating or None) – Score from the answering backend, when reported.

  • episodes (int or None) – Episode count, when known.

  • studios (list of str) – Production studios, in the upstream’s order.

  • streaming (list of AnimeStreamingLink) – Legal streaming destinations.

  • description (str or None) – Synopsis / description (free text; may be markdown or HTML depending on the upstream).

  • genres (list of str) – Curated, broad genre tags (e.g. "Adventure", "Drama"). Smaller and stabler than tags; AniList separates these explicitly.

  • tags (list of str) – Long-tail descriptive tags (e.g. "Slow Burn", "Magic"). May be empty when the upstream does not separate from genres.

  • status (str or None) – Airing status, normalised to AnimeStatus.

  • format (str or None) – Media format, normalised to AnimeFormat.

  • season (str or None) – Broadcast season, normalised to AnimeSeason.

  • season_year (int or None) – Calendar year of the broadcast season.

  • aired_from (datetime.date or None) – Date of the first aired episode.

  • aired_to (datetime.date or None) – Date of the last aired episode (or None when still airing).

  • duration_minutes (int or None) – Per-episode duration in minutes.

  • cover_image_url (str or None) – Cover image URL.

  • banner_image_url (str or None) – Banner image URL when one is exposed.

  • trailer_url (str or None) – Trailer URL when one is exposed.

  • source_material (str or None) – Origin story type (e.g. "manga", "light_novel", "original"); free-form because backend vocabularies vary.

  • country_of_origin (str or None) – ISO 3166-1 alpha-2 country code.

  • is_adult (bool or None) – True for adult-only content. None when the upstream does not expose the flag.

  • age_rating (str or None) – Free-form rating string (e.g. "PG-13", "TV-MA"); upstream vocabularies vary.

  • title_synonyms (list of str) – Alternative-language / fan-translation titles. Filled from Jikan title_synonyms (transliterations, English short forms) and AniList synonyms (community- contributed titles).

  • popularity (int or None) – Popularity metric; the meaning is upstream- specific (rank, favourites, member count).

  • favourites (int or None) – Count of users who marked the title as favourite (AniList-only; Jikan reports this separately).

  • trending (int or None) – AniList trending rank at fetch time. Lower is more-trending; None from non-AniList sources.

  • next_airing_episode (NextAiringEpisode or None) – Upcoming episode for currently-airing series. None for finished / upcoming-but-no-schedule shows.

  • ids (dict[str, str]) – Cross-service identifier map (e.g. {"mal": "52991", "kitsu": "47390"}).

  • source (SourceTag) – Provenance tag.

id: str
title: AnimeTitle
score: AnimeRating | None
episodes: int | None
studios: List[str]
streaming: List[AnimeStreamingLink]
description: str | None
genres: List[str]
tags: List[str]
status: AnimeStatus | None
format: AnimeFormat | None
season: AnimeSeason | None
season_year: int | None
aired_from: date | None
aired_to: date | None
duration_minutes: int | None
cover_image_url: str | None
banner_image_url: str | None
trailer_url: str | None
source_material: str | None
country_of_origin: str | None
is_adult: bool | None
age_rating: str | None
title_synonyms: List[str]
popularity: int | None
favourites: int | None
trending: int | None
next_airing_episode: NextAiringEpisode | None
ids: Dict[str, str]
source: SourceTag

selftest

animedex.models.anime.selftest() bool[source]

Smoke-test the anime model graph.

Instantiates and JSON-round-trips an Anime containing every optional field so future schema regressions surface in the diagnostic, not at first real backend hit.

Returns:

True on success; raises on schema errors.

Return type:

bool