Skip to content

Commit

Permalink
Merge branch 'release/2.2.0'
Browse files Browse the repository at this point in the history
  • Loading branch information
fgmacedo committed May 7, 2024
2 parents dbfc4e9 + 45427e5 commit 524df07
Show file tree
Hide file tree
Showing 62 changed files with 1,894 additions and 1,313 deletions.
23 changes: 0 additions & 23 deletions .github/workflows/codesee-arch-diagram.yml

This file was deleted.

19 changes: 6 additions & 13 deletions .github/workflows/python-package.yml
Expand Up @@ -15,7 +15,7 @@ jobs:
strategy:
fail-fast: false
matrix:
python-version: ["3.7", "3.8", "3.9", "3.10", "3.11"]
python-version: ["3.7", "3.8", "3.9", "3.10", "3.11", "3.12"]

steps:
- uses: actions/checkout@v3
Expand Down Expand Up @@ -46,18 +46,11 @@ jobs:
# run ruff
#----------------------------------------------
- name: Linter with ruff
if: matrix.python-version == 3.11
if: matrix.python-version == 3.12
run: |
source .venv/bin/activate
ruff .
#----------------------------------------------
# run black
#----------------------------------------------
- name: Linter with black
if: matrix.python-version == 3.11
run: |
source .venv/bin/activate
black . --check --diff
ruff check .
ruff format --check .
#----------------------------------------------
# run pytest
#----------------------------------------------
Expand All @@ -70,8 +63,8 @@ jobs:
# upload coverage
#----------------------------------------------
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v3
if: matrix.python-version == 3.11
uses: codecov/codecov-action@v4
if: matrix.python-version == 3.12
with:
token: ${{ secrets.CODECOV_TOKEN }} # not required for public repos
directory: .
Expand Down
52 changes: 52 additions & 0 deletions .github/workflows/release.yml
@@ -0,0 +1,52 @@
on:
push:
tags: [ 'v?*.*.*' ]
name: release

jobs:
pypi-publish:
name: upload release to PyPI
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
python-version: ["3.12"]

