Skip to content

Interpretation

interpretation

Interpretation data contracts and mapping-backed implementation.

This is the package's public anchor module; it also exposes the distribution version as __version__ (the fortune_telling_core package root belongs to the sibling fortune-telling-core package, so this layer cannot own it there).

InterpretationKey dataclass

InterpretationKey(symbol_id: str, position_id: str | None = None, variant: str | None = None)

Lookup key for interpretation text.

Parameters:

Name Type Description Default
symbol_id str

Symbol identifier to interpret.

required
position_id str | None

Optional spread position identifier.

None
variant str | None

Optional engine-specific variant such as reversed or retrograde.

None

Raises:

Type Description
ValidationError

If symbol_id is empty or optional fields are empty strings.

symbol_id instance-attribute

symbol_id: str

position_id class-attribute instance-attribute

position_id: str | None = None

variant class-attribute instance-attribute

variant: str | None = None

to_dict

to_dict() -> JsonObject

Serialize the key to a JSON-compatible dictionary.

Source code in src/fortune_telling_core/interpretation.py
def to_dict(self) -> JsonObject:
    """Serialize the key to a JSON-compatible dictionary."""

    result: JsonObject = {"symbol_id": self.symbol_id}
    if self.position_id is not None:
        result["position_id"] = self.position_id
    if self.variant is not None:
        result["variant"] = self.variant
    return result

from_dict classmethod

from_dict(data: JsonMapping) -> InterpretationKey

Deserialize an interpretation key.

Parameters:

Name Type Description Default
data JsonMapping

JSON-compatible key mapping.

required

Returns:

Type Description
InterpretationKey

The decoded key.

Raises:

Type Description
ValidationError

If required fields are missing or malformed.

Source code in src/fortune_telling_core/interpretation.py
@classmethod
def from_dict(cls, data: JsonMapping) -> InterpretationKey:
    """Deserialize an interpretation key.

    Args:
        data: JSON-compatible key mapping.

    Returns:
        The decoded key.

    Raises:
        ValidationError: If required fields are missing or malformed.
    """

    return cls(
        symbol_id=require_str(data, "symbol_id"),
        position_id=optional_str(data, "position_id"),
        variant=optional_str(data, "variant"),
    )

InterpretationEntry dataclass

InterpretationEntry(key: InterpretationKey, text: str, keywords: Sequence[str] = (), source: str | None = None)

Textual interpretation for one lookup key.

Parameters:

Name Type Description Default
key InterpretationKey

Lookup key this entry answers.

required
text str

Interpretation text.

required
keywords Sequence[str]

Search or summary keywords.

()
source str | None

Optional citation or dataset source.

None

Raises:

Type Description
ValidationError

If text is empty.

key instance-attribute

key: InterpretationKey

text instance-attribute

text: str

keywords class-attribute instance-attribute

keywords: Sequence[str] = ()

source class-attribute instance-attribute

source: str | None = None

to_dict

to_dict() -> JsonObject

Serialize the entry to a JSON-compatible dictionary.

Source code in src/fortune_telling_core/interpretation.py
def to_dict(self) -> JsonObject:
    """Serialize the entry to a JSON-compatible dictionary."""

    result: JsonObject = {
        "key": self.key.to_dict(),
        "text": self.text,
        "keywords": list(self.keywords),
    }
    if self.source is not None:
        result["source"] = self.source
    return result

from_dict classmethod

from_dict(data: JsonMapping) -> InterpretationEntry

Deserialize an interpretation entry.

Parameters:

Name Type Description Default
data JsonMapping

JSON-compatible entry mapping.

required

Returns:

Type Description
InterpretationEntry

The decoded entry.

Raises:

Type Description
ValidationError

If required fields are missing or malformed.

Source code in src/fortune_telling_core/interpretation.py
@classmethod
def from_dict(cls, data: JsonMapping) -> InterpretationEntry:
    """Deserialize an interpretation entry.

    Args:
        data: JSON-compatible entry mapping.

    Returns:
        The decoded entry.

    Raises:
        ValidationError: If required fields are missing or malformed.
    """

    return cls(
        key=InterpretationKey.from_dict(json_object(data.get("key"), "key")),
        text=require_str(data, "text"),
        keywords=str_sequence(data.get("keywords", []), "keywords"),
        source=optional_str(data, "source"),
    )

