(states)= (state)=
New to statecharts? See [](concepts.md) for an overview of how states,
transitions, events, and actions fit together.
A state represents a distinct mode or condition of the system at a given point in time. States are the building blocks of a statechart — you define them as class attributes, and the library handles initialization, validation, and lifecycle management.
>>> from statemachine import State, StateChart
>>> class TrafficLight(StateChart):
... green = State(initial=True)
... yellow = State()
... red = State()
...
... cycle = green.to(yellow) | yellow.to(red) | red.to(green)
>>> sm = TrafficLight()
>>> "green" in sm.configuration_values
True| Parameter | Default | Description |
|---|---|---|
name |
"" |
Human-readable display name. Defaults to the attribute name, capitalized. Accepts any object castable to str (e.g. a lazy translation proxy), resolved via str() at display time. |
value |
None |
Custom value for this state, accessible via configuration_values. |
initial |
False |
Marks this as the initial state. Exactly one per machine (or per compound). |
final |
False |
Marks this as a final (accepting) state. No outgoing transitions allowed. |
enter |
None |
Callback(s) to run when entering this state. See {ref}state-actions. |
exit |
None |
Callback(s) to run when leaving this state. See {ref}state-actions. |
invoke |
None |
Background work spawned on entry, cancelled on exit. See {ref}invoke-actions. |
>>> class CampaignMachine(StateChart):
... draft = State("Draft", value=1, initial=True)
... producing = State("Being produced", value=2)
... closed = State("Closed", value=3, final=True)
...
... produce = draft.to(producing)
... deliver = producing.to(closed)
>>> sm = CampaignMachine()
>>> sm.send("produce")
>>> list(sm.configuration_values)
[2]A {ref}StateChart must have exactly one initial state. The initial state is
entered when the machine starts, and the corresponding {ref}enter actions <state-actions> are called.
(final-state)=
A final state signals that the machine has completed its work. No outgoing transitions are allowed from a final state.
>>> sm = CampaignMachine()
>>> sm.send("produce")
>>> sm.send("deliver")
>>> sm.is_terminated
TrueYou can query the list of all declared final states:
>>> sm.final_states
[State('Closed', id='closed', value=3, initial=False, final=True, parallel=False)]See {ref}`validations` for the checks the library performs at class definition
time — including final state reachability, unreachable states, and trap states.
(compound-states)=
Compound states contain inner child states, enabling hierarchical state machines.
Define them using the State.Compound inner class syntax:
>>> from statemachine import State, StateChart
>>> class Journey(StateChart):
... class shire(State.Compound):
... bag_end = State(initial=True)
... green_dragon = State()
... visit_pub = bag_end.to(green_dragon)
... road = State(final=True)
... depart = shire.to(road)
>>> sm = Journey()
>>> set(sm.configuration_values) == {"shire", "bag_end"}
TrueEntering a compound activates both the parent and its initial child. You can query
whether a state is compound using the is_compound property.
See {ref}`done-state-events` for completion events when a compound state's
final child is reached.
(parallel-states)=
Parallel states activate all child regions simultaneously. Each region operates
independently. Define them using State.Parallel:
>>> from statemachine import State, StateChart
>>> class WarOfTheRing(StateChart):
... class war(State.Parallel):
... class quest(State.Compound):
... start = State(initial=True)
... end = State(final=True)
... go = start.to(end)
... class battle(State.Compound):
... fighting = State(initial=True)
... won = State(final=True)
... victory = fighting.to(won)
>>> sm = WarOfTheRing()
>>> "start" in sm.configuration_values and "fighting" in sm.configuration_values
TrueSee {ref}`done-state-events` for how `done.state` events work with parallel
states (all regions must reach a final state).
(history-states)=
A history pseudo-state records the active child of a compound state when it is exited.
Re-entering via the history state restores the previously active child. Import and use
HistoryState inside a State.Compound:
>>> from statemachine import HistoryState, State, StateChart
>>> class WithHistory(StateChart):
... class mode(State.Compound):
... a = State(initial=True)
... b = State()
... h = HistoryState()
... switch = a.to(b)
... outside = State()
... leave = mode.to(outside)
... resume = outside.to(mode.h)
>>> sm = WithHistory()
>>> sm.send("switch")
>>> sm.send("leave")
>>> sm.send("resume")
>>> "b" in sm.configuration_values
TrueUse HistoryState(type="deep") for deep history that remembers the exact leaf state
in nested compounds.
See {ref}`querying-configuration` for how to inspect which states are currently
active at runtime.
(states from enum types)=
{ref}States can also be declared from standard Enum classes.
For this, use {ref}States (class) to convert your Enum type to a list of {ref}State objects.
.. automethod:: statemachine.states.States.from_enum
:noindex:
See the example {ref}`sphx_glr_auto_examples_enum_campaign_machine.py`.