Skip to content

Commit 19548c6

Browse files
committed
docs(behaviour): add doctests, cross-references, and API links
- Add seealso to intro for consistency with other pages - Link StateChart and StateMachine to API definitions - Clarify backward compat is relative to pre-3.0 - Add inline doctests for atomic_configuration_update showing both modes - Add cross-references: conditions, transitions, validators, DI - Fix error_on_execution description: validators are not affected - Shorten gradual migration section
1 parent 246c1f9 commit 19548c6

1 file changed

Lines changed: 118 additions & 44 deletions

File tree

docs/behaviour.md

Lines changed: 118 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -3,31 +3,40 @@
33

44
# Behaviour
55

6-
The `StateChart` class follows the
6+
```{seealso}
7+
New to statecharts? See [](concepts.md) for an overview of how states,
8+
transitions, events, and actions fit together.
9+
```
10+
11+
The {class}`~statemachine.statemachine.StateChart` class follows the
712
[SCXML specification](https://www.w3.org/TR/scxml/) by default. The
8-
`StateMachine` class extends `StateChart` but overrides several defaults to
9-
preserve backward compatibility with existing code.
13+
{class}`~statemachine.statemachine.StateMachine` class extends `StateChart`
14+
but overrides several defaults to preserve backward compatibility with
15+
pre-3.0 code.
1016

1117
The behavioral differences are controlled by class-level attributes. This
12-
design allows a gradual upgrade path: start from `StateMachine` and selectively
13-
enable spec-compliant behaviors one at a time, or start from `StateChart` and
14-
get full SCXML compliance out of the box.
18+
design allows a gradual upgrade path: start from `StateMachine` and
19+
selectively enable spec-compliant behaviors one at a time, or start from
20+
`StateChart` and get full SCXML compliance out of the box.
1521

1622
```{tip}
17-
We **strongly recommend** that new projects use `StateChart` directly. Existing
18-
projects should consider migrating when possible, as the SCXML-compliant
19-
behavior provides more predictable semantics.
23+
We **strongly recommend** that new projects use `StateChart` directly.
24+
Existing projects should consider migrating when possible, as the
25+
SCXML-compliant behavior provides more predictable semantics.
2026
```
2127

2228

2329
## Comparison table
2430

25-
| Attribute | `StateChart` | `StateMachine` | Description |
26-
|------------------------------------|---------------|----------------|-------------|
27-
| `allow_event_without_transition` | `True` | `False` | Tolerate events that don't match any transition |
28-
| `enable_self_transition_entries` | `True` | `False` | Execute entry/exit actions on self-transitions |
29-
| `atomic_configuration_update` | `False` | `True` | When to update {ref}`configuration <querying-configuration>` during a microstep |
30-
| `error_on_execution` | `True` | `False` | Catch runtime errors as `error.execution` events |
31+
| Attribute | `StateChart` | `StateMachine` | Description |
32+
|---|---|---|---|
33+
| `allow_event_without_transition` | `True` | `False` | Tolerate events that don't match any transition |
34+
| `enable_self_transition_entries` | `True` | `False` | Execute entry/exit actions on self-transitions |
35+
| `atomic_configuration_update` | `False` | `True` | When to update {ref}`configuration <querying-configuration>` during a microstep |
36+
| `error_on_execution` | `True` | `False` | Catch action errors as `error.execution` events |
37+
38+
Each attribute is described below, with cross-references to the pages that
39+
cover the topic in depth.
3140

3241

3342
## `allow_event_without_transition`
@@ -36,69 +45,134 @@ When `True` (SCXML default), sending an event that does not match any enabled
3645
transition is silently ignored. When `False` (legacy default), a
3746
`TransitionNotAllowed` exception is raised, including for unknown event names.
3847

39-
The SCXML spec requires tolerance to unmatched events, as the event-driven model
40-
expects that not every event is relevant in every state.
48+
The SCXML spec requires tolerance to unmatched events, as the event-driven
49+
model expects that not every event is relevant in every state.
50+
51+
```{seealso}
52+
See {ref}`conditions` for how the engine selects transitions, and
53+
{ref}`checking enabled events` to query which events are currently valid.
54+
```
4155

4256

4357
## `enable_self_transition_entries`
4458

45-
When `True` (SCXML default), a {ref}`self-transition <self-transition>` executes
46-
the state's exit and entry actions, just like any other transition. When `False`
47-
(legacy default), self-transitions skip entry/exit actions.
59+
When `True` (SCXML default), a {ref}`self-transition <self-transition>`
60+
executes the state's exit and entry actions, just like any other transition.
61+
When `False` (legacy default), self-transitions skip entry/exit actions.
4862

4963
The SCXML spec treats self-transitions as regular transitions that happen to
5064
return to the same state, so entry/exit actions must fire. Use an
5165
{ref}`internal transition <internal-transition>` if you need a transition that
5266
stays in the same state **without** running exit/entry actions.
5367

68+
```{seealso}
69+
See {ref}`transitions` for the full reference on self-transitions and
70+
internal transitions.
71+
```
72+
5473

5574
## `atomic_configuration_update`
5675

57-
When `False` (SCXML default), a microstep follows the SCXML processing order:
58-
first exit all states in the exit set (running exit callbacks), then execute the
59-
transition content (`on` callbacks), then enter all states in the entry set
60-
(running entry callbacks). During the `on` callbacks, the
61-
{ref}`configuration <querying-configuration>` may be empty or partial.
76+
Controls **when** the {ref}`configuration <querying-configuration>` is
77+
updated during a microstep.
78+
79+
When `False` (SCXML default), the configuration reflects each phase as it
80+
happens: states are removed during exit and added during entry. This means
81+
that during transition `on` callbacks, the configuration may be empty or
82+
partial — the source states have already been exited but the target states
83+
have not yet been entered.
84+
85+
When `True` (legacy default), the configuration is updated atomically
86+
**after** the `on` callbacks complete, so `sm.configuration` and
87+
`state.is_active` always reflect a consistent snapshot during the transition.
88+
89+
```py
90+
>>> from statemachine import State, StateChart
91+
92+
>>> class AtomicDemo(StateChart):
93+
... atomic_configuration_update = True
94+
... off = State(initial=True)
95+
... on = State(final=True)
96+
...
97+
... switch = off.to(on, on="check_config")
98+
...
99+
... def check_config(self):
100+
... # With atomic update, configuration is unchanged during 'on'
101+
... self.off_was_active = self.off.is_active
102+
... self.on_was_active = self.on.is_active
103+
104+
>>> sm = AtomicDemo()
105+
>>> sm.send("switch")
106+
>>> sm.off_was_active # source still in configuration during 'on'
107+
True
108+
>>> sm.on_was_active # target not yet in configuration during 'on'
109+
False
62110

63-
When `True` (legacy default), the configuration is updated atomically after the
64-
`on` callbacks, so `sm.configuration` and `state.is_active` always reflect a
65-
consistent snapshot during the transition. This was the behavior of all previous
66-
versions.
111+
```
112+
113+
With `atomic_configuration_update = False` (the SCXML default), the result
114+
is different — `off.is_active` is `False` because exit already removed it,
115+
and `on.is_active` is also `False` because entry hasn't added it yet.
116+
In this mode, use `previous_configuration` and `new_configuration` to
117+
inspect the full picture:
118+
119+
```py
120+
>>> class SCXMLDemo(StateChart):
121+
... off = State(initial=True)
122+
... on = State(final=True)
123+
...
124+
... switch = off.to(on, on="check_config")
125+
...
126+
... def check_config(self, previous_configuration, new_configuration):
127+
... self.prev = {s.id for s in previous_configuration}
128+
... self.new = {s.id for s in new_configuration}
129+
130+
>>> sm = SCXMLDemo()
131+
>>> sm.send("switch")
132+
>>> sm.prev
133+
{'off'}
134+
>>> sm.new
135+
{'on'}
67136

68-
```{note}
69-
When `atomic_configuration_update` is `False`, `on` callbacks can request
70-
`previous_configuration` and `new_configuration` keyword arguments to inspect
71-
which states were active before and after the microstep. See
72-
{ref}`dependency-injection` for the full parameter list.
137+
```
138+
139+
```{seealso}
140+
See {ref}`dependency-injection` for the full list of parameters available
141+
in callbacks.
73142
```
74143

75144

76145
## `error_on_execution`
77146

78-
When `True` (SCXML default), runtime exceptions in callbacks (guards, actions,
79-
entry/exit) are caught by the engine and result in an internal `error.execution`
80-
event. When `False` (legacy default), exceptions propagate normally to the
81-
caller.
147+
When `True` (SCXML default), runtime exceptions in action callbacks
148+
(entry/exit, transition `on`) are caught by the engine and dispatched as
149+
internal `error.execution` events. When `False` (legacy default), exceptions
150+
propagate normally to the caller.
151+
152+
```{note}
153+
{ref}`Validators <validators>` are **not** affected by this flag — they
154+
always propagate exceptions to the caller, regardless of the
155+
`error_on_execution` setting. See {ref}`validators` for details.
156+
```
82157

83158
```{seealso}
84-
See {ref}`error-handling` for the full `error.execution` lifecycle, block-level
85-
error catching, and the cleanup/finalize pattern.
159+
See {ref}`error-handling` for the full `error.execution` lifecycle,
160+
block-level error catching, and the cleanup/finalize pattern.
86161
```
87162

88163

89164
## Gradual migration
90165

91-
You can override any of these attributes individually. For example, to adopt
92-
SCXML error handling in an existing `StateMachine` without changing other
93-
behaviors:
166+
All behavioral attributes can be overridden individually. This lets you
167+
adopt SCXML semantics incrementally in an existing `StateMachine`:
94168

95169
```python
96170
class MyMachine(StateMachine):
97171
error_on_execution = True
98172
# ... everything else behaves as before ...
99173
```
100174

101-
Or to use `StateChart` but keep the legacy atomic configuration update:
175+
Or keep a specific legacy behavior while using `StateChart` for the rest:
102176

103177
```python
104178
class MyChart(StateChart):

0 commit comments

Comments
 (0)