python-statemachine 2.6.0__tar.gz → 3.1.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 (571) hide show
  1. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/.github/ISSUE_TEMPLATE.md +2 -0
  2. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/.github/workflows/python-package.yml +5 -2
  3. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/.github/workflows/release.yml +1 -1
  4. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/.gitignore +6 -0
  5. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/.pre-commit-config.yaml +18 -2
  6. python_statemachine-3.1.0/AGENTS.md +283 -0
  7. python_statemachine-3.1.0/PKG-INFO +421 -0
  8. python_statemachine-3.1.0/README.md +393 -0
  9. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/conftest.py +4 -2
  10. python_statemachine-3.1.0/docs/actions.md +642 -0
  11. python_statemachine-3.1.0/docs/api.md +161 -0
  12. python_statemachine-3.1.0/docs/async.md +201 -0
  13. python_statemachine-3.1.0/docs/behaviour.md +186 -0
  14. python_statemachine-3.1.0/docs/concepts.md +152 -0
  15. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/docs/conf.py +4 -0
  16. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/docs/contributing.md +130 -0
  17. python_statemachine-3.1.0/docs/diagram.md +856 -0
  18. python_statemachine-3.1.0/docs/error_handling.md +246 -0
  19. python_statemachine-3.1.0/docs/events.md +383 -0
  20. python_statemachine-3.1.0/docs/guards.md +396 -0
  21. python_statemachine-3.1.0/docs/how-to/coming_from_state_pattern.md +396 -0
  22. python_statemachine-3.1.0/docs/how-to/coming_from_transitions.md +963 -0
  23. python_statemachine-3.1.0/docs/images/internal_transition_sc.png +0 -0
  24. python_statemachine-3.1.0/docs/images/readme_trafficlightmachine.png +0 -0
  25. python_statemachine-3.1.0/docs/images/test_state_machine_internal.png +0 -0
  26. python_statemachine-3.1.0/docs/index.md +90 -0
  27. python_statemachine-3.1.0/docs/integrations.md +170 -0
  28. python_statemachine-3.1.0/docs/invoke.md +570 -0
  29. python_statemachine-3.1.0/docs/listeners.md +277 -0
  30. python_statemachine-3.1.0/docs/models.md +70 -0
  31. python_statemachine-3.1.0/docs/processing_model.md +364 -0
  32. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/docs/releases/1.0.1.md +3 -1
  33. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/docs/releases/2.0.0.md +4 -1
  34. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/docs/releases/2.2.0.md +14 -14
  35. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/docs/releases/2.3.0.md +13 -15
  36. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/docs/releases/2.4.0.md +19 -21
  37. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/docs/releases/2.5.0.md +35 -56
  38. python_statemachine-3.1.0/docs/releases/3.0.0.md +667 -0
  39. python_statemachine-3.1.0/docs/releases/3.1.0.md +225 -0
  40. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/docs/releases/index.md +19 -6
  41. python_statemachine-3.1.0/docs/releases/upgrade_2x_to_3.md +477 -0
  42. python_statemachine-3.1.0/docs/statechart.md +286 -0
  43. python_statemachine-3.1.0/docs/states.md +230 -0
  44. python_statemachine-3.1.0/docs/timeout.md +92 -0
  45. python_statemachine-3.1.0/docs/transitions.md +384 -0
  46. python_statemachine-3.1.0/docs/tutorial.md +765 -0
  47. python_statemachine-3.1.0/docs/validations.md +280 -0
  48. python_statemachine-3.1.0/docs/weighted_transitions.md +234 -0
  49. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/pyproject.toml +48 -21
  50. python_statemachine-3.1.0/statemachine/__init__.py +21 -0
  51. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/statemachine/callbacks.py +131 -38
  52. python_statemachine-3.1.0/statemachine/configuration.py +162 -0
  53. python_statemachine-3.1.0/statemachine/contrib/diagram/__init__.py +237 -0
  54. python_statemachine-3.1.0/statemachine/contrib/diagram/__main__.py +6 -0
  55. python_statemachine-3.1.0/statemachine/contrib/diagram/extract.py +288 -0
  56. python_statemachine-3.1.0/statemachine/contrib/diagram/formatter.py +137 -0
  57. python_statemachine-3.1.0/statemachine/contrib/diagram/model.py +63 -0
  58. python_statemachine-3.1.0/statemachine/contrib/diagram/renderers/dot.py +532 -0
  59. python_statemachine-3.1.0/statemachine/contrib/diagram/renderers/mermaid.py +348 -0
  60. python_statemachine-3.1.0/statemachine/contrib/diagram/renderers/table.py +105 -0
  61. python_statemachine-3.1.0/statemachine/contrib/diagram/sphinx_ext.py +280 -0
  62. python_statemachine-3.1.0/statemachine/contrib/timeout.py +68 -0
  63. python_statemachine-3.1.0/statemachine/contrib/weighted.py +193 -0
  64. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/statemachine/dispatcher.py +2 -2
  65. python_statemachine-3.1.0/statemachine/engines/async_.py +529 -0
  66. python_statemachine-3.1.0/statemachine/engines/base.py +951 -0
  67. python_statemachine-3.1.0/statemachine/engines/sync.py +203 -0
  68. python_statemachine-3.1.0/statemachine/event.py +227 -0
  69. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/statemachine/event_data.py +28 -13
  70. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/statemachine/events.py +13 -4
  71. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/statemachine/exceptions.py +8 -4
  72. python_statemachine-3.1.0/statemachine/factory.py +396 -0
  73. python_statemachine-3.1.0/statemachine/graph.py +62 -0
  74. python_statemachine-3.1.0/statemachine/invoke.py +641 -0
  75. python_statemachine-3.1.0/statemachine/io/__init__.py +225 -0
  76. python_statemachine-3.1.0/statemachine/io/scxml/actions.py +650 -0
  77. python_statemachine-3.1.0/statemachine/io/scxml/invoke.py +233 -0
  78. python_statemachine-3.1.0/statemachine/io/scxml/parser.py +473 -0
  79. python_statemachine-3.1.0/statemachine/io/scxml/processor.py +263 -0
  80. python_statemachine-3.1.0/statemachine/io/scxml/schema.py +175 -0
  81. python_statemachine-3.1.0/statemachine/locale/en/LC_MESSAGES/statemachine.po +160 -0
  82. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/statemachine/locale/hi_IN/LC_MESSAGES/statemachine.po +85 -35
  83. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/statemachine/locale/pt_BR/LC_MESSAGES/statemachine.po +86 -34
  84. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/statemachine/locale/zh_CN/LC_MESSAGES/statemachine.po +79 -33
  85. python_statemachine-3.1.0/statemachine/orderedset.py +118 -0
  86. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/statemachine/registry.py +4 -10
  87. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/statemachine/signature.py +3 -1
  88. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/statemachine/spec_parser.py +50 -9
  89. python_statemachine-3.1.0/statemachine/state.py +451 -0
  90. python_statemachine-3.1.0/statemachine/statemachine.py +530 -0
  91. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/statemachine/states.py +22 -19
  92. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/statemachine/transition.py +46 -8
  93. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/statemachine/transition_list.py +7 -0
  94. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/statemachine/transition_mixin.py +6 -2
  95. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/statemachine/utils.py +20 -1
  96. python_statemachine-3.1.0/tests/conftest.py +270 -0
  97. python_statemachine-3.1.0/tests/django_project/workflow/__init__.py +0 -0
  98. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/tests/django_project/workflow/statemachines.py +4 -2
  99. python_statemachine-3.1.0/tests/examples/__init__.py +0 -0
  100. python_statemachine-3.1.0/tests/examples/ai_shell_machine.py +568 -0
  101. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/tests/examples/air_conditioner_machine.py +3 -3
  102. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/tests/examples/all_actions_machine.py +5 -4
  103. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/tests/examples/async_guess_the_number_machine.py +9 -7
  104. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/tests/examples/async_without_loop_machine.py +4 -4
  105. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/tests/examples/enum_campaign_machine.py +13 -15
  106. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/tests/examples/guess_the_number_machine.py +4 -3
  107. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/tests/examples/lor_machine.py +11 -10
  108. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/tests/examples/order_control_machine.py +5 -3
  109. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/tests/examples/order_control_rich_model_machine.py +7 -4
  110. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/tests/examples/persistent_model_machine.py +6 -6
  111. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/tests/examples/recursive_event_machine.py +3 -2
  112. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/tests/examples/reusing_transitions_machine.py +3 -3
  113. python_statemachine-3.1.0/tests/examples/sqlite_persistent_model_machine.py +446 -0
  114. python_statemachine-3.1.0/tests/examples/statechart_cleanup_machine.py +111 -0
  115. python_statemachine-3.1.0/tests/examples/statechart_compound_machine.py +97 -0
  116. python_statemachine-3.1.0/tests/examples/statechart_delayed_machine.py +189 -0
  117. python_statemachine-3.1.0/tests/examples/statechart_error_handling_machine.py +104 -0
  118. python_statemachine-3.1.0/tests/examples/statechart_eventless_machine.py +99 -0
  119. python_statemachine-3.1.0/tests/examples/statechart_history_machine.py +125 -0
  120. python_statemachine-3.1.0/tests/examples/statechart_in_condition_machine.py +115 -0
  121. python_statemachine-3.1.0/tests/examples/statechart_parallel_machine.py +97 -0
  122. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/tests/examples/traffic_light_machine.py +4 -4
  123. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/tests/examples/user_machine.py +5 -4
  124. python_statemachine-3.1.0/tests/examples/weighted_idle_machine.py +41 -0
  125. python_statemachine-3.1.0/tests/machines/__init__.py +0 -0
  126. python_statemachine-3.1.0/tests/machines/compound/__init__.py +0 -0
  127. python_statemachine-3.1.0/tests/machines/compound/middle_earth_journey.py +25 -0
  128. python_statemachine-3.1.0/tests/machines/compound/middle_earth_journey_two_compounds.py +18 -0
  129. python_statemachine-3.1.0/tests/machines/compound/middle_earth_journey_with_finals.py +25 -0
  130. python_statemachine-3.1.0/tests/machines/compound/moria_expedition.py +15 -0
  131. python_statemachine-3.1.0/tests/machines/compound/moria_expedition_with_escape.py +18 -0
  132. python_statemachine-3.1.0/tests/machines/compound/quest_for_erebor.py +13 -0
  133. python_statemachine-3.1.0/tests/machines/compound/shire_to_rivendell.py +13 -0
  134. python_statemachine-3.1.0/tests/machines/donedata/__init__.py +0 -0
  135. python_statemachine-3.1.0/tests/machines/donedata/destroy_the_ring.py +20 -0
  136. python_statemachine-3.1.0/tests/machines/donedata/destroy_the_ring_simple.py +17 -0
  137. python_statemachine-3.1.0/tests/machines/donedata/nested_quest_donedata.py +22 -0
  138. python_statemachine-3.1.0/tests/machines/donedata/quest_for_erebor_done_convention.py +13 -0
  139. python_statemachine-3.1.0/tests/machines/donedata/quest_for_erebor_explicit_id.py +14 -0
  140. python_statemachine-3.1.0/tests/machines/donedata/quest_for_erebor_multi_word.py +13 -0
  141. python_statemachine-3.1.0/tests/machines/donedata/quest_for_erebor_with_event.py +14 -0
  142. python_statemachine-3.1.0/tests/machines/error/__init__.py +0 -0
  143. python_statemachine-3.1.0/tests/machines/error/error_convention_event.py +16 -0
  144. python_statemachine-3.1.0/tests/machines/error/error_convention_transition_list.py +15 -0
  145. python_statemachine-3.1.0/tests/machines/error/error_in_action_sc.py +15 -0
  146. python_statemachine-3.1.0/tests/machines/error/error_in_action_sm_with_flag.py +17 -0
  147. python_statemachine-3.1.0/tests/machines/error/error_in_after_sc.py +15 -0
  148. python_statemachine-3.1.0/tests/machines/error/error_in_error_handler_sc.py +24 -0
  149. python_statemachine-3.1.0/tests/machines/error/error_in_guard_sc.py +14 -0
  150. python_statemachine-3.1.0/tests/machines/error/error_in_guard_sm.py +15 -0
  151. python_statemachine-3.1.0/tests/machines/error/error_in_on_enter_sc.py +15 -0
  152. python_statemachine-3.1.0/tests/machines/eventless/__init__.py +0 -0
  153. python_statemachine-3.1.0/tests/machines/eventless/auto_advance.py +15 -0
  154. python_statemachine-3.1.0/tests/machines/eventless/beacon_chain.py +13 -0
  155. python_statemachine-3.1.0/tests/machines/eventless/beacon_chain_lighting.py +18 -0
  156. python_statemachine-3.1.0/tests/machines/eventless/coordinated_advance.py +18 -0
  157. python_statemachine-3.1.0/tests/machines/eventless/ring_corruption.py +18 -0
  158. python_statemachine-3.1.0/tests/machines/eventless/ring_corruption_with_bear_ring.py +18 -0
  159. python_statemachine-3.1.0/tests/machines/eventless/ring_corruption_with_tick.py +15 -0
  160. python_statemachine-3.1.0/tests/machines/history/__init__.py +0 -0
  161. python_statemachine-3.1.0/tests/machines/history/deep_memory_of_moria.py +21 -0
  162. python_statemachine-3.1.0/tests/machines/history/gollum_personality.py +17 -0
  163. python_statemachine-3.1.0/tests/machines/history/gollum_personality_default_gollum.py +17 -0
  164. python_statemachine-3.1.0/tests/machines/history/gollum_personality_with_default.py +17 -0
  165. python_statemachine-3.1.0/tests/machines/history/shallow_moria.py +21 -0
  166. python_statemachine-3.1.0/tests/machines/in_condition/__init__.py +0 -0
  167. python_statemachine-3.1.0/tests/machines/in_condition/combined_guard.py +18 -0
  168. python_statemachine-3.1.0/tests/machines/in_condition/descendant_check.py +15 -0
  169. python_statemachine-3.1.0/tests/machines/in_condition/eventless_in.py +18 -0
  170. python_statemachine-3.1.0/tests/machines/in_condition/fellowship.py +18 -0
  171. python_statemachine-3.1.0/tests/machines/in_condition/fellowship_coordination.py +18 -0
  172. python_statemachine-3.1.0/tests/machines/in_condition/gate_of_moria.py +13 -0
  173. python_statemachine-3.1.0/tests/machines/parallel/__init__.py +0 -0
  174. python_statemachine-3.1.0/tests/machines/parallel/session.py +17 -0
  175. python_statemachine-3.1.0/tests/machines/parallel/session_with_done_state.py +20 -0
  176. python_statemachine-3.1.0/tests/machines/parallel/two_towers.py +20 -0
  177. python_statemachine-3.1.0/tests/machines/parallel/war_of_the_ring.py +25 -0
  178. python_statemachine-3.1.0/tests/machines/parallel/war_with_exit.py +20 -0
  179. python_statemachine-3.1.0/tests/machines/showcase_actions.py +16 -0
  180. python_statemachine-3.1.0/tests/machines/showcase_compound.py +15 -0
  181. python_statemachine-3.1.0/tests/machines/showcase_deep_history.py +21 -0
  182. python_statemachine-3.1.0/tests/machines/showcase_guards.py +16 -0
  183. python_statemachine-3.1.0/tests/machines/showcase_history.py +17 -0
  184. python_statemachine-3.1.0/tests/machines/showcase_internal.py +12 -0
  185. python_statemachine-3.1.0/tests/machines/showcase_parallel.py +21 -0
  186. python_statemachine-3.1.0/tests/machines/showcase_parallel_compound.py +34 -0
  187. python_statemachine-3.1.0/tests/machines/showcase_self_transition.py +10 -0
  188. python_statemachine-3.1.0/tests/machines/showcase_simple.py +16 -0
  189. python_statemachine-3.1.0/tests/machines/transition_from_any.py +30 -0
  190. python_statemachine-3.1.0/tests/machines/tutorial_coffee_order.py +13 -0
  191. python_statemachine-3.1.0/tests/machines/validators/__init__.py +0 -0
  192. python_statemachine-3.1.0/tests/machines/validators/multi_validator.py +19 -0
  193. python_statemachine-3.1.0/tests/machines/validators/order_validation.py +17 -0
  194. python_statemachine-3.1.0/tests/machines/validators/order_validation_no_error_events.py +19 -0
  195. python_statemachine-3.1.0/tests/machines/validators/validator_fallthrough.py +20 -0
  196. python_statemachine-3.1.0/tests/machines/validators/validator_with_cond.py +17 -0
  197. python_statemachine-3.1.0/tests/machines/validators/validator_with_error_transition.py +25 -0
  198. python_statemachine-3.1.0/tests/machines/workflow/__init__.py +0 -0
  199. python_statemachine-3.1.0/tests/machines/workflow/campaign_machine.py +14 -0
  200. python_statemachine-3.1.0/tests/machines/workflow/campaign_machine_with_validator.py +18 -0
  201. python_statemachine-3.1.0/tests/machines/workflow/campaign_machine_with_values.py +14 -0
  202. python_statemachine-3.1.0/tests/machines/workflow/reverse_traffic_light.py +13 -0
  203. python_statemachine-3.1.0/tests/scxml/__init__.py +0 -0
  204. python_statemachine-3.1.0/tests/scxml/conftest.py +74 -0
  205. python_statemachine-3.1.0/tests/scxml/test_microwave.py +130 -0
  206. python_statemachine-3.1.0/tests/scxml/test_scxml_cases.py +101 -0
  207. python_statemachine-3.1.0/tests/scxml/w3c/LICENSE +11 -0
  208. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test144.scxml +33 -0
  209. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test145.scxml +31 -0
  210. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test147.scxml +36 -0
  211. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test148.scxml +36 -0
  212. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test149.scxml +32 -0
  213. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test150.scxml +46 -0
  214. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test151.scxml +46 -0
  215. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test152.scxml +52 -0
  216. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test153.scxml +45 -0
  217. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test155.scxml +31 -0
  218. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test156.scxml +34 -0
  219. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test158.scxml +31 -0
  220. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test159.scxml +26 -0
  221. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test172.scxml +25 -0
  222. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test173.scxml +26 -0
  223. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test174.scxml +26 -0
  224. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test175.scxml +34 -0
  225. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test176.scxml +36 -0
  226. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test179.scxml +24 -0
  227. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test183.scxml +26 -0
  228. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test185.scxml +27 -0
  229. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test186.scxml +39 -0
  230. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test187.scxml +40 -0
  231. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test189.scxml +29 -0
  232. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test190.scxml +45 -0
  233. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test191.scxml +40 -0
  234. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test192.scxml +57 -0
  235. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test194.scxml +26 -0
  236. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test198.scxml +26 -0
  237. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test199.scxml +23 -0
  238. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test200.scxml +23 -0
  239. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test205.scxml +36 -0
  240. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test207.scxml +63 -0
  241. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test208.scxml +26 -0
  242. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test210.scxml +28 -0
  243. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test215.scxml +41 -0
  244. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test216.scxml +33 -0
  245. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test216sub1.scxml +8 -0
  246. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test220.scxml +33 -0
  247. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test223.scxml +40 -0
  248. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test224.scxml +43 -0
  249. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test225.scxml +49 -0
  250. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test226.scxml +50 -0
  251. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test226sub1.scxml +18 -0
  252. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test228.scxml +44 -0
  253. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test229.scxml +54 -0
  254. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test232.scxml +51 -0
  255. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test233.scxml +46 -0
  256. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test234.scxml +77 -0
  257. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test235.scxml +34 -0
  258. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test236.scxml +51 -0
  259. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test237.scxml +52 -0
  260. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test239.scxml +42 -0
  261. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test239sub1.scxml +7 -0
  262. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test240.scxml +77 -0
  263. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test241.scxml +109 -0
  264. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test242.scxml +64 -0
  265. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test242sub1.scxml +7 -0
  266. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test243.scxml +46 -0
  267. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test244.scxml +49 -0
  268. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test245.scxml +46 -0
  269. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test247.scxml +32 -0
  270. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test252.scxml +58 -0
  271. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test253.scxml +80 -0
  272. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test276.scxml +27 -0
  273. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test276sub1.scxml +24 -0
  274. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test277.scxml +39 -0
  275. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test279.scxml +32 -0
  276. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test280.scxml +40 -0
  277. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test286.scxml +30 -0
  278. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test287.scxml +30 -0
  279. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test294.scxml +39 -0
  280. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test298.scxml +34 -0
  281. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test302.scxml +25 -0
  282. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test303.scxml +31 -0
  283. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test304.scxml +24 -0
  284. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test309.scxml +24 -0
  285. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test310.scxml +28 -0
  286. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test311.scxml +27 -0
  287. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test312.scxml +30 -0
  288. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test318.scxml +38 -0
  289. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test319.scxml +30 -0
  290. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test321.scxml +25 -0
  291. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test322.scxml +47 -0
  292. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test323.scxml +25 -0
  293. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test324.scxml +32 -0
  294. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test325.scxml +27 -0
  295. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test326.scxml +46 -0
  296. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test329.scxml +63 -0
  297. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test330.scxml +38 -0
  298. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test331.scxml +70 -0
  299. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test332.scxml +40 -0
  300. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test333.scxml +25 -0
  301. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test335.scxml +25 -0
  302. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test336.scxml +36 -0
  303. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test337.scxml +25 -0
  304. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test338.scxml +49 -0
  305. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test339.scxml +26 -0
  306. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test342.scxml +36 -0
  307. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test343.scxml +36 -0
  308. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test344.scxml +32 -0
  309. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test346.scxml +67 -0
  310. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test347.scxml +53 -0
  311. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test348.scxml +28 -0
  312. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test349.scxml +41 -0
  313. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test350.scxml +34 -0
  314. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test351.scxml +59 -0
  315. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test352.scxml +39 -0
  316. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test354.scxml +63 -0
  317. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test355.scxml +25 -0
  318. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test364.scxml +81 -0
  319. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test372.scxml +36 -0
  320. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test375.scxml +36 -0
  321. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test376.scxml +33 -0
  322. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test377.scxml +41 -0
  323. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test378.scxml +36 -0
  324. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test387.scxml +61 -0
  325. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test388.scxml +76 -0
  326. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test396.scxml +27 -0
  327. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test399.scxml +77 -0
  328. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test401.scxml +27 -0
  329. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test402.scxml +51 -0
  330. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test403a.scxml +48 -0
  331. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test403b.scxml +43 -0
  332. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test403c.scxml +54 -0
  333. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test404.scxml +71 -0
  334. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test405.scxml +78 -0
  335. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test406.scxml +76 -0
  336. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test407.scxml +31 -0
  337. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test409.scxml +45 -0
  338. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test411.scxml +44 -0
  339. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test412.scxml +66 -0
  340. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test413.scxml +59 -0
  341. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test416.scxml +33 -0
  342. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test417.scxml +43 -0
  343. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test419.scxml +27 -0
  344. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test421.scxml +35 -0
  345. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test422.scxml +86 -0
  346. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test423.scxml +36 -0
  347. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test487.scxml +27 -0
  348. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test488.scxml +34 -0
  349. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test495.scxml +35 -0
  350. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test496.scxml +28 -0
  351. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test500.scxml +27 -0
  352. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test501.scxml +31 -0
  353. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test503.scxml +48 -0
  354. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test504.scxml +81 -0
  355. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test505.scxml +58 -0
  356. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test506.scxml +64 -0
  357. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test521.scxml +34 -0
  358. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test525.scxml +31 -0
  359. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test527.scxml +29 -0
  360. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test528.scxml +34 -0
  361. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test529.scxml +27 -0
  362. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test530.scxml +39 -0
  363. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test533.scxml +74 -0
  364. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test550.scxml +26 -0
  365. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test551.scxml +28 -0
  366. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test552.scxml +24 -0
  367. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test552.txt +1 -0
  368. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test553.scxml +34 -0
  369. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test554.scxml +36 -0
  370. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test570.scxml +48 -0
  371. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test576.scxml +45 -0
  372. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test579.scxml +63 -0
  373. python_statemachine-3.1.0/tests/scxml/w3c/mandatory/test580.scxml +46 -0
  374. python_statemachine-3.1.0/tests/scxml/w3c/optional/test193.scxml +30 -0
  375. python_statemachine-3.1.0/tests/scxml/w3c/optional/test201.scxml +25 -0
  376. python_statemachine-3.1.0/tests/scxml/w3c/optional/test278.scxml +32 -0
  377. python_statemachine-3.1.0/tests/scxml/w3c/optional/test444.scxml +23 -0
  378. python_statemachine-3.1.0/tests/scxml/w3c/optional/test445.scxml +22 -0
  379. python_statemachine-3.1.0/tests/scxml/w3c/optional/test446.scxml +28 -0
  380. python_statemachine-3.1.0/tests/scxml/w3c/optional/test446.txt +1 -0
  381. python_statemachine-3.1.0/tests/scxml/w3c/optional/test448.scxml +39 -0
  382. python_statemachine-3.1.0/tests/scxml/w3c/optional/test449.scxml +19 -0
  383. python_statemachine-3.1.0/tests/scxml/w3c/optional/test451.scxml +22 -0
  384. python_statemachine-3.1.0/tests/scxml/w3c/optional/test452.scxml +39 -0
  385. python_statemachine-3.1.0/tests/scxml/w3c/optional/test453.scxml +28 -0
  386. python_statemachine-3.1.0/tests/scxml/w3c/optional/test456.scxml +26 -0
  387. python_statemachine-3.1.0/tests/scxml/w3c/optional/test457.scxml +63 -0
  388. python_statemachine-3.1.0/tests/scxml/w3c/optional/test459.scxml +46 -0
  389. python_statemachine-3.1.0/tests/scxml/w3c/optional/test460.scxml +31 -0
  390. python_statemachine-3.1.0/tests/scxml/w3c/optional/test509.scxml +26 -0
  391. python_statemachine-3.1.0/tests/scxml/w3c/optional/test510.scxml +31 -0
  392. python_statemachine-3.1.0/tests/scxml/w3c/optional/test518.scxml +27 -0
  393. python_statemachine-3.1.0/tests/scxml/w3c/optional/test519.scxml +27 -0
  394. python_statemachine-3.1.0/tests/scxml/w3c/optional/test520.scxml +31 -0
  395. python_statemachine-3.1.0/tests/scxml/w3c/optional/test522.scxml +29 -0
  396. python_statemachine-3.1.0/tests/scxml/w3c/optional/test531.scxml +28 -0
  397. python_statemachine-3.1.0/tests/scxml/w3c/optional/test532.scxml +28 -0
  398. python_statemachine-3.1.0/tests/scxml/w3c/optional/test534.scxml +26 -0
  399. python_statemachine-3.1.0/tests/scxml/w3c/optional/test557.scxml +34 -0
  400. python_statemachine-3.1.0/tests/scxml/w3c/optional/test557.txt +4 -0
  401. python_statemachine-3.1.0/tests/scxml/w3c/optional/test558.scxml +33 -0
  402. python_statemachine-3.1.0/tests/scxml/w3c/optional/test558.txt +3 -0
  403. python_statemachine-3.1.0/tests/scxml/w3c/optional/test560.scxml +25 -0
  404. python_statemachine-3.1.0/tests/scxml/w3c/optional/test561.scxml +31 -0
  405. python_statemachine-3.1.0/tests/scxml/w3c/optional/test562.scxml +28 -0
  406. python_statemachine-3.1.0/tests/scxml/w3c/optional/test567.scxml +39 -0
  407. python_statemachine-3.1.0/tests/scxml/w3c/optional/test569.scxml +21 -0
  408. python_statemachine-3.1.0/tests/scxml/w3c/optional/test577.scxml +26 -0
  409. python_statemachine-3.1.0/tests/scxml/w3c/optional/test578.scxml +25 -0
  410. python_statemachine-3.1.0/tests/test_api_contract.py +280 -0
  411. python_statemachine-3.1.0/tests/test_async.py +557 -0
  412. python_statemachine-3.1.0/tests/test_async_futures.py +341 -0
  413. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/tests/test_callbacks.py +44 -6
  414. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/tests/test_callbacks_isolation.py +5 -3
  415. python_statemachine-3.1.0/tests/test_class_listeners.py +477 -0
  416. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/tests/test_conditions_algebra.py +10 -7
  417. python_statemachine-3.1.0/tests/test_configuration.py +217 -0
  418. python_statemachine-3.1.0/tests/test_contrib_diagram.py +1803 -0
  419. python_statemachine-3.1.0/tests/test_contrib_timeout.py +139 -0
  420. python_statemachine-3.1.0/tests/test_copy.py +190 -0
  421. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/tests/test_dispatcher.py +4 -2
  422. python_statemachine-3.1.0/tests/test_error_execution.py +1020 -0
  423. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/tests/test_events.py +62 -25
  424. python_statemachine-3.1.0/tests/test_fellowship_quest.py +452 -0
  425. python_statemachine-3.1.0/tests/test_invoke.py +1250 -0
  426. python_statemachine-3.1.0/tests/test_io.py +46 -0
  427. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/tests/test_listener.py +2 -27
  428. python_statemachine-3.1.0/tests/test_mermaid_renderer.py +702 -0
  429. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/tests/test_mixins.py +2 -2
  430. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/tests/test_mock_compatibility.py +2 -2
  431. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/tests/test_multiple_destinations.py +23 -11
  432. python_statemachine-3.1.0/tests/test_profiling.py +293 -0
  433. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/tests/test_registry.py +1 -4
  434. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/tests/test_rtc.py +46 -92
  435. python_statemachine-3.1.0/tests/test_scxml_units.py +1055 -0
  436. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/tests/test_spec_parser.py +61 -60
  437. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/tests/test_state.py +31 -2
  438. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/tests/test_state_callbacks.py +2 -2
  439. python_statemachine-3.1.0/tests/test_statechart_compound.py +254 -0
  440. python_statemachine-3.1.0/tests/test_statechart_delayed.py +100 -0
  441. python_statemachine-3.1.0/tests/test_statechart_donedata.py +109 -0
  442. python_statemachine-3.1.0/tests/test_statechart_error.py +83 -0
  443. python_statemachine-3.1.0/tests/test_statechart_eventless.py +78 -0
  444. python_statemachine-3.1.0/tests/test_statechart_history.py +108 -0
  445. python_statemachine-3.1.0/tests/test_statechart_in_condition.py +78 -0
  446. python_statemachine-3.1.0/tests/test_statechart_parallel.py +201 -0
  447. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/tests/test_statemachine.py +334 -90
  448. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/tests/test_statemachine_bounded_transitions.py +2 -2
  449. python_statemachine-3.1.0/tests/test_statemachine_compat.py +383 -0
  450. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/tests/test_statemachine_inheritance.py +3 -3
  451. python_statemachine-3.1.0/tests/test_threading.py +350 -0
  452. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/tests/test_transition_list.py +42 -0
  453. python_statemachine-3.1.0/tests/test_transition_table.py +201 -0
  454. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/tests/test_transitions.py +111 -41
  455. python_statemachine-3.1.0/tests/test_validators.py +167 -0
  456. python_statemachine-3.1.0/tests/test_weighted_transitions.py +458 -0
  457. python_statemachine-3.1.0/tests/testcases/__init__.py +0 -0
  458. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/tests/testcases/issue308.md +16 -10
  459. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/tests/testcases/issue384_multiple_observers.md +5 -5
  460. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/tests/testcases/issue449.md +6 -6
  461. python_statemachine-3.1.0/tests/testcases/test_issue434.py +75 -0
  462. python_statemachine-3.1.0/tests/testcases/test_issue480.py +56 -0
  463. python_statemachine-3.1.0/tests/testcases/test_issue509.py +63 -0
  464. python_statemachine-3.1.0/uv.lock +2944 -0
  465. python_statemachine-2.6.0/AGENTS.md +0 -114
  466. python_statemachine-2.6.0/PKG-INFO +0 -433
  467. python_statemachine-2.6.0/README.md +0 -403
  468. python_statemachine-2.6.0/docs/actions.md +0 -463
  469. python_statemachine-2.6.0/docs/api.md +0 -81
  470. python_statemachine-2.6.0/docs/async.md +0 -186
  471. python_statemachine-2.6.0/docs/diagram.md +0 -154
  472. python_statemachine-2.6.0/docs/guards.md +0 -277
  473. python_statemachine-2.6.0/docs/images/order_control_machine_initial.png +0 -0
  474. python_statemachine-2.6.0/docs/images/order_control_machine_initial_300dpi.png +0 -0
  475. python_statemachine-2.6.0/docs/images/order_control_machine_processing.png +0 -0
  476. python_statemachine-2.6.0/docs/images/readme_trafficlightmachine.png +0 -0
  477. python_statemachine-2.6.0/docs/images/test_state_machine_internal.png +0 -0
  478. python_statemachine-2.6.0/docs/index.md +0 -33
  479. python_statemachine-2.6.0/docs/integrations.md +0 -90
  480. python_statemachine-2.6.0/docs/listeners.md +0 -105
  481. python_statemachine-2.6.0/docs/mixins.md +0 -93
  482. python_statemachine-2.6.0/docs/models.md +0 -27
  483. python_statemachine-2.6.0/docs/processing_model.md +0 -138
  484. python_statemachine-2.6.0/docs/readme.md +0 -2
  485. python_statemachine-2.6.0/docs/states.md +0 -166
  486. python_statemachine-2.6.0/docs/transitions.md +0 -378
  487. python_statemachine-2.6.0/statemachine/__init__.py +0 -9
  488. python_statemachine-2.6.0/statemachine/contrib/diagram.py +0 -242
  489. python_statemachine-2.6.0/statemachine/engines/async_.py +0 -158
  490. python_statemachine-2.6.0/statemachine/engines/base.py +0 -40
  491. python_statemachine-2.6.0/statemachine/engines/sync.py +0 -158
  492. python_statemachine-2.6.0/statemachine/event.py +0 -148
  493. python_statemachine-2.6.0/statemachine/factory.py +0 -261
  494. python_statemachine-2.6.0/statemachine/graph.py +0 -20
  495. python_statemachine-2.6.0/statemachine/locale/en/LC_MESSAGES/statemachine.po +0 -107
  496. python_statemachine-2.6.0/statemachine/state.py +0 -303
  497. python_statemachine-2.6.0/statemachine/statemachine.py +0 -334
  498. python_statemachine-2.6.0/tests/conftest.py +0 -213
  499. python_statemachine-2.6.0/tests/test_async.py +0 -279
  500. python_statemachine-2.6.0/tests/test_contrib_diagram.py +0 -90
  501. python_statemachine-2.6.0/tests/test_copy.py +0 -232
  502. python_statemachine-2.6.0/tests/test_profiling.py +0 -62
  503. python_statemachine-2.6.0/tests/test_threading.py +0 -188
  504. python_statemachine-2.6.0/tests/testcases/issue434.md +0 -87
  505. python_statemachine-2.6.0/tests/testcases/issue480.md +0 -43
  506. python_statemachine-2.6.0/uv.lock +0 -2081
  507. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/.git-blame-ignore-revs +0 -0
  508. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/.github/FUNDING.yml +0 -0
  509. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/.readthedocs.yaml +0 -0
  510. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/CLAUDE.md +0 -0
  511. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/LICENSE +0 -0
  512. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/contributing.md +0 -0
  513. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/docs/_static/custom_machine.css +0 -0
  514. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/docs/authors.md +0 -0
  515. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/docs/images/_oc_machine_processing.svg +0 -0
  516. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/docs/images/lab_approval_machine_accepted.png +0 -0
  517. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/docs/images/oc_machine_processing.svg +0 -0
  518. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/docs/images/python-statemachine.png +0 -0
  519. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/docs/images/traffic_light_machine.png +0 -0
  520. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/docs/installation.md +0 -0
  521. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/docs/releases/0.1.0.md +0 -0
  522. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/docs/releases/0.2.0.md +0 -0
  523. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/docs/releases/0.3.0.md +0 -0
  524. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/docs/releases/0.4.2.md +0 -0
  525. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/docs/releases/0.5.0.md +0 -0
  526. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/docs/releases/0.5.1.md +0 -0
  527. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/docs/releases/0.6.0.md +0 -0
  528. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/docs/releases/0.6.1.md +0 -0
  529. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/docs/releases/0.6.2.md +0 -0
  530. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/docs/releases/0.7.0.md +0 -0
  531. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/docs/releases/0.7.1.md +0 -0
  532. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/docs/releases/0.8.0.md +0 -0
  533. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/docs/releases/0.9.0.md +0 -0
  534. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/docs/releases/1.0.0.md +0 -0
  535. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/docs/releases/1.0.2.md +0 -0
  536. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/docs/releases/1.0.3.md +0 -0
  537. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/docs/releases/2.1.0.md +0 -0
  538. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/docs/releases/2.1.1.md +0 -0
  539. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/docs/releases/2.1.2.md +0 -0
  540. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/docs/releases/2.3.1.md +0 -0
  541. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/docs/releases/2.3.2.md +0 -0
  542. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/docs/releases/2.3.3.md +0 -0
  543. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/docs/releases/2.3.4.md +0 -0
  544. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/docs/releases/2.3.5.md +0 -0
  545. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/docs/releases/2.3.6.md +0 -0
  546. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/docs/releases/2.6.0.md +0 -0
  547. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/statemachine/contrib/__init__.py +0 -0
  548. {python_statemachine-2.6.0/statemachine/engines → python_statemachine-3.1.0/statemachine/contrib/diagram/renderers}/__init__.py +0 -0
  549. {python_statemachine-2.6.0/tests → python_statemachine-3.1.0/statemachine/engines}/__init__.py +0 -0
  550. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/statemachine/i18n.py +0 -0
  551. {python_statemachine-2.6.0/tests/django_project/workflow → python_statemachine-3.1.0/statemachine/io/scxml}/__init__.py +0 -0
  552. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/statemachine/mixins.py +0 -0
  553. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/statemachine/model.py +0 -0
  554. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/statemachine/py.typed +0 -0
  555. {python_statemachine-2.6.0/tests/examples → python_statemachine-3.1.0/tests}/__init__.py +0 -0
  556. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/tests/django_project/app.py +0 -0
  557. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/tests/django_project/core/__init__,.py +0 -0
  558. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/tests/django_project/core/settings.py +0 -0
  559. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/tests/django_project/core/wsgi.py +0 -0
  560. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/tests/django_project/manage.py +0 -0
  561. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/tests/django_project/workflow/apps.py +0 -0
  562. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/tests/django_project/workflow/models.py +0 -0
  563. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/tests/django_project/workflow/tests.py +0 -0
  564. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/tests/examples/README.rst +0 -0
  565. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/tests/helpers.py +0 -0
  566. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/tests/models.py +0 -0
  567. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/tests/scrape_images.py +0 -0
  568. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/tests/test_actions.py +0 -0
  569. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/tests/test_examples.py +0 -0
  570. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/tests/test_signature.py +0 -0
  571. {python_statemachine-2.6.0 → python_statemachine-3.1.0}/tests/test_signature_positional_only.py +0 -0