InterpretationData

Bases: Protocol

Protocol for interpretation lookup datasets.

id property

id: str

Stable identifier for this interpretation dataset.

lookup

lookup(key: InterpretationKey) -> InterpretationEntry | None

Return the best matching interpretation entry for key.

Parameters:

Name Type Description Default
key InterpretationKey

Desired symbol, position, and variant combination.

required

Returns:

Type Description
InterpretationEntry | None

A matching entry, or None if the dataset has no usable fallback.

Source code in src/fortune_telling_core/interpretation.py
def lookup(self, key: InterpretationKey) -> InterpretationEntry | None:
    """Return the best matching interpretation entry for `key`.

    Args:
        key: Desired symbol, position, and variant combination.

    Returns:
        A matching entry, or `None` if the dataset has no usable fallback.
    """

LocaleDatasetLookup

Bases: Protocol

Locale-aware dataset lookup result.

data instance-attribute

data: InterpretationData | None

requested_locale instance-attribute

requested_locale: str

normalized_locale instance-attribute

normalized_locale: str

resolved_locale instance-attribute

resolved_locale: str

LocaleInterpretationRegistry

Bases: Protocol

Registry protocol implemented by InterpretationRegistry.

datasets instance-attribute

datasets: Mapping[str, InterpretationData]

lookup

lookup(locale: str) -> LocaleDatasetLookup

Return the best dataset for a requested locale.

Source code in src/fortune_telling_core/interpretation.py
def lookup(self, locale: str) -> LocaleDatasetLookup:
    """Return the best dataset for a requested locale."""

MappingInterpretationData dataclass

MappingInterpretationData(id: str, entries: Sequence[InterpretationEntry])

Mapping-backed interpretation dataset with fallback lookup.

Lookup order is exact key, symbol plus variant, symbol plus position, then symbol only.

Parameters:

Name Type Description Default
id str

Stable dataset identifier.

required
entries Sequence[InterpretationEntry]

Interpretation entries in the dataset.

required

Raises:

Type Description
ValidationError

If the id is empty or keys are duplicated.

id instance-attribute

id: str

entries instance-attribute

entries: Sequence[InterpretationEntry]

lookup

lookup(key: InterpretationKey) -> InterpretationEntry | None

Look up an interpretation with graceful fallbacks.

Parameters:

Name Type Description Default
key InterpretationKey

Desired symbol, position, and variant combination.

required

Returns:

Type Description
InterpretationEntry | None

The first matching entry in the fallback chain, or None.

Source code in src/fortune_telling_core/interpretation.py
def lookup(self, key: InterpretationKey) -> InterpretationEntry | None:
    """Look up an interpretation with graceful fallbacks.

    Args:
        key: Desired symbol, position, and variant combination.

    Returns:
        The first matching entry in the fallback chain, or `None`.
    """

    candidates = (
        key,
        InterpretationKey(key.symbol_id, None, key.variant),
        InterpretationKey(key.symbol_id, key.position_id, None),
        InterpretationKey(key.symbol_id, None, None),
    )
    for candidate in candidates:
        entry = self._index.get(candidate)
        if entry is not None:
            return entry
    return None

to_dict

to_dict() -> JsonObject

Serialize the dataset to a JSON-compatible dictionary.

Source code in src/fortune_telling_core/interpretation.py
def to_dict(self) -> JsonObject:
    """Serialize the dataset to a JSON-compatible dictionary."""

    return {
        "id": self.id,
        "entries": [entry.to_dict() for entry in self.entries],
    }

from_dict classmethod

from_dict(data: JsonMapping) -> MappingInterpretationData

Deserialize a mapping-backed interpretation dataset.

Parameters:

Name Type Description Default
data JsonMapping

JSON-compatible dataset mapping.

required

Returns:

Type Description
MappingInterpretationData

The decoded dataset.

Raises:

Type Description
ValidationError

If required fields are missing or malformed.

