ProvenPin Install

transitions order workflow with conditions and callbacks: working versions (tested 2026-10-18)

An order workflow state machine built with transitions, covering states, triggers, guarded conditions, before/after callbacks via EventData and MachineError on invalid moves, tested offline.

passed5 passed · 0 failed2026-10-18 03:57 UTC
Status
passed
Last passed
2026-10-18 03:57 UTC
Tests
5 / 5
Language
Python
Runtime
Python 3.13.16
pinned versions2
transitions@0.9.3pytest@9.1.1
run it
uv venv -q .venv && uv pip install -q --python .venv/bin/python -r requirements.txt
.venv/bin/python -m pytest -q
test environment
Python 3.13.16
linux 6.17.0-1022-azure
x64
runner: github-actions 39095370682

The code

Exactly the files that passed. Your agent can pull them with get_recipe("transitions-fsm-callbacks") (install), or see them on GitHub.

requirements.txt
transitions==0.9.3
pytest==9.1.1
order.py
from transitions import Machine


class Order:
    states = ["cart", "placed", "paid", "shipped", "cancelled"]

    def __init__(self, items=0):
        self.items = items
        self.amount = 0
        self.log = []
        self.machine = Machine(
            model=self,
            states=self.states,
            initial="cart",
            send_event=True,
        )
        self.machine.add_transition(
            "place", "cart", "placed",
            conditions="has_items",
            before="before_place",
            after="after_place",
        )
        self.machine.add_transition(
            "pay", "placed", "paid",
            before="charge",
            after="paid",
        )
        self.machine.add_transition(
            "ship", "paid", "shipped",
            after="shipped",
        )
        self.machine.add_transition(
            "cancel", ["cart", "placed"], "cancelled",
            after="cancelled",
        )

    def has_items(self, event):
        return self.items > 0

    def before_place(self, event):
        self.log.append(("before_place", self.state))

    def after_place(self, event):
        self.log.append(("after_place", self.state))

    def charge(self, event):
        self.amount = event.kwargs.get("amount", 0)
        self.log.append(("charge", self.state))

    def paid(self, event):
        self.log.append(("paid", self.state))

    def shipped(self, event):
        self.log.append(("shipped", self.state))

    def cancelled(self, event):
        self.log.append(("cancelled", self.state))
tests/test_order.py
import pytest
from transitions import MachineError

from order import Order


def test_before_sees_old_state_after_sees_new_state():
    order = Order(items=2)
    assert order.place() is True
    order.pay(amount=25)
    assert order.ship() is True
    assert order.state == "shipped"
    assert order.amount == 25
    assert ("before_place", "cart") in order.log
    assert ("after_place", "placed") in order.log
    assert ("charge", "placed") in order.log
    assert ("paid", "paid") in order.log


def test_wrong_source_raises_machine_error():
    order = Order(items=1)
    with pytest.raises(MachineError, match="Can't trigger event ship"):
        order.ship()
    assert order.state == "cart"


def test_failed_condition_returns_false_without_raising():
    order = Order(items=0)
    assert order.may_place() is False
    assert order.place() is False
    assert order.state == "cart"
    assert order.log == []


def test_cancel_only_from_cart_or_placed():
    order = Order(items=1)
    order.place()
    order.pay()
    assert order.may_cancel() is False
    with pytest.raises(MachineError):
        order.cancel()
    assert order.state == "paid"


def test_auto_transitions_bypass_sources_and_conditions():
    order = Order(items=0)
    assert "to_shipped" in order.machine.get_triggers("cart")
    assert order.to_shipped() is True
    assert order.state == "shipped"
    assert order.log == []
pytest.ini
[pytest]
pythonpath = .

Connect to ProvenPin

Add the free MCP server so your agent can pull this recipe and others like it. Same setup as the docs.

terminal
claude mcp add --transport http provenpin https://mcp.provenpin.com/mcp

Any other MCP client: Streamable HTTP at https://mcp.provenpin.com/mcp. No API key, no signup.