@@ -13,3 +13,5 @@ Tell us what happened, what went wrong, and what you expected to happen.
13
13
  Paste the command(s) you ran and the output.
14
14
  If there was a crash, please include the traceback here.
15
15
  ```
16
+
17
+ If you're reporting a bug, consider providing a complete example that can be used directly in the automated tests. We allways write tests to reproduce the issue in order to avoid future regressions.
@@ -9,13 +9,16 @@ on:
9
9
  pull_request:
10
10
  branches: [ "develop" ]
11
11
 
12
+ permissions:
13
+ contents: read
14
+
12
15
  jobs:
13
16
  build:
14
17
  runs-on: ubuntu-latest
15
18
  strategy:
16
19
  fail-fast: false
17
20
  matrix:
18
- python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13", "3.14"]
21
+ python-version: ["3.9", "3.10", "3.11", "3.12", "3.13", "3.14"]
19
22
 
20
23
  steps:
21
24
  - uses: actions/checkout@v4
@@ -46,7 +49,7 @@ jobs:
46
49
  #----------------------------------------------
47
50
  - name: Test with pytest
48
51
  run: |
49
- uv run pytest --cov-report=xml:coverage.xml
52
+ uv run pytest -n auto --cov --cov-report=xml:coverage.xml
50
53
  uv run coverage xml
51
54
  #----------------------------------------------
52
55
  # upload coverage
@@ -33,7 +33,7 @@ jobs:
33
33
 
34
34
  - name: Test
35
35
  run: |
36
- uv run pytest
36
+ uv run pytest -n auto --cov
37
37
 
38
38
  - name: Build
39
39
  run: |
@@ -79,3 +79,9 @@ target/
79
79
  docs/auto_examples/sg_execution_times.*
80
80
  docs/auto_examples/*.pickle
81
81
  docs/sg_execution_times.rst
82
+
83
+ # Temporary files
84
+ tmp/
85
+
86
+ # Local specs
87
+ specs/
@@ -9,7 +9,7 @@ repos:
9
9
  exclude: docs/auto_examples
10
10
  - repo: https://github.com/charliermarsh/ruff-pre-commit
11
11
  # Ruff version.
12
- rev: v0.15.0
12
+ rev: v0.15.8
13
13
  hooks:
14
14
  # Run the linter.
15
15
  - id: ruff
@@ -25,9 +25,25 @@ repos:
25
25
  types: [python]
26
26
  language: system
27
27
  pass_filenames: false
28
+ - id: pyright
29
+ name: Pyright
30
+ entry: uv run pyright statemachine/
31
+ types: [python]
32
+ language: system
33
+ pass_filenames: false
34
+ - id: generate-images
35
+ name: Generate README images
36
+ entry: >-
37
+ uv run python -m statemachine.contrib.diagram
38
+ tests.examples.traffic_light_machine.TrafficLightMachine
39
+ docs/images/readme_trafficlightmachine.png
40
+ --events cycle cycle cycle
41
+ language: system
42
+ pass_filenames: false
43
+ files: (statemachine/contrib/diagram/|tests/examples/traffic_light_machine\.py)
28
44
  - id: pytest
29
45
  name: Pytest
30
- entry: uv run pytest
46
+ entry: uv run pytest -n auto --cov-fail-under=100
31
47
  types: [python]
32
48
  language: system
33
49
  pass_filenames: false
@@ -0,0 +1,283 @@
1
+ # python-statemachine
2
+
3
+ Python Finite State Machines made easy.
4
+
5
+ ## Project overview
6
+
7
+ A library for building finite state machines in Python, with support for sync and async engines,
8
+ Django integration, diagram generation, and a flexible callback/listener system.
9
+
10
+ - **Source code:** `statemachine/`
11
+ - **Tests:** `tests/`
12
+ - **Documentation:** `docs/` (Sphinx + MyST Markdown, hosted on ReadTheDocs)
13
+
14
+ ## Architecture
15
+
16
+ - `statemachine.py` — Core `StateMachine` and `StateChart` classes
17
+ - `factory.py` — `StateMachineMetaclass` handles class construction, state/transition validation
18
+ - `state.py` / `event.py` — Descriptor-based `State` and `Event` definitions
19
+ - `transition.py` / `transition_list.py` — Transition logic and composition (`|` operator)
20
+ - `callbacks.py` — Priority-based callback registry (`CallbackPriority`, `CallbackGroup`)
21
+ - `dispatcher.py` — Listener/observer pattern, `callable_method` wraps callables with signature adaptation
22
+ - `signature.py` — `SignatureAdapter` for dependency injection into callbacks
23
+ - `engines/base.py` — Shared engine logic (microstep, transition selection, error handling)
24
+ - `engines/sync.py`, `engines/async_.py` — Sync and async processing loops
25
+ - `registry.py` — Global state machine registry (used by `MachineMixin`)
26
+ - `mixins.py` — `MachineMixin` for domain model integration (e.g., Django models)
27
+ - `spec_parser.py` — Boolean expression parser for condition guards
28
+ - `contrib/diagram.py` — Diagram generation via pydot/Graphviz
29
+
30
+ ## Processing model
31
+
32
+ The engine follows the SCXML run-to-completion (RTC) model with two processing levels:
33
+
34
+ - **Microstep**: atomic execution of one transition set (before → exit → on → enter → after).
35
+ - **Macrostep**: complete processing cycle for one external event; repeats microsteps until
36
+ the machine reaches a **stable configuration** (no eventless transitions enabled, internal
37
+ queue empty).
38
+
39
+ ### Event queues
40
+
41
+ - `send()` → **external queue** (processed after current macrostep ends).
42
+ - `raise_()` → **internal queue** (processed within the current macrostep, before external events).
43
+
44
+ ### Error handling (`catch_errors_as_events`)
45
+
46
+ - `StateChart` has `catch_errors_as_events=True` by default; `StateMachine` has `False`.
47
+ - Errors are caught at the **block level** (per onentry/onexit/transition `on` block), not per
48
+ microstep. This means `after` callbacks still run even when an action raises — making
49
+ `after_<event>()` a natural **finalize** hook (runs on both success and failure paths).
50
+ - `error.execution` is dispatched as an internal event; define transitions for it to handle
51
+ errors within the statechart.
52
+ - Error during `error.execution` handling → ignored to prevent infinite loops.
53
+
54
+ #### `on_error` asymmetry: transition `on` vs onentry/onexit
55
+
56
+ Transition `on` content uses `on_error` **only for non-`error.execution` events**. During
57
+ `error.execution` processing, `on_error` is disabled for transition `on` content — errors
58
+ propagate to `microstep()` where `_send_error_execution` ignores them. This prevents infinite
59
+ loops in self-transition error handlers (e.g., `error_execution = s1.to(s1, on="handler")`
60
+ where `handler` raises). `onentry`/`onexit` blocks always use `on_error` regardless of the
61
+ current event.
62
+
63
+ ### Eventless transitions
64
+
65
+ - Bare transition statements (not assigned to a variable) are **eventless** — they fire
66
+ automatically when their guard condition is met.
67
+ - Assigned transitions (e.g., `go = s1.to(s2)`) create **named events**.
68
+ - `error_` prefix naming convention: `error_X` auto-registers both `error_X` and `error.X`
69
+ event names (explicit `id=` takes precedence).
70
+
71
+ ### Callback conventions
72
+
73
+ - Generic callbacks (always available): `prepare_event()`, `before_transition()`,
74
+ `on_transition()`, `on_exit_state()`, `on_enter_state()`, `after_transition()`.
75
+ - Event-specific: `before_<event>()`, `on_<event>()`, `after_<event>()`.
76
+ - State-specific: `on_enter_<state>()`, `on_exit_<state>()`.
77
+ - `on_error_execution()` works via naming convention but **only** when a transition for
78
+ `error.execution` is declared — it is NOT a generic callback.
79
+
80
+ ### Thread safety
81
+
82
+ - The sync engine is **thread-safe**: multiple threads can send events to the same SM instance
83
+ concurrently. The processing loop uses a `threading.Lock` so at most one thread executes
84
+ transitions at a time. Event queues use `PriorityQueue` (stdlib, thread-safe).
85
+ - **Do not replace `PriorityQueue`** with non-thread-safe alternatives (e.g., `collections.deque`,
86
+ plain `list`) — this would break concurrent access guarantees.
87
+ - Stress tests in `tests/test_threading.py::TestThreadSafety` exercise real contention with
88
+ barriers and multiple sender threads. Any change to queue or locking internals must pass these.
89
+
90
+ ### Invoke (`<invoke>`)
91
+
92
+ - `invoke.py` — `InvokeManager` on the engine manages the lifecycle: `mark_for_invoke()`,
93
+ `cancel_for_state()`, `spawn_pending_sync/async()`, `send_to_child()`.
94
+ - `_cleanup_terminated()` only removes invocations that are both terminated **and** cancelled.
95
+ A terminated-but-not-cancelled invocation means the handler's `run()` returned but the owning
96
+ state is still active — it must stay in `_active` so `send_to_child()` can still route events.
97
+ - **Child machine constructor blocks** in the processing loop. Use a listener pattern (e.g.,
98
+ `_ChildRefSetter`) to capture the child reference during the first `on_enter_state`, before
99
+ the loop spins.
100
+ - `#_<invokeid>` send target: routed via `_send_to_invoke()` in `io/scxml/actions.py` →
101
+ `InvokeManager.send_to_child()` → handler's `on_event()`.
102
+ - **Tests with blocking threads**: use `threading.Event.wait(timeout=)` instead of
103
+ `time.sleep()` for interruptible waits — avoids thread leak errors in teardown.
104
+
105
+ ## Environment setup
106
+
107
+ ```bash
108
+ uv sync --all-extras --dev
109
+ pre-commit install
110
+ ```
111
+
112
+ ## Running tests
113
+
114
+ Always use `uv` to run commands. Also, use a timeout to avoid being stuck in the case of a leaked thread or infinite loop:
115
+
116
+ ```bash
117
+ # Run all tests (parallel)
118
+ timeout 120 uv run pytest -n 4
119
+
120
+ # Run a specific test file
121
+ uv run pytest tests/test_signature.py
122
+
123
+ # Run a specific test
124
+ uv run pytest tests/test_signature.py::TestSignatureAdapter::test_wrap_fn_single_positional_parameter
125
+
126
+ # Skip slow tests
127
+ uv run pytest -m "not slow"
128
+ ```
129
+
130
+ When trying to run all tests, prefer to use xdist (`-n`) as some SCXML tests uses timeout of 30s to verify fallback mechanism.
131
+ Don't specify the directory `tests/`, because this will exclude doctests from both source modules (`--doctest-modules`) and markdown docs
132
+ (`--doctest-glob=*.md`) (enabled by default):
133
+
134
+ ```bash
135
+ timeout 120 uv run pytest -n 4
136
+ ```
137
+
138
+ Testes normally run under 60s (~40s on average), so take a closer look if they take longer, it can be a regression.
139
+
140
+ ### Debug logging
141
+
142
+ `log_cli_level` defaults to `WARNING` in `pyproject.toml`. The engine caches a no-op
143
+ for `logger.debug` at init time — running tests with `DEBUG` would bypass this
144
+ optimization and inflate benchmark numbers. To enable debug logs for a specific run:
145
+
146
+ ```bash
147
+ uv run pytest -o log_cli_level=DEBUG tests/test_something.py
148
+ ```
149
+
150
+ When analyzing warnings or extensive output, run the tests **once** saving the output to a file
151
+ (`> /tmp/pytest-output.txt 2>&1`), then analyze the file — instead of running the suite
152
+ repeatedly with different greps.
153
+
154
+ Coverage is enabled by default (`--cov` is in `pyproject.toml`'s `addopts`). To generate a
155
+ coverage report to a file, pass `--cov-report` **in addition to** `--cov`:
156
+
157
+ ```bash
158
+ # JSON report (machine-readable, includes missing_lines per file)
159
+ timeout 120 uv run pytest -n auto --cov=statemachine --cov-report=json:cov.json
160
+
161
+ # Terminal report with missing lines
162
+ timeout 120 uv run pytest -n auto --cov=statemachine --cov-report=term-missing
163
+ ```
164
+
165
+ Note: `--cov=statemachine` is required to activate coverage collection; `--cov-report`
166
+ alone only changes the output format.
167
+
168
+ ### Testing both sync and async engines
169
+
170
+ Use the `sm_runner` fixture (from `tests/conftest.py`) when you need to test the same
171
+ statechart on both sync and async engines. It is parametrized with `["sync", "async"]`
172
+ and provides `start()` / `send()` helpers that handle engine selection automatically:
173
+
174
+ ```python
175
+ async def test_something(self, sm_runner):
176
+ sm = await sm_runner.start(MyStateChart)
177
+ await sm_runner.send(sm, "some_event")
178
+ assert "expected_state" in sm.configuration_values
179
+ ```
180
+
181
+ Do **not** manually add async no-op listeners or duplicate test classes — prefer `sm_runner`.
182
+
183
+ ### TDD and coverage requirements
184
+
185
+ Follow a **test-driven development** approach: tests are not an afterthought — they are a
186
+ first-class requirement that must be part of every implementation plan.
187
+
188
+ - **Planning phase:** every plan must include test tasks as explicit steps, not a final
189
+ "add tests" bullet. Identify what needs to be tested (new branches, edge cases, error
190
+ paths) while designing the implementation.
191
+ - **100% branch coverage is mandatory.** The pre-commit hook enforces `--cov-fail-under=100`
192
+ with branch coverage enabled. Code that drops coverage will not pass CI.
193
+ - **Verify coverage before committing:** after writing tests, run coverage on the affected
194
+ modules and check for missing lines/branches:
195
+ ```bash
196
+ timeout 120 uv run pytest tests/<test_file>.py --cov=statemachine.<module> --cov-report=term-missing --cov-branch
197
+ ```
198
+ - **Use pytest fixtures** (`tmp_path`, `monkeypatch`, etc.) — never hardcode paths or
199
+ use mutable global state when a fixture exists.
200
+ - **Unreachable defensive branches** (e.g., `if` guards that can never be True given the
201
+ type system) may be marked with `pragma: no cover`, but prefer writing a test first.
202
+
203
+ ## Linting and formatting
204
+
205
+ ```bash
206
+ # Lint
207
+ uv run ruff check .
208
+
209
+ # Auto-fix lint issues
210
+ uv run ruff check --fix .
211
+
212
+ # Format
213
+ uv run ruff format .
214
+
215
+ # Type check
216
+ uv run mypy statemachine/ tests/
217
+ ```
218
+
219
+ ## Code style
220
+
221
+ - **Formatter/Linter:** ruff (line length 99, target Python 3.9)
222
+ - **Rules:** pycodestyle, pyflakes, isort, pyupgrade, flake8-comprehensions, flake8-bugbear, flake8-pytest-style
223
+ - **Imports:** single-line, sorted by isort. **Always prefer top-level imports** — only use
224
+ lazy (in-function) imports when strictly necessary to break circular dependencies
225
+ - **Docstrings:** Google convention
226
+ - **Naming:** PascalCase for classes, snake_case for functions/methods, UPPER_SNAKE_CASE for constants
227
+ - **Type hints:** used throughout; `TYPE_CHECKING` for circular imports
228
+ - Pre-commit hooks enforce ruff + mypy + pytest
229
+
230
+ ## Design principles
231
+
232
+ - **Use GRASP/SOLID patterns to guide decisions.** When refactoring or designing, explicitly
233
+ apply patterns like Information Expert, Single Responsibility, and Law of Demeter to decide
234
+ where logic belongs — don't just pick a convenient location.
235
+ - **Information Expert (GRASP):** Place logic in the module/class that already has the
236
+ knowledge it needs. If a method computes a result, it should signal or return it rather
237
+ than forcing another method to recompute the same thing.
238
+ - **Law of Demeter:** Methods should depend only on the data they need, not on the
239
+ objects that contain it. Pass the specific value (e.g., a `Future`) rather than the
240
+ parent object (e.g., `TriggerData`) — this reduces coupling and removes the need for
241
+ null-checks on intermediate accessors.
242
+ - **Single Responsibility:** Each module, class, and function should have one clear reason
243
+ to change. Functions and types belong in the module that owns their domain (e.g.,
244
+ event-name helpers belong in `event.py`, not in `factory.py`).
245
+ - **Interface Segregation:** Depend on narrow interfaces. If a helper only needs one field
246
+ from a dataclass, accept that field directly.
247
+ - **Decouple infrastructure from domain:** Modules like `signature.py` and `dispatcher.py` are
248
+ general-purpose (signature adaptation, listener/observer pattern) and intentionally not coupled
249
+ to the state machine domain. Prefer this separation even for modules that are only used
250
+ internally — it keeps responsibilities clear and the code easier to reason about.
251
+ - **Favor small, focused modules:** When adding new functionality, consider whether it can live in
252
+ its own module with a well-defined boundary, rather than growing an existing one.
253
+
254
+ ## Building documentation
255
+
256
+ ```bash
257
+ # Build HTML docs
258
+ uv run sphinx-build docs docs/_build/html
259
+
260
+ # Live reload for development
261
+ uv run sphinx-autobuild docs docs/_build/html --re-ignore "auto_examples/.*"
262
+ ```
263
+
264
+ ### Documentation code examples
265
+
266
+ All code examples in `docs/*.md` **must** be testable doctests (using ```` ```py ```` with
267
+ `>>>` prompts), not plain ```` ```python ```` blocks. The test suite collects them via
268
+ `--doctest-glob=*.md`. If an example cannot be expressed as a doctest (e.g., it requires
269
+ real concurrency), write it as a unit test in `tests/` and reference it from the docs instead.
270
+
271
+ ## Git workflow
272
+
273
+ - Main branch: `develop`
274
+ - PRs target `develop`
275
+ - Releases are tagged as `v*.*.*`
276
+ - Signed commits preferred (`git commit -s`)
277
+ - Use [Conventional Commits](https://www.conventionalcommits.org/) messages
278
+ (e.g., `feat:`, `fix:`, `refactor:`, `test:`, `docs:`, `chore:`, `perf:`)
279
+
280
+ ## Security
281
+
282
+ - Do not commit secrets, credentials, or `.env` files
283
+ - Validate at system boundaries; trust internal code