Source code in src/fortune_telling_core/interpretation.py
@classmethod
def from_dict(cls, data: JsonMapping) -> MappingInterpretationData:
    """Deserialize a mapping-backed interpretation dataset.

    Args:
        data: JSON-compatible dataset mapping.

    Returns:
        The decoded dataset.

    Raises:
        ValidationError: If required fields are missing or malformed.
    """

    return cls(
        id=require_str(data, "id"),
        entries=tuple(
            InterpretationEntry.from_dict(item)
            for item in json_object_sequence(data.get("entries"), "entries")
        ),
    )

interpret

interpret(reading: Reading, dataset_or_registry: object | Sequence[object], *, locale: str = 'en-GB') -> dict[str, InterpretationEntry]

Resolve interpretation entries for a structural core reading.

Parameters:

Name Type Description Default
reading Reading

Core reading produced by a structural engine.

required
dataset_or_registry object | Sequence[object]

One dataset, one locale-aware registry, or a sequence of datasets/registries to compose.

required
locale str

Requested locale when a registry is supplied.

'en-GB'

Returns:

Type Description
dict[str, InterpretationEntry]

Mapping from spread position id to resolved interpretation entry.

Source code in src/fortune_telling_core/interpretation.py
def interpret(
    reading: Reading,
    dataset_or_registry: object | Sequence[object],
    *,
    locale: str = "en-GB",
) -> dict[str, InterpretationEntry]:
    """Resolve interpretation entries for a structural core reading.

    Args:
        reading: Core reading produced by a structural engine.
        dataset_or_registry: One dataset, one locale-aware registry, or a
            sequence of datasets/registries to compose.
        locale: Requested locale when a registry is supplied.

    Returns:
        Mapping from spread position id to resolved interpretation entry.
    """

    datasets = tuple(_resolve_datasets(dataset_or_registry, locale))
    resolved: dict[str, InterpretationEntry] = {}
    for position in reading.positions:
        entry = _resolve_position(position, datasets)
        if entry is not None:
            resolved[position.selection.position_id] = entry
    return resolved

interpret_extras

interpret_extras(reading: Reading, dataset_or_registry: object | Sequence[object], *, locale: str = 'en-GB') -> list[tuple[Selection, InterpretationEntry | None]]

Resolve interpretation entries for a reading's off-grid extras.

A reading's draw.extras holds structured selections not bound to a spread position (e.g. astrology aspects, keyed astro.aspect.<type>), so they fall outside :func:interpret. This resolves each by its symbol_id (a kind modifier, when present, is tried as a variant first).

Parameters:

Name Type Description Default
reading Reading

Core reading produced by a structural engine.

required
dataset_or_registry object | Sequence[object]

One dataset, one locale-aware registry, or a sequence of datasets/registries to compose.

required
locale str

Requested locale when a registry is supplied.

'en-GB'

Returns:

Type Description
list[tuple[Selection, InterpretationEntry | None]]

A list of (selection, entry) in draw order; entry is None

list[tuple[Selection, InterpretationEntry | None]]

when no dataset covers the selection's symbol.

Source code in src/fortune_telling_core/interpretation.py
def interpret_extras(
    reading: Reading,
    dataset_or_registry: object | Sequence[object],
    *,
    locale: str = "en-GB",
) -> list[tuple[Selection, InterpretationEntry | None]]:
    """Resolve interpretation entries for a reading's off-grid extras.

    A reading's ``draw.extras`` holds structured selections not bound to a spread
    position (e.g. astrology aspects, keyed ``astro.aspect.<type>``), so they fall
    outside :func:`interpret`. This resolves each by its ``symbol_id`` (a
    ``kind`` modifier, when present, is tried as a variant first).

    Args:
        reading: Core reading produced by a structural engine.
        dataset_or_registry: One dataset, one locale-aware registry, or a
            sequence of datasets/registries to compose.
        locale: Requested locale when a registry is supplied.

    Returns:
        A list of ``(selection, entry)`` in draw order; ``entry`` is ``None``
        when no dataset covers the selection's symbol.
    """

    datasets = tuple(_resolve_datasets(dataset_or_registry, locale))
    extras = getattr(reading.draw, "extras", ()) or ()
    return [(selection, _resolve_selection(selection, datasets)) for selection in extras]