Skip to content

Quickstart

1. Define States and Triggers

from enum import Enum, auto

class OrderState(Enum):
    DRAFT = auto()
    SUBMITTED = auto()
    APPROVED = auto()

class OrderTrigger(Enum):
    SUBMIT = auto()
    APPROVE = auto()

2. Configure the State Machine

from stateless import StateMachine

sm = StateMachine[OrderState, OrderTrigger](OrderState.DRAFT)

sm.configure(OrderState.DRAFT).permit(OrderTrigger.SUBMIT, OrderState.SUBMITTED)
sm.configure(OrderState.SUBMITTED).permit(OrderTrigger.APPROVE, OrderState.APPROVED)

3. Fire Triggers

sm.fire(OrderTrigger.SUBMIT)
assert sm.state == OrderState.SUBMITTED

sm.fire(OrderTrigger.APPROVE)
assert sm.state == OrderState.APPROVED

4. Add a Guard

is_eligible = False

def can_approve() -> bool:
    return is_eligible

sm = StateMachine[OrderState, OrderTrigger](OrderState.SUBMITTED)
sm.configure(OrderState.SUBMITTED).permit_if(
    OrderTrigger.APPROVE,
    OrderState.APPROVED,
    can_approve,
    "Order must be eligible",
)

If can_approve() is False, fire(...) raises InvalidTransitionError.

5. Use Async Guards or Actions

import asyncio

async def can_approve_async() -> bool:
    await asyncio.sleep(0.01)
    return True

sm = StateMachine[OrderState, OrderTrigger](OrderState.SUBMITTED)
sm.configure(OrderState.SUBMITTED).permit_if(
    OrderTrigger.APPROVE,
    OrderState.APPROVED,
    can_approve_async,
)

await sm.fire_async(OrderTrigger.APPROVE)

Use fire_async(...) when any involved guard/action/selector is async.