Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .github/workflows/pages.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ jobs:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v7
- name: Assemble site
run: |
mkdir -p _site/schemas/statechart
Expand All @@ -44,8 +44,8 @@ jobs:
<p>See the <a href="schemas/statechart/v1.json">statechart JSON Schema</a> or the
<a href="https://python-statemachine.readthedocs.io/">documentation</a>.</p>
HTML
- uses: actions/upload-pages-artifact@v3
- uses: actions/upload-pages-artifact@v5
with:
path: _site
- id: deployment
uses: actions/deploy-pages@v4
uses: actions/deploy-pages@v5
8 changes: 4 additions & 4 deletions .github/workflows/python-package.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,16 @@ jobs:
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]

steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v7
- run: git fetch origin develop
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v6
uses: actions/setup-python@v7
with:
python-version: ${{ matrix.python-version }}
- name: Setup Graphviz
uses: ts-graphviz/setup-graphviz@v2
- name: Install uv
uses: astral-sh/setup-uv@v8.1.0
uses: astral-sh/setup-uv@v10.1.0
with:
enable-cache: true
cache-suffix: "python${{ matrix.python-version }}"
Expand All @@ -55,7 +55,7 @@ jobs:
# upload coverage
#----------------------------------------------
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v6
uses: codecov/codecov-action@v7
if: matrix.python-version == 3.14
with:
token: ${{ secrets.CODECOV_TOKEN }} # not required for public repos
Expand Down
10 changes: 5 additions & 5 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,20 @@ jobs:
permissions:
id-token: write
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v7

- run: git fetch origin develop

- name: Setup Python
uses: actions/setup-python@v6
uses: actions/setup-python@v7
with:
python-version: '3.14'

- name: Setup Graphviz
uses: ts-graphviz/setup-graphviz@v2

- name: Install uv
uses: astral-sh/setup-uv@v8.1.0
uses: astral-sh/setup-uv@v10.1.0
with:
enable-cache: true

Expand All @@ -40,7 +40,7 @@ jobs:
uv build

- name: Upload dists
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v7
with:
name: release-dists
path: dist/
Expand All @@ -59,7 +59,7 @@ jobs:

steps:
- name: Retrieve release distributions
uses: actions/download-artifact@v4
uses: actions/download-artifact@v8
with:
name: release-dists
path: dist/
Expand Down
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ repos:
exclude: docs/auto_examples
- repo: https://github.com/astral-sh/ruff-pre-commit
# Ruff version.
rev: v0.15.17
rev: v0.16.7
hooks:
# Run the linter.
- id: ruff
Expand Down
2 changes: 2 additions & 0 deletions docs/diagram.md
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,7 @@ Sphinx directive):
```python
from statemachine.contrib.diagram import formatter


@formatter.register_format("plantuml", "puml")
def _render_plantuml(machine_or_class):
# your PlantUML renderer here
Expand Down Expand Up @@ -525,6 +526,7 @@ class CustomDiagram(DotGraphMachine):
graph_rankdir = "TB"
state_active_fillcolor = "lightyellow"


sm = OrderControl()
sm.receive_payment(10)

Expand Down
2 changes: 1 addition & 1 deletion docs/guards.md
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,7 @@ listeners. They can point to properties, attributes, or methods:
**Parentheses** control evaluation order:

```python
cond="(is_admin or is_moderator) and not is_banned"
cond = "(is_admin or is_moderator) and not is_banned"
```

#### Expression examples
Expand Down
9 changes: 3 additions & 6 deletions docs/how-to/coming_from_state_pattern.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,13 @@ class OrderState(ABC):
"""Abstract base for all order states."""

@abstractmethod
def confirm(self, order):
...
def confirm(self, order): ...

@abstractmethod
def ship(self, order):
...
def ship(self, order): ...

@abstractmethod
def deliver(self, order):
...
def deliver(self, order): ...


class DraftState(OrderState):
Expand Down
29 changes: 18 additions & 11 deletions docs/how-to/coming_from_transitions.md
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,7 @@ that reads SCXML, JSON and YAML *documents* straight into a `StateChart`:
```python
from statemachine.io import load

