Skip to content

Commit 26f3096

Browse files
authored
Extended the documentation to show a few more (#340)
* Extended the documentation to show a few more usage examples * Documentation: Update transition documentation * Corrected the description of how to add transitions using multiple lines
1 parent cb28828 commit 26f3096

9 files changed

Lines changed: 67 additions & 36 deletions

File tree

docs/actions.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -87,9 +87,9 @@ All actions and {ref}`guards` support multiple method signatures. They follow th
8787

8888
For each defined {ref}`state`, you can declare `enter` and `exit` callbacks.
8989

90-
### Declare state actions by name convention
90+
### Declare state actions by naming convention
9191

92-
Callbacks by name convention will be searched on the StateMachine and on the
92+
Callbacks by naming convention will be searched on the StateMachine and on the
9393
model, using the patterns:
9494

9595
- `on_enter_<state.id>()`
@@ -158,11 +158,11 @@ Use the `enter` or `exit` params available on the `State` constructor.
158158

159159
For each {ref}`event`, you can register `before`, `on` and `after` callbacks.
160160

161-
### Declare transition actions by name convention
161+
### Declare transition actions by naming convention
162162

163163
The action will be registered for every {ref}`transition` associated with the event.
164164

165-
Callbacks by name convention will be searched on the StateMachine and on the
165+
Callbacks by naming convention will be searched on the StateMachine and on the
166166
model, using the patterns:
167167

168168
- `before_<event>()`
@@ -325,8 +325,8 @@ Actions and Guards will be executed in the following order:
325325
(dynamic-dispatch)=
326326
## Dynamic dispatch
327327

328-
python-statemachine implements a custom dispatch mechanism on all those available Actions and
329-
Guards, this means that you can declare an arbitrary number of `*args` and `**kwargs`, and the
328+
`python-statemachine` implements a custom dispatch mechanism on all those available Actions and
329+
Guards. This means that you can declare an arbitrary number of `*args` and `**kwargs`, and the
330330
library will match your method signature of what's expected to receive with the provided arguments.
331331

332332
This means that if on your `on_enter_<state.id>()` or `on_execute_<event>()` method, you need to know
@@ -353,7 +353,7 @@ For your convenience, all these parameters are available for you on any Action o
353353
: The {ref}`Event` that was triggered.
354354

355355
`source`
356-
: The {ref}`State` the state machine was when the {ref}`Event` started.
356+
: The {ref}`State` the state machine was in when the {ref}`Event` started.
357357

358358
`state`
359359
: The current {ref}`State` of the state machine.

docs/guards.md

Lines changed: 31 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ Validations and Guards are checked before an transition is started. They are mea
55
transition to occur.
66

77
The main difference, is that {ref}`validators` raise exceptions to stop the flow, and {ref}`guards`
8-
act like predicates that should resolve for a ``boolean`` value.
8+
act like predicates that shall resolve to a ``boolean`` value.
99

1010
```{seealso}
1111
Please see {ref}`dynamic-dispatch` to know more about how this lib supports multiple signatures
@@ -18,13 +18,12 @@ Also known as **Conditional transition**.
1818

1919
A guard is a condition that may be checked when a statemachine wants to handle
2020
an {ref}`event`. A guard is declared on the {ref}`transition`, and when that transition
21-
would trigger, then the guard (if any) is checked. If the guard is `True`
21+
would trigger, then the guard (if any) is checked. If the guard is `True`
2222
then the transition does happen. If the guard is `False`, the transition
2323
is ignored.
2424

2525
When transitions have guards, then it's possible to define two or more
26-
transitions for the same event from the same {ref}`state`, i.e. that a state has
27-
two (or more) transitions for the same event. When the event happens, then
26+
transitions for the same event from the same {ref}`state`. When the event happens, then
2827
the guarded transitions are checked, one by one, and the first transition
2928
whose guard is true will be used, the others will be ignored.
3029

@@ -37,9 +36,13 @@ There are two variations of Guard clauses available:
3736
cond
3837
: A list of conditions, acting like predicates. A transition is only allowed to occur if
3938
all conditions evaluate to ``True``.
39+
* Single condition: `cond="condition"`
40+
* Multiple conditions: `cond=["condition1", "condition2"]`
4041

4142
unless
42-
: Same as `cond`, but the transition is allowed if all conditions evaluate to `False`.
43+
: Same as `cond`, but the transition is only allowed if all conditions evaluate to ``False``.
44+
* Single condition: `unless="condition"`
45+
* Multiple conditions: `unless=["condition1", "condition2"]`
4346

4447
```{hint}
4548
In Python, a boolean value is either `True` or `False`. However, there are also specific values that
@@ -48,9 +51,9 @@ are considered "**falsy**" and will evaluate as `False` when used in a boolean c
4851
These include:
4952
5053
1. The special value `None`.
51-
1. Numeric values of `0` or `0.0`.
52-
1. **Empty** strings, lists, tuples, sets, and dictionaries.
53-
1. Instances of certain classes that define a `__bool__()` or `__len__()` method that returns
54+
2. Numeric values of `0` or `0.0`.
55+
3. **Empty** strings, lists, tuples, sets, and dictionaries.
56+
4. Instances of certain classes that define a `__bool__()` or `__len__()` method that returns
5457
`False` or `0`, respectively.
5558
5659
On the other hand, any value that is not considered "**falsy**" is considered "**truthy**" and will evaluate to `True` when used in a boolean context.
@@ -64,8 +67,14 @@ So, a condition `s1.to(s2, cond=lambda: [])` will evaluate as `False`, as an emp
6467

6568
Are like {ref}`guards`, but instead of evaluating to boolean, they are expected to raise an
6669
exception to stop the flow. It may be useful for imperative style programming when you don't
67-
wanna to continue evaluating other possible transitions and exit immediately.
70+
want to continue evaluating other possible transitions and exit immediately.
6871

72+
* Single validator: `validators="validator"`
73+
* Multiple validator: `validators=["validator1", "validator2"]`
74+
75+
Both conditions and validators can also be combined for a single event.
76+
77+
<event> = <state1>.to(<state2>, cond="condition1", unless="condition2", validators="validator")
6978

7079
Consider this example:
7180

@@ -76,16 +85,23 @@ class InvoiceStateMachine(StateMachine):
7685
paid = State("paid")
7786
failed = State("failed")
7887

88+
paused = False
89+
offer_valid = True
90+
7991
pay = (
80-
unpaid.to(paid, cond="payment_success")
81-
| failed.to(paid)
82-
| unpaid.to(failed)
92+
unpaid.to(paid, cond="payment_success") |
93+
unpaid.to(failed, validators="validator", unless="paused") |
94+
failed.to(paid, cond=["payment_success", "offer_valid"])
8395
)
84-
8596
def payment_success(self, event_data):
86-
return <validation logic goes here>
97+
return <condition logic goes here>
8798

99+
def validator(self):
100+
return <validator logic goes here>
101+
```
102+
```{seealso}
103+
See the example {ref}`sphx_glr_auto_examples_all_actions_machine.py` for a complete example of
104+
validators and guards.
88105
```
89-
90106

91107
Reference: [Statecharts](https://statecharts.dev/).
67 Bytes
Loading
2.75 KB
Loading
-80 Bytes
Loading

docs/releases/1.0.0.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,5 @@
22

33
*January 11, 2023*
44

5-
This release tag was replaced by [](1.0.1.md) due to an error on the metadata when uploading to
5+
This release tag was replaced by [1.0.1](1.0.1.md) due to an error on the metadata when uploading to
66
pypi.

docs/releases/1.0.1.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ Welcome to StateMachine 1.0.1!
66

77
This version is a huge refactoring adding a lot of new and exciting features. We hope that you enjoy it.
88

9-
These release notes cover the [](#whats-new-in-10), as well as
9+
These release notes cover the [new features in 1.0](#whats-new-in-10), as well as
1010
some [backwards incompatible changes](#backwards-incompatible-changes-in-10) you'll
1111
want to be aware of when upgrading from StateMachine 0.9.0 or earlier. We've
1212
[begun the deprecation process for some features](#deprecated-features-in-10).

docs/transitions.md

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,9 @@ In an executing state machine, a transition is a transfer from one state to anot
5252
A transition can define {ref}`actions` that will be executed whenever that transition
5353
is executed.
5454
55+
Transitions can be filtered with {ref}`guards` allowing you to add conditions when a
56+
transition may be executed.
57+
5558
An action associated with an event (before, on, after), will be assigned to all transitions
5659
bounded that uses the event as trigger.
5760
```
@@ -63,7 +66,7 @@ bounded that uses the event as trigger.
6366

6467
```{hint}
6568
Usually you don't need to import and use a {ref}`transition` class directly in your code,
66-
one of the most powerful features of this library is now transitions and events can be expressed
69+
one of the most powerful features of this library is how transitions and events can be expressed
6770
linking directly from/to {ref}`state` instances.
6871
```
6972

@@ -150,7 +153,7 @@ Usage:
150153

151154
```{note}
152155

153-
The internal transition is represented like an entry/exit action, where
156+
The internal transition is represented the same way as an entry/exit action, where
154157
the event name is used to describe the transition.
155158

156159
```
@@ -159,7 +162,7 @@ the event name is used to describe the transition.
159162
## Event
160163

161164
An event is an external signal that something has happened.
162-
They are sent to a state machine and allow the state machine to react.
165+
They are send to a state machine and allow the state machine to react.
163166

164167
An event starts a {ref}`transition`, which can be thought of as a "cause" that
165168
initiates a change in the state of the system.
@@ -171,12 +174,16 @@ In `python-statemachine`, an event is specified as an attribute of the state mac
171174
Triggering an event on a state machine means invoking or sending a signal, initiating the
172175
process that may result in executing a transition.
173176

174-
This process usually involves checking the current state, evaluating any guard conditions
175-
associated with the transition, executing any actions associated with the transition and states,
176-
and finally updating the current state.
177+
This process usually involves
178+
179+
1. checking the current state
180+
1. evaluating any guard conditions
181+
associated with the transition
182+
1. executing any actions associated with the transition and (current and target) states
183+
1. finally updating the current state.
177184

178185
```{seealso}
179-
See {ref}`actions` and {ref}`validator sand guards`.
186+
See {ref}`actions` and {ref}`validators and guards`.
180187
```
181188

182189

statemachine/state.py

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -47,14 +47,22 @@ class State:
4747
>>> draft.to(producing)
4848
TransitionList([Transition(State('Draft', ...
4949
50-
The result is a `TransitionList`. Don't worry about this internal class. But the good
51-
thing is that it implements the ``OR`` operator to combine transitions, so you can use the
52-
``|`` syntax to compound a list of transitions and assign to the same event.
50+
The result is a `TransitionList`.
51+
Don't worry about this internal class.
52+
But the good thing is that it implements the ``OR`` operator to combine transitions,
53+
so you can use the ``|`` syntax to compound a list of transitions and assign
54+
to the same event.
5355
54-
>>> transitions = draft.to(draft) | draft.to(producing)
56+
You can declare all transitions for a state in one single line ...
57+
58+
>>> transitions = draft.to(draft) | producing.to(closed)
59+
60+
... and you can append additional transitions for a state to previous definitions.
61+
62+
>>> transitions |= closed.to(draft)
5563
5664
>>> [(t.source.name, t.target.name) for t in transitions]
57-
[('Draft', 'Draft'), ('Draft', 'Producing')]
65+
[('Draft', 'Draft'), ('Producing', 'Closed'), ('Closed', 'Draft')]
5866
5967
There are handy shortcuts that you can use to express this same set of transitions.
6068

0 commit comments

Comments
 (0)