python-statemachine 2.1.2__tar.gz → 2.3.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. {python_statemachine-2.1.2 → python_statemachine-2.3.0}/PKG-INFO +86 -25
  2. {python_statemachine-2.1.2 → python_statemachine-2.3.0}/README.md +83 -23
  3. {python_statemachine-2.1.2 → python_statemachine-2.3.0}/pyproject.toml +52 -40
  4. {python_statemachine-2.1.2 → python_statemachine-2.3.0}/statemachine/__init__.py +1 -1
  5. {python_statemachine-2.1.2 → python_statemachine-2.3.0}/statemachine/callbacks.py +106 -76
  6. {python_statemachine-2.1.2 → python_statemachine-2.3.0}/statemachine/contrib/diagram.py +20 -6
  7. python_statemachine-2.3.0/statemachine/dispatcher.py +159 -0
  8. {python_statemachine-2.1.2 → python_statemachine-2.3.0}/statemachine/event.py +21 -20
  9. {python_statemachine-2.1.2 → python_statemachine-2.3.0}/statemachine/exceptions.py +9 -3
  10. {python_statemachine-2.1.2 → python_statemachine-2.3.0}/statemachine/factory.py +72 -9
  11. {python_statemachine-2.1.2 → python_statemachine-2.3.0}/statemachine/graph.py +6 -0
  12. python_statemachine-2.3.0/statemachine/locale/en/LC_MESSAGES/statemachine.po +80 -0
  13. python_statemachine-2.3.0/statemachine/locale/pt_BR/LC_MESSAGES/statemachine.po +91 -0
  14. {python_statemachine-2.1.2 → python_statemachine-2.3.0}/statemachine/mixins.py +1 -3
  15. {python_statemachine-2.1.2 → python_statemachine-2.3.0}/statemachine/signature.py +15 -8
  16. {python_statemachine-2.1.2 → python_statemachine-2.3.0}/statemachine/state.py +22 -25
  17. {python_statemachine-2.1.2 → python_statemachine-2.3.0}/statemachine/statemachine.py +125 -97
  18. {python_statemachine-2.1.2 → python_statemachine-2.3.0}/statemachine/states.py +6 -4
  19. {python_statemachine-2.1.2 → python_statemachine-2.3.0}/statemachine/transition.py +35 -26
  20. python_statemachine-2.3.0/statemachine/utils.py +33 -0
  21. python_statemachine-2.1.2/statemachine/dispatcher.py +0 -124
  22. python_statemachine-2.1.2/statemachine/locale/en/LC_MESSAGES/statemachine.mo +0 -0
  23. python_statemachine-2.1.2/statemachine/locale/en/LC_MESSAGES/statemachine.po +0 -66
  24. python_statemachine-2.1.2/statemachine/locale/pt_BR/LC_MESSAGES/statemachine.mo +0 -0
  25. python_statemachine-2.1.2/statemachine/locale/pt_BR/LC_MESSAGES/statemachine.po +0 -70
  26. python_statemachine-2.1.2/statemachine/utils.py +0 -14
  27. {python_statemachine-2.1.2 → python_statemachine-2.3.0}/LICENSE +0 -0
  28. {python_statemachine-2.1.2 → python_statemachine-2.3.0}/statemachine/contrib/__init__.py +0 -0
  29. {python_statemachine-2.1.2 → python_statemachine-2.3.0}/statemachine/event_data.py +0 -0
  30. {python_statemachine-2.1.2 → python_statemachine-2.3.0}/statemachine/events.py +0 -0
  31. {python_statemachine-2.1.2 → python_statemachine-2.3.0}/statemachine/i18n.py +0 -0
  32. {python_statemachine-2.1.2 → python_statemachine-2.3.0}/statemachine/model.py +0 -0
  33. {python_statemachine-2.1.2 → python_statemachine-2.3.0}/statemachine/registry.py +0 -0
  34. {python_statemachine-2.1.2 → python_statemachine-2.3.0}/statemachine/transition_list.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: python-statemachine
3
- Version: 2.1.2
3
+ Version: 2.3.0
4
4
  Summary: Python Finite State Machines made easy.
5
5
  Home-page: https://github.com/fgmacedo/python-statemachine