# Specifying a GitHub environment is optional, but strongly encouraged
environment: release
permissions:
# IMPORTANT: this permission is mandatory for trusted publishing
id-token: write
steps:
- uses: actions/checkout@v3
- run: git fetch origin develop
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
- name: Install Poetry
uses: snok/install-poetry@v1
with:
version: 1.5.1
virtualenvs-create: true
virtualenvs-in-project: true
installer-parallel: true
- name: Load cached venv
id: cached-poetry-dependencies
uses: actions/cache@v3
with:
path: .venv
key: venv-${{ runner.os }}-${{ matrix.python-version }}-${{ hashFiles('**/poetry.lock') }}
- name: Install dependencies
if: steps.cached-poetry-dependencies.outputs.cache-hit != 'true'
run: poetry install --no-interaction --no-root
- name: Test with pytest
run: |
source .venv/bin/activate
pytest
- name: Poetry build
run: |
source .venv/bin/activate
poetry build
- name: Publish package distributions to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
1 change: 1 addition & 0 deletions .gitignore
Expand Up @@ -78,3 +78,4 @@ target/
# Sphinx-galery
docs/auto_examples/sg_execution_times.*
docs/auto_examples/*.pickle
docs/sg_execution_times.rst
10 changes: 5 additions & 5 deletions .pre-commit-config.yaml
Expand Up @@ -9,13 +9,13 @@ repos:
exclude: docs/auto_examples
- repo: https://github.com/charliermarsh/ruff-pre-commit
# Ruff version.
rev: 'v0.0.257'
rev: v0.3.7
hooks:
# Run the linter.
- id: ruff
- repo: https://github.com/psf/black
rev: 22.10.0
hooks:
- id: black
args: [ --fix ]
# Run the formatter.
- id: ruff-format

- repo: local
hooks:
Expand Down
13 changes: 5 additions & 8 deletions .readthedocs.yaml
Expand Up @@ -7,26 +7,23 @@ version: 2

# Set the version of Python and other tools you might need
build:
os: ubuntu-20.04
os: ubuntu-22.04
tools:
python: "3.11"
python: "3.12"
apt_packages:
- graphviz
jobs:
post_create_environment:
# Install poetry
# https://python-poetry.org/docs/#installing-manually
- pip install poetry
- python -m pip install poetry
# Tell poetry to not use a virtual environment
- poetry config virtualenvs.create false
post_install:
# Install dependencies with 'docs' dependency group
# https://python-poetry.org/docs/managing-dependencies/#dependency-groups
- poetry install --extras diagrams --with docs
- VIRTUAL_ENV=$READTHEDOCS_VIRTUALENV_PATH poetry install --extras diagrams --with docs

# Build documentation in the docs/ directory with Sphinx
sphinx:
configuration: docs/conf.py

python:
install:
- requirements: docs/requirements.txt
2 changes: 1 addition & 1 deletion docs/conf.py
Expand Up @@ -66,7 +66,7 @@

# General information about the project.
project = "Python State Machine"
copyright = "2023, Fernando Macedo"
copyright = "2024, Fernando Macedo"

# The version info for the project you're documenting, acts as replacement
# for |version| and |release|, also used in various other places throughout
Expand Down
2 changes: 1 addition & 1 deletion docs/diagram.md
Expand Up @@ -87,7 +87,7 @@ A handy shortcut to have the graph representation:
```py
>>> machine._graph()
<pydot.Dot ...
<pydot.core.Dot ...
```

Expand Down
Binary file modified docs/images/order_control_machine_initial.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/images/order_control_machine_processing.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/images/readme_trafficlightmachine.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/images/test_state_machine_internal.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions docs/mixins.md
Expand Up @@ -25,8 +25,8 @@ Given a state machine definition:
... "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)
... closed = State('Closed', value=3, final=True)
... cancelled = State('Cancelled', value=4, final=True)
...
... add_job = draft.to.itself() | producing.to.itself()
... produce = draft.to(producing)
Expand Down
2 changes: 1 addition & 1 deletion docs/processing_model.md
Expand Up @@ -32,7 +32,7 @@ Consider this state machine:
>>> class ServerConnection(StateMachine):
... disconnected = State(initial=True)
... connecting = State()
... connected = State()
... connected = State(final=True)
...
... connect = disconnected.to(connecting, after="connection_succeed")
... connection_succeed = connecting.to(connected)
Expand Down
71 changes: 71 additions & 0 deletions docs/releases/2.2.0.md
@@ -0,0 +1,71 @@
# StateMachine 2.2.0

*May 6, 2024*

## What's new in 2.2.0

In this release, we conducted a general cleanup and refactoring across various modules to enhance code readability and maintainability. We improved exception handling and reduced code redundancy.

As a result, we achieved a **~2.2x** faster setup in our performance tests and significantly simplified the callback machinery.


### Check of unreachable and non-final states

We included one more state machine definition validation for non-final states.

We already check if any states are unreachable from the initial state, if not, an `InvalidDefinition` exception is thrown.

```py
>>> from statemachine import StateMachine, State

>>> class TrafficLightMachine(StateMachine):
... "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)
...
... cycle = red.to(green) | green.to(orange) | orange.to(red)
... blink = hazard.to.itself()
Traceback (most recent call last):
...
InvalidDefinition: There are unreachable states. The statemachine graph should have a single component. Disconnected states: ['hazard']
```

From this release, `StateMachine` will also check that all non-final states have an outgoing transition,
and warn you if any states would result in the statemachine becoming trapped in a non-final state with no further transitions possible.

```{note}
This will currently issue a warning, but can be turned into an exception by setting `strict_states=True` on the class.
```

```py
>>> 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)
...
... cycle = red.to(green) | green.to(orange) | orange.to(red)
... fault = red.to(hazard) | green.to(hazard) | orange.to(hazard)
Traceback (most recent call last):
...
InvalidDefinition: All non-final states should have at least one outgoing transition. These states have no outgoing transition: ['hazard']
```

```{warning}
`strict_states=True` will become the default behaviour in the next major release.
```

See {ref}`State Transitions`.


## Bugfixes in 2.2.0

- Fixes [#424](https://github.com/fgmacedo/python-statemachine/issues/424) allowing `deepcopy` of state machines.
- **Dispatch Mechanism**: Resolved issues in the dispatch mechanism in `statemachine/dispatcher.py` that affected the reliability
of event handling across different states. This fix ensures consistent behavior when events are dispatched in complex state
machine configurations.
1 change: 1 addition & 0 deletions docs/releases/index.md
Expand Up @@ -15,6 +15,7 @@ Below are release notes through StateMachine and its patch releases.
```{toctree}
:maxdepth: 2
2.2.0
2.1.2
2.1.1
2.1.0
Expand Down
4 changes: 0 additions & 4 deletions docs/requirements.txt

This file was deleted.

0 comments on commit 524df07

Please sign in to comment.