Machine = load("traffic_light.scxml") # or .json / .yaml; format detected from the extension
Machine = load("traffic_light.scxml") # or .json / .yaml; format detected from the extension
```

Expressions in the document (guards, datamodel) are evaluated by a restricted allowlist —
Expand Down Expand Up @@ -306,8 +306,8 @@ True
In *transitions*, events are called as methods on the model:

```python
machine.produce() # triggers the "produce" event
machine.deliver() # triggers the "deliver" event
machine.produce() # triggers the "produce" event
machine.deliver() # triggers the "deliver" event
```

python-statemachine supports both styles:
Expand Down Expand Up @@ -342,13 +342,15 @@ Callbacks are specified as strings (method names) or callables:
```python
machine = Machine(
states=states,
transitions=[{
"trigger": "produce",
"source": "draft",
"dest": "producing",
"before": "validate_job",
"after": "notify_team",
}],
transitions=[
{
"trigger": "produce",
"source": "draft",
"dest": "producing",
"before": "validate_job",
"after": "notify_team",
}
],
initial="draft",
)
```
Expand Down Expand Up @@ -454,7 +456,9 @@ In *transitions*:

```python
machine.add_transition(
"produce", "draft", "producing",
"produce",
"draft",
"producing",
conditions=["is_valid", "has_resources"],
unless=["is_locked"],
)
Expand Down Expand Up @@ -588,10 +592,12 @@ See {ref}`invoke` for full documentation.
```python
from transitions.extensions import AsyncMachine


class AsyncModel:
async def on_enter_producing(self):
await some_async_operation()


machine = AsyncMachine(model=AsyncModel(), states=states, initial="draft")
await machine.produce()
```
Expand Down Expand Up @@ -752,6 +758,7 @@ No class swapping, no feature matrices to consult — just `StateChart`.
class MyModel:
pass


model = MyModel()
machine = Machine(model=model, states=states, transitions=transitions, initial="draft")
model.produce() # events are added to the model
Expand Down
15 changes: 8 additions & 7 deletions docs/integrations.md
Original file line number Diff line number Diff line change
Expand Up @@ -120,10 +120,11 @@ from statemachine import State

class CampaignMachine(StateChart):
"A workflow machine"
draft = State('Draft', initial=True, value=1)
producing = State('Being produced', value=2)
closed = State('Closed', value=3)
cancelled = State('Cancelled', value=4)

draft = State("Draft", initial=True, value=1)
producing = State("Being produced", value=2)
closed = State("Closed", value=3)
cancelled = State("Cancelled", value=4)

add_job = draft.to.itself() | producing.to.itself()
produce = draft.to(producing)
Expand All @@ -142,9 +143,9 @@ from statemachine.mixins import MachineMixin


class Campaign(models.Model, MachineMixin):
state_machine_name = 'campaign.statemachines.CampaignMachine'
state_machine_attr = 'sm'
state_field_name = 'step'
state_machine_name = "campaign.statemachines.CampaignMachine"
state_machine_attr = "sm"
state_field_name = "step"

name = models.CharField(max_length=30)
step = models.IntegerField()
Expand Down
32 changes: 19 additions & 13 deletions docs/releases/1.0.1.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,15 @@ Transitions now support `cond` and `unless` parameters, to restrict
the execution.

```python
class ApprovalMachine(StateMachine):
"A workflow machine"
requested = State("Requested", initial=True)
accepted = State("Accepted")
rejected = State("Rejected")
completed = State("Completed")
class ApprovalMachine(StateMachine):
"A workflow machine"

requested = State("Requested", initial=True)
accepted = State("Accepted")
rejected = State("Rejected")
completed = State("Completed")

validate = requested.to(accepted, cond="is_ok") | requested.to(rejected)
validate = requested.to(accepted, cond="is_ok") | requested.to(rejected)
```