6
6
  License: MIT
@@ -8,7 +8,8 @@ Author: Fernando Macedo
8
8
  Author-email: fgmacedo@gmail.com
9
9
  Maintainer: Fernando Macedo
10
10
  Maintainer-email: fgmacedo@gmail.com
11
- Requires-Python: >=3.7,<3.13
11
+ Requires-Python: >=3.7
12
+ Classifier: Framework :: AsyncIO
12
13
  Classifier: Intended Audience :: Developers
13
14
  Classifier: License :: OSI Approved :: MIT License
14
15
  Classifier: Natural Language :: English
@@ -26,8 +27,8 @@ Description-Content-Type: text/markdown
26
27
  # Python StateMachine
27
28
 
28
29
  [![pypi](https://img.shields.io/pypi/v/python-statemachine.svg)](https://pypi.python.org/pypi/python-statemachine)
30
+ [![downloads total](https://static.pepy.tech/badge/python-statemachine)](https://pepy.tech/project/python-statemachine)
29
31
  [![downloads](https://img.shields.io/pypi/dm/python-statemachine.svg)](https://pypi.python.org/pypi/python-statemachine)
30
- [![build status](https://github.com/fgmacedo/python-statemachine/actions/workflows/python-package.yml/badge.svg?branch=develop)](https://github.com/fgmacedo/python-statemachine/actions/workflows/python-package.yml?query=branch%3Adevelop)
31
32
  [![Coverage report](https://codecov.io/gh/fgmacedo/python-statemachine/branch/develop/graph/badge.svg)](https://codecov.io/gh/fgmacedo/python-statemachine)
32
33
  [![Documentation Status](https://readthedocs.org/projects/python-statemachine/badge/?version=latest)](https://python-statemachine.readthedocs.io/en/latest/?badge=latest)
33
34
  [![GitHub commits since last release (main)](https://img.shields.io/github/commits-since/fgmacedo/python-statemachine/main/develop)](https://github.com/fgmacedo/python-statemachine/compare/main...develop)
@@ -35,33 +36,43 @@ Description-Content-Type: text/markdown
35
36
 
36
37
  Python [finite-state machines](https://en.wikipedia.org/wiki/Finite-state_machine) made easy.
37
38
 
39
+ <div align="center">
38
40
 
39
- * Free software: MIT license
40
- * Documentation: https://python-statemachine.readthedocs.io.
41
+ ![](https://github.com/fgmacedo/python-statemachine/blob/develop/docs/images/python-statemachine.png?raw=true)
41
42
 
43
+ </div>
42
44
 
43
- Welcome to python-statemachine, an intuitive and powerful state machine framework designed for a
44
- great developer experience.
45
+ Welcome to python-statemachine, an intuitive and powerful state machine library designed for a
46
+ great developer experience. We provide an _pythonic_ and expressive API for implementing state
47
+ machines in sync or asynchonous Python codebases.
45
48
 
46
- 🚀 With StateMachine, you can easily create complex, dynamic systems with clean, readable code.
49
+ ## Features
47
50
 
48
- 💡 Our framework makes it easy to understand and reason about the different states, events and
49
- transitions in your system, so you can focus on building great products.
51
+ - **Basic components**: Easily define **States**, **Events**, and **Transitions** to model your logic.
52
+ - ⚙️ **Actions and handlers**: Attach actions and handlers to states, events, and transitions to control behavior dynamically.
53
+ - 🛡️ **Conditional transitions**: Implement **Guards** and **Validators** to conditionally control transitions, ensuring they only occur when specific conditions are met.
54
+ - 🚀 **Full async support**: Enjoy full asynchronous support. Await events, and dispatch callbacks asynchronously for seamless integration with async codebases.
55
+ - 🔄 **Full sync support**: Use the same state machine from synchronous codebases without any modifications.
56
+ - 🎨 **Declarative and simple API**: Utilize a clean, elegant, and readable API to define your state machine, making it easy to maintain and understand.
57
+ - 👀 **Observer pattern support**: Register external and generic objects to watch events and register callbacks.
58
+ - 🔍 **Decoupled design**: Separate concerns with a decoupled "state machine" and "model" design, promoting cleaner architecture and easier maintenance.
59
+ - ✅ **Correctness guarantees**: Ensured correctness with validations at class definition time:
60
+ - Ensures exactly one `initial` state.
61
+ - Disallows transitions from `final` states.
62
+ - Requires ongoing transitions for all non-final states.
63
+ - Guarantees all non-final states have at least one path to a final state if final states are declared.
64
+ - Validates the state machine graph representation has a single component.
65
+ - 📦 **Flexible event dispatching**: Dispatch events with any extra data, making it available to all callbacks, including actions and guards.
66
+ - 🔧 **Dependency injection**: Needed parameters are injected into callbacks.
67
+ - 📊 **Graphical representation**: Generate and output graphical representations of state machines. Create diagrams from the command line, at runtime, or even in Jupyter notebooks.
68
+ - 🌍 **Internationalization support**: Provides error messages in different languages, making the library accessible to a global audience.
69
+ - 🛡️ **Robust testing**: Ensured reliability with a codebase that is 100% covered by automated tests, including all docs examples. Releases follow semantic versioning for predictable releases.
70
+ - 🏛️ **Domain model integration**: Seamlessly integrate with domain models using Mixins.
71
+ - 🔧 **Django integration**: Automatically discover state machines in Django applications.
50
72
 
51
- 🔒 python-statemachine also provides robust error handling and ensures that your system stays
52
- in a valid state at all times.
53
73
 
54
74
 
55
- A few reasons why you may consider using it:
56
-
57
- * 📈 python-statemachine is designed to help you build scalable,
58
- maintainable systems that can handle any complexity.
59
- * 💪 You can easily create and manage multiple state machines within a single application.
60
- * 🚫 Prevents common mistakes and ensures that your system stays in a valid state at all times.
61
-
62
-
63
- ## Getting started
64
-
75
+ ## Installing
65
76
 
66
77
  To install Python State Machine, run this command in your terminal:
67
78
 
@@ -73,6 +84,8 @@ our docs for more details.
73
84
 
74
85
  pip install python-statemachine[diagrams]
75
86
 
87
+ ## First example
88
+
76
89
  Define your state machine:
77
90
 
78
91
  ```py
@@ -90,7 +103,7 @@ Define your state machine:
90
103
  ... | red.to(green)
91
104
  ... )
92
105
  ...
93
- ... def before_cycle(self, event: str, source: State, target: State, message: str = ""):
106
+ ... async def before_cycle(self, event: str, source: State, target: State, message: str = ""):
94
107
  ... message = ". " + message if message else ""
95
108
  ... return f"Running {event} from {source.id} to {target.id}{message}"
96
109
  ...
@@ -133,7 +146,27 @@ Then start sending events to your new state machine:
133
146
 
134
147
  ```
135
148
 
136
- That's it. This is all an external object needs to know about your state machine: How to send events.
149
+ You can use the exactly same state machine from an async codebase:
150
+
151
+
152
+ ```py
153
+ >>> async def run_sm():
154
+ ... asm = TrafficLightMachine()
155
+ ... results = []
156
+ ... for _i in range(4):
157
+ ... result = await asm.send("cycle")
158
+ ... results.append(result)
159
+ ... return results
160
+
161
+ >>> asyncio.run(run_sm())
162
+ Don't move.
163
+ Go ahead!
164
+ ['Running cycle from green to yellow', 'Running cycle from yellow to red', ...
165
+
166
+ ```
167
+
168
+
169
+ **That's it.** This is all an external object needs to know about your state machine: How to send events.
137
170
  Ideally, all states, transitions, and actions should be kept internally and not checked externally to avoid unnecessary coupling.
138
171
 
139
172
  But if your use case needs, you can inspect state machine properties, like the current state:
@@ -220,7 +253,7 @@ callback method.
220
253
  Note how `before_cycle` was declared:
221
254
 
222
255
  ```py
223
- def before_cycle(self, event: str, source: State, target: State, message: str = ""):
256
+ async def before_cycle(self, event: str, source: State, target: State, message: str = ""):
224
257
  message = ". " + message if message else ""
225
258
  return f"Running {event} from {source.id} to {target.id}{message}"
226
259
  ```
@@ -265,6 +298,34 @@ and in diagrams:
265
298
 
266
299
  ```
267
300
 
301
+ ## Async support
302
+
303
+ We support native coroutine using `asyncio`, enabling seamless integration with asynchronous code.
304
+ There's no change on the public API of the library to work on async codebases.
305
+
306
+
307
+ ```py
308
+ >>> class AsyncStateMachine(StateMachine):
309
+ ... initial = State('Initial', initial=True)
310
+ ... final = State('Final', final=True)
311
+ ...
312
+ ... advance = initial.to(final)
313
+ ...
314
+ ... async def on_advance(self):
315
+ ... return 42
316
+
317
+ >>> async def run_sm():
318
+ ... sm = AsyncStateMachine()
319
+ ... result = await sm.advance()
320
+ ... print(f"Result is {result}")
321
+ ... print(sm.current_state)
322
+
323
+ >>> asyncio.run(run_sm())
324
+ Result is 42
325
+ Final
326
+
327
+ ```
328
+
268
329
  ## A more useful example
269
330
 
270
331
  A simple didactic state machine for controlling an `Order`:
@@ -1,8 +1,8 @@
1
1
  # Python StateMachine
2
2
 
3
3
  [![pypi](https://img.shields.io/pypi/v/python-statemachine.svg)](https://pypi.python.org/pypi/python-statemachine)
4
+ [![downloads total](https://static.pepy.tech/badge/python-statemachine)](https://pepy.tech/project/python-statemachine)
4
5
  [![downloads](https://img.shields.io/pypi/dm/python-statemachine.svg)](https://pypi.python.org/pypi/python-statemachine)
5
- [![build status](https://github.com/fgmacedo/python-statemachine/actions/workflows/python-package.yml/badge.svg?branch=develop)](https://github.com/fgmacedo/python-statemachine/actions/workflows/python-package.yml?query=branch%3Adevelop)
6
6
  [![Coverage report](https://codecov.io/gh/fgmacedo/python-statemachine/branch/develop/graph/badge.svg)](https://codecov.io/gh/fgmacedo/python-statemachine)
7
7
  [![Documentation Status](https://readthedocs.org/projects/python-statemachine/badge/?version=latest)](https://python-statemachine.readthedocs.io/en/latest/?badge=latest)
8
8
  [![GitHub commits since last release (main)](https://img.shields.io/github/commits-since/fgmacedo/python-statemachine/main/develop)](https://github.com/fgmacedo/python-statemachine/compare/main...develop)
@@ -10,33 +10,43 @@
10
10
 
11
11
  Python [finite-state machines](https://en.wikipedia.org/wiki/Finite-state_machine) made easy.
12
12
 
13
+ <div align="center">
13
14
 
14
- * Free software: MIT license
15
- * Documentation: https://python-statemachine.readthedocs.io.
15
+ ![](https://github.com/fgmacedo/python-statemachine/blob/develop/docs/images/python-statemachine.png?raw=true)
16
16
 
17
+ </div>
17
18
 
18
- Welcome to python-statemachine, an intuitive and powerful state machine framework designed for a
19
- great developer experience.
19
+ Welcome to python-statemachine, an intuitive and powerful state machine library designed for a
20
+ great developer experience. We provide an _pythonic_ and expressive API for implementing state
21
+ machines in sync or asynchonous Python codebases.
20
22
 
21
- 🚀 With StateMachine, you can easily create complex, dynamic systems with clean, readable code.
23
+ ## Features
22
24
 
23
- 💡 Our framework makes it easy to understand and reason about the different states, events and
24
- transitions in your system, so you can focus on building great products.
25
+ - **Basic components**: Easily define **States**, **Events**, and **Transitions** to model your logic.
26
+ - ⚙️ **Actions and handlers**: Attach actions and handlers to states, events, and transitions to control behavior dynamically.
27
+ - 🛡️ **Conditional transitions**: Implement **Guards** and **Validators** to conditionally control transitions, ensuring they only occur when specific conditions are met.
28
+ - 🚀 **Full async support**: Enjoy full asynchronous support. Await events, and dispatch callbacks asynchronously for seamless integration with async codebases.
29
+ - 🔄 **Full sync support**: Use the same state machine from synchronous codebases without any modifications.
30
+ - 🎨 **Declarative and simple API**: Utilize a clean, elegant, and readable API to define your state machine, making it easy to maintain and understand.
31
+ - 👀 **Observer pattern support**: Register external and generic objects to watch events and register callbacks.
32
+ - 🔍 **Decoupled design**: Separate concerns with a decoupled "state machine" and "model" design, promoting cleaner architecture and easier maintenance.
33
+ - ✅ **Correctness guarantees**: Ensured correctness with validations at class definition time:
34
+ - Ensures exactly one `initial` state.
35
+ - Disallows transitions from `final` states.
36
+ - Requires ongoing transitions for all non-final states.
37
+ - Guarantees all non-final states have at least one path to a final state if final states are declared.
38
+ - Validates the state machine graph representation has a single component.
39
+ - 📦 **Flexible event dispatching**: Dispatch events with any extra data, making it available to all callbacks, including actions and guards.
40
+ - 🔧 **Dependency injection**: Needed parameters are injected into callbacks.
41
+ - 📊 **Graphical representation**: Generate and output graphical representations of state machines. Create diagrams from the command line, at runtime, or even in Jupyter notebooks.
42
+ - 🌍 **Internationalization support**: Provides error messages in different languages, making the library accessible to a global audience.
43
+ - 🛡️ **Robust testing**: Ensured reliability with a codebase that is 100% covered by automated tests, including all docs examples. Releases follow semantic versioning for predictable releases.
44
+ - 🏛️ **Domain model integration**: Seamlessly integrate with domain models using Mixins.
45
+ - 🔧 **Django integration**: Automatically discover state machines in Django applications.
25
46
 
26
- 🔒 python-statemachine also provides robust error handling and ensures that your system stays
27
- in a valid state at all times.
28
47
 
29
48
 
30
- A few reasons why you may consider using it:
31
-
32
- * 📈 python-statemachine is designed to help you build scalable,
33
- maintainable systems that can handle any complexity.
34
- * 💪 You can easily create and manage multiple state machines within a single application.
35
- * 🚫 Prevents common mistakes and ensures that your system stays in a valid state at all times.
36
-
37
-
38
- ## Getting started
39
-
49
+ ## Installing
40
50
 
41
51
  To install Python State Machine, run this command in your terminal:
42
52
 
@@ -48,6 +58,8 @@ our docs for more details.
48
58
 
49
59
  pip install python-statemachine[diagrams]
50
60
 
61
+ ## First example
62
+
51
63
  Define your state machine:
52
64
 
53
65
  ```py
@@ -65,7 +77,7 @@ Define your state machine:
65
77
  ... | red.to(green)
66
78
  ... )
67
79
  ...
68
- ... def before_cycle(self, event: str, source: State, target: State, message: str = ""):
80
+ ... async def before_cycle(self, event: str, source: State, target: State, message: str = ""):
69
81
  ... message = ". " + message if message else ""
70
82
  ... return f"Running {event} from {source.id} to {target.id}{message}"
71
83
  ...
@@ -108,7 +120,27 @@ Then start sending events to your new state machine:
108
120
 
109
121
  ```
110
122
 
111
- That's it. This is all an external object needs to know about your state machine: How to send events.
123
+ You can use the exactly same state machine from an async codebase:
124
+
125
+
126
+ ```py
127
+ >>> async def run_sm():
128
+ ... asm = TrafficLightMachine()
129
+ ... results = []
130
+ ... for _i in range(4):
131
+ ... result = await asm.send("cycle")
132
+ ... results.append(result)
133
+ ... return results
134
+
135
+ >>> asyncio.run(run_sm())
136
+ Don't move.
137
+ Go ahead!
138
+ ['Running cycle from green to yellow', 'Running cycle from yellow to red', ...
139
+
140
+ ```
141
+
142
+
143
+ **That's it.** This is all an external object needs to know about your state machine: How to send events.
112
144
  Ideally, all states, transitions, and actions should be kept internally and not checked externally to avoid unnecessary coupling.
113
145
 
114
146
  But if your use case needs, you can inspect state machine properties, like the current state:
@@ -195,7 +227,7 @@ callback method.
195
227
  Note how `before_cycle` was declared:
196
228
 
197
229
  ```py
198
- def before_cycle(self, event: str, source: State, target: State, message: str = ""):
230
+ async def before_cycle(self, event: str, source: State, target: State, message: str = ""):
199
231
  message = ". " + message if message else ""
200
232
  return f"Running {event} from {source.id} to {target.id}{message}"
201
233
  ```
@@ -240,6 +272,34 @@ and in diagrams:
240
272
 
241
273
  ```
242
274
 
275
+ ## Async support
276
+
277
+ We support native coroutine using `asyncio`, enabling seamless integration with asynchronous code.
278
+ There's no change on the public API of the library to work on async codebases.
279
+
280
+
281
+ ```py
282
+ >>> class AsyncStateMachine(StateMachine):
283
+ ... initial = State('Initial', initial=True)
284
+ ... final = State('Final', final=True)
285
+ ...
286
+ ... advance = initial.to(final)
287
+ ...
288
+ ... async def on_advance(self):
289
+ ... return 42
290
+
291
+ >>> async def run_sm():
292
+ ... sm = AsyncStateMachine()
293
+ ... result = await sm.advance()
294
+ ... print(f"Result is {result}")
295
+ ... print(sm.current_state)
296
+
297
+ >>> asyncio.run(run_sm())
298
+ Result is 42
299
+ Final
300
+
301
+ ```
302
+
243
303
  ## A more useful example
244
304
 
245
305
  A simple didactic state machine for controlling an `Order`:
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "python-statemachine"
3
- version = "2.1.2"
3
+ version = "2.3.0"
4
4
  description = "Python Finite State Machines made easy."
5
5
  authors = ["Fernando Macedo <fgmacedo@gmail.com>"]
6
6
  maintainers = [
@@ -27,36 +27,38 @@ classifiers = [
27
27
  "Programming Language :: Python :: 3.10",
28
28
  "Programming Language :: Python :: 3.11",
29
29
  "Programming Language :: Python :: 3.12",
30
- "Topic :: Software Development :: Libraries"
30
+ "Topic :: Software Development :: Libraries",
31
+ "Framework :: AsyncIO",
32
+ "Intended Audience :: Developers",
31
33
  ]
32
34
 
33
35
  [tool.poetry.extras]
34
36
  diagrams = ["pydot"]
35
37
 
36
38
  [tool.poetry.dependencies]
37
- python = ">=3.7, <3.13"
39
+ python = ">=3.7"
38
40
 
39
41
  [tool.poetry.group.dev.dependencies]
40
- pytest = "^7.2.0"
41
- pytest-cov = "^4.0.0"
42
- pytest-sugar = "^0.9.6"
43
- pydot = "^1.4.2"
44
- ruff = "^0.0.257"
45
- pre-commit = "^2.21.0"
46
- mypy = "^0.991"
47
- black = "^22.12.0"
48
- pdbpp = "^0.10.3"
42
+ pytest = "*"
43
+ pytest-cov = "*"
44
+ pytest-sugar = "^1.0.0"
45
+ pydot = "^2.0.0"
46
+ ruff = "^0.4.8"
47
+ pre-commit = "*"
48
+ mypy = "*"
49
49
  pytest-mock = "^3.10.0"
50
50
  pytest-profiling = "^1.7.0"
51
51
  pytest-benchmark = "^4.0.0"
52
+ pytest-asyncio = "*"
53
+ sphinx-rtd-theme = "^2.0.0"
52
54
 
53
55
  [tool.poetry.group.docs.dependencies]
54
- Sphinx = "4.5.0"
55
- sphinx-rtd-theme = "1.1.1"
56
- myst-parser = "^0.18.1"
57
- sphinx-gallery = "^0.11.1"
58
- pillow = "^9.4.0"
59
- sphinx-autobuild = "^2021.3.14"
56
+ Sphinx = "*"
57
+ sphinx-rtd-theme = "2.0.0"
58
+ myst-parser = "*"
59
+ sphinx-gallery = "*"
60
+ pillow = "*"
61
+ sphinx-autobuild = "*"
60
62
 
61
63
  [build-system]
62
64
  requires = ["poetry-core"]
@@ -65,6 +67,10 @@ build-backend = "poetry.core.masonry.api"
65
67
  [tool.pytest.ini_options]
66
68
  addopts = "--ignore=docs/conf.py --ignore=docs/auto_examples/ --ignore=docs/_build/ --ignore=tests/examples/ --cov --cov-config .coveragerc --doctest-glob='*.md' --doctest-modules --doctest-continue-on-failure --benchmark-autosave"
67
69
  doctest_optionflags = "ELLIPSIS IGNORE_EXCEPTION_DETAIL NORMALIZE_WHITESPACE IGNORE_EXCEPTION_DETAIL"
70
+ asyncio_mode = "auto"
71
+ markers = [
72
+ """slow: marks tests as slow (deselect with '-m "not slow"')""",
73
+ ]
68
74
 
69
75
  [tool.mypy]
70
76
  python_version = "3.12"
@@ -91,24 +97,8 @@ max-line-length = 99
91
97
  [tool.ruff]
92
98
  src = ["statemachine"]
93
99
 
94
- # Enable Pyflakes and pycodestyle rules.
95
- select = [
96
- "E", # pycodestyle errors
97
- "W", # pycodestyle warnings
98
- "F", # pyflakes
99
- "I", # isort
100
- "UP", # pyupgrade
101
- "C", # flake8-comprehensions
102
- "B", # flake8-bugbear
103
- "PT", # flake8-pytest-style
104
- ]
105
- ignore = [
106
- "UP006", # `use-pep585-annotation` Requires Python3.9+
107
- "UP035", # `use-pep585-annotation` Requires Python3.9+
108
- "UP038", # `use-pep585-annotation` Requires Python3.9+
109
- ]
110
-
111
100
  line-length = 99
101
+ target-version = "py312"
112
102
 
113
103
  # Exclude a variety of commonly ignored directories.
114
104
  exclude = [
@@ -131,19 +121,41 @@ exclude = [
131
121
  "venv",
132
122
  ]
133
123
 
124
+ [tool.ruff.lint]
125
+
126
+ # Enable Pyflakes and pycodestyle rules.
127
+ select = [
128
+ "E", # pycodestyle errors
129
+ "W", # pycodestyle warnings
130
+ "F", # pyflakes
131
+ "I", # isort
132
+ "UP", # pyupgrade
133
+ "C", # flake8-comprehensions
134
+ "B", # flake8-bugbear
135
+ "PT", # flake8-pytest-style
136
+ ]
137
+ ignore = [
138
+ "UP006", # `use-pep585-annotation` Requires Python3.9+
139
+ "UP035", # `use-pep585-annotation` Requires Python3.9+
140
+ "UP038", # `use-pep585-annotation` Requires Python3.9+
141
+ ]
142
+
134
143
  # Allow unused variables when underscore-prefixed.
135
144
  dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$"
136
145
 
137
- # Assume Python 3.11.
138
- target-version = "py311"
146
+ [tool.ruff.lint.per-file-ignores]
147
+ # Ignore `E402` (import violations) in all `__init__.py` files, and in `path/to/file.py`.
148
+ "__init__.py" = ["E402"]
149
+ "path/to/file.py" = ["E402"]
150
+ "tests/examples/**.py" = ["B018"]
139
151
 
140
- [tool.ruff.mccabe]
152
+ [tool.ruff.lint.mccabe]
141
153
  max-complexity = 6
142
154
 
143
- [tool.ruff.isort]
155
+ [tool.ruff.lint.isort]
144
156
  force-single-line = true
145
157
 
146
- [tool.ruff.pydocstyle]
158
+ [tool.ruff.lint.pydocstyle]
147
159
  # Use Google-style docstrings.
148
160
  convention = "google"
149
161
 
@@ -3,6 +3,6 @@ from .statemachine import StateMachine
3
3
 
4
4
  __author__ = """Fernando Macedo"""
5
5
  __email__ = "fgmacedo@gmail.com"
6
- __version__ = "2.1.2"
6
+ __version__ = "2.3.0"
7
7
 
8
8
  __all__ = ["StateMachine", "State"]