Skip to content

Petit Lenormand

A Petit Lenormand engine with the 36-card deck and single-card, three-card, and Grand Tableau spreads. Casting is RNG-driven; Lenormand cards are never reversed, and the Grand Tableau lays out the whole deck.

from fortune_telling_core import RandomRng, ReadingRequest
from fortune_telling_core.traditions.lenormand import LENORMAND_DECK, THREE_CARD, build_engine

request = ReadingRequest(deck_id=LENORMAND_DECK.id, spread_id=THREE_CARD.id)
reading = build_engine().read(request, rng=RandomRng(seed=42))

lenormand

LENORMAND_DECK module-attribute

LENORMAND_DECK = Deck(
    id="lenormand.deck.petit.v1",
    symbols=tuple(
        (
            Symbol(
                id=f"lenormand.card.{slug}",
                name=name,
                attributes={
                    "number": str(number),
                    "slug": slug,
                },
            )
        )
        for number, slug, name in _CARDS
    ),
)

GRAND_TABLEAU module-attribute

GRAND_TABLEAU = Spread(
    id="lenormand.spread.grand-tableau.v1",
    name="Grand Tableau",
    positions=tuple(
        (
            Position(
                f"house_{index}",
                f"House {index}",
                f"Tableau position {index}.",
            )
        )
        for index in (range(1, 37))
    ),
)

SINGLE_CARD module-attribute

SINGLE_CARD = Spread(
    id="lenormand.spread.single.v1",
    name="Single Card",
    positions=(
        Position(
            "focus",
            "Focus",
            "The card answering the question.",
        ),
    ),
)

THREE_CARD module-attribute

THREE_CARD = Spread(
    id="lenormand.spread.three.v1",
    name="Three Card Line",
    positions=(
        Position(
            "left",
            "Left",
            "Background, modifying the center.",
        ),
        Position(
            "center", "Center", "The heart of the matter."
        ),
        Position(
            "right",
            "Right",
            "Outcome, modifying the center.",
        ),
    ),
)

LenormandEngine

Bases: AbstractEngine

Petit Lenormand engine.

The engine draws from the 36-card deck into a single-card, three-card line, or Grand Tableau spread. Lenormand cards are not read reversed, so draws carry no orientation; the Grand Tableau consumes the entire deck.

id class-attribute instance-attribute

id = 'lenormand.engine'

version class-attribute instance-attribute

version = '0.1.0'

deck

deck(request: ReadingRequest) -> Deck

Return the Lenormand deck for a request.

Parameters:

Name Type Description Default
request ReadingRequest

Reading request whose deck_id must match LENORMAND_DECK.id.

required

Returns:

Type Description
Deck

The bundled Lenormand deck.

Raises:

Type Description
ValidationError

If the request names an unsupported deck.

Source code in src/fortune_telling_core/traditions/lenormand/engine.py
def deck(self, request: ReadingRequest) -> Deck:
    """Return the Lenormand deck for a request.

    Args:
        request: Reading request whose ``deck_id`` must match
            ``LENORMAND_DECK.id``.

    Returns:
        The bundled Lenormand deck.

    Raises:
        ValidationError: If the request names an unsupported deck.
    """

    if request.deck_id != LENORMAND_DECK.id:
        raise ValidationError(f"unsupported Lenormand deck: {request.deck_id}")
    return LENORMAND_DECK

spread

spread(request: ReadingRequest) -> Spread

Return the Lenormand spread requested by id.

Parameters:

Name Type Description Default
request ReadingRequest

Reading request whose spread_id selects a bundled spread.

required

Returns:

Type Description
Spread

SINGLE_CARD, THREE_CARD, or GRAND_TABLEAU.

Raises:

Type Description
ValidationError

If the spread is not supported.

Source code in src/fortune_telling_core/traditions/lenormand/engine.py
def spread(self, request: ReadingRequest) -> Spread:
    """Return the Lenormand spread requested by id.

    Args:
        request: Reading request whose ``spread_id`` selects a bundled
            spread.

    Returns:
        ``SINGLE_CARD``, ``THREE_CARD``, or ``GRAND_TABLEAU``.

    Raises:
        ValidationError: If the spread is not supported.
    """

    spread = _SPREADS.get(request.spread_id)
    if spread is None:
        raise ValidationError(f"unsupported Lenormand spread: {request.spread_id}")
    return spread

draw

draw(request: ReadingRequest, rng: Rng) -> Draw

Draw cards for the requested spread.

Parameters:

Name Type Description Default
request ReadingRequest

Reading request.

required
rng Rng

Random source used to shuffle the deck.

required

Returns:

Type Description
Draw

A draw containing one selection per spread position.

Raises:

Type Description
ValidationError

If the requested deck or spread is unsupported.

ExhaustedRngError

If the supplied RNG cannot provide enough values.

Source code in src/fortune_telling_core/traditions/lenormand/engine.py
def draw(self, request: ReadingRequest, rng: Rng) -> Draw:
    """Draw cards for the requested spread.

    Args:
        request: Reading request.
        rng: Random source used to shuffle the deck.

    Returns:
        A draw containing one selection per spread position.

    Raises:
        ValidationError: If the requested deck or spread is unsupported.
        ExhaustedRngError: If the supplied RNG cannot provide enough values.
    """

    deck = self.deck(request)
    spread = self.spread(request)
    order = rng.shuffle(len(deck.symbols))
    selections = tuple(
        Selection(position_id=position.id, symbol_id=deck.symbols[symbol_index].id)
        for position, symbol_index in zip(spread.positions, order[: spread.size], strict=True)
    )
    return Draw(deck_id=deck.id, spread_id=spread.id, selections=selections)

build_engine

build_engine() -> LenormandEngine

Create a Petit Lenormand engine.

Returns:

Type Description
LenormandEngine

A new LenormandEngine instance.

Source code in src/fortune_telling_core/traditions/lenormand/engine.py
def build_engine() -> LenormandEngine:
    """Create a Petit Lenormand engine.

    Returns:
        A new ``LenormandEngine`` instance.
    """

    return LenormandEngine()