```{seealso}
Expand Down Expand Up @@ -114,9 +115,10 @@ So, the previous code (not valid anymore):
```py
class ApprovalMachine(StateMachine):
"A workflow machine"
requested = State('Requested', initial=True)
accepted = State('Accepted')
rejected = State('Rejected')

requested = State("Requested", initial=True)
accepted = State("Accepted")
rejected = State("Rejected")

validate = requested.to(accepted, rejected)

Expand All @@ -133,6 +135,7 @@ Should be rewritten to use {ref}`guards`, like this:
``` py
class ApprovalMachine(StateMachine):
"A workflow machine"

requested = State("Requested", initial=True)
accepted = State("Accepted")
rejected = State("Rejected")
Expand Down Expand Up @@ -168,14 +171,16 @@ This was the previous behavior, you only got an error when trying to instantiate
```py
class CampaignMachine(StateMachine):
"A workflow machine"
draft = State('Draft', initial=True)
producing = State('Being produced')
closed = State('Closed', initial=True) # Should raise an Exception when instantiated

draft = State("Draft", initial=True)
producing = State("Being produced")
closed = State("Closed", initial=True) # Should raise an Exception when instantiated

add_job = draft.to(draft) | producing.to(producing)
produce = draft.to(producing)
deliver = producing.to(closed)


with pytest.raises(exceptions.InvalidDefinition):
CampaignMachine()
```
Expand All @@ -187,6 +192,7 @@ with pytest.raises(exceptions.InvalidDefinition):

class CampaignMachine(StateMachine):
"A workflow machine"

draft = State("Draft", initial=True)
producing = State("Being produced")
closed = State(
Expand Down
4 changes: 0 additions & 4 deletions docs/releases/2.0.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -291,7 +291,6 @@ from tests.examples.traffic_light_machine import TrafficLightMachine

sm = TrafficLightMachine()
sm.run("cycle")

```

Should become:
Expand All @@ -313,7 +312,6 @@ from tests.examples.traffic_light_machine import TrafficLightMachine

sm = TrafficLightMachine()
assert [t.name for t in sm.allowed_transitions] == ["cycle"]

```

Should become:
Expand All @@ -333,7 +331,6 @@ from tests.examples.traffic_light_machine import TrafficLightMachine

sm = TrafficLightMachine()
assert sm.is_green

```

Should become:
Expand All @@ -355,7 +352,6 @@ from tests.examples.traffic_light_machine import TrafficLightMachine

sm = TrafficLightMachine()
assert sm.current_state.identification == "green"

```

Should become:
Expand Down
11 changes: 7 additions & 4 deletions docs/releases/2.2.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,16 +42,19 @@ This will currently issue a warning, but can be turned into an exception by sett
```python
from statemachine import StateMachine, State


class TrafficLightMachine(StateMachine, strict_states=True):
"A workflow machine"
red = State('Red', initial=True, value=1)
green = State('Green', value=2)
orange = State('Orange', value=3)
hazard = State('Hazard', value=4)

red = State("Red", initial=True, value=1)
green = State("Green", value=2)
orange = State("Orange", value=3)
hazard = State("Hazard", value=4)

cycle = red.to(green) | green.to(orange) | orange.to(red)
fault = red.to(hazard) | green.to(hazard) | orange.to(hazard)


# InvalidDefinition: All non-final states should have at least one outgoing transition.
# These states have no outgoing transition: ['hazard']
```
Expand Down
5 changes: 3 additions & 2 deletions docs/releases/2.3.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ async code with a state machine.

```python
class AsyncStateMachine(StateMachine):
initial = State('Initial', initial=True)
final = State('Final', final=True)
initial = State("Initial", initial=True)
final = State("Final", final=True)

advance = initial.to(final)

Expand All @@ -42,6 +42,7 @@ async def run_sm():
res = await sm.advance()
return (42, sm.current_state.name)


asyncio.run(run_sm())
# (42, 'Final')
```
Loading
Loading