Skip to content

Commit 2476d20

Browse files
authored
feat: Mermaid diagrams, transition tables, and format() support (#595)
* feat: add Mermaid diagrams, transition tables, and __format__ support - Add MermaidRenderer that converts DiagramGraph IR to Mermaid stateDiagram-v2 source (compound, parallel, history, guards, etc.) - Add TransitionTableRenderer for markdown and RST table output - Add MermaidGraphMachine facade mirroring DotGraphMachine - Add __format__ to StateChart and StateMachineMetaclass supporting dot, mermaid, md/markdown, and rst format specs - Extend CLI with --format option (mermaid, md, rst) and stdout support - Add :format: option to Sphinx statemachine-diagram directive with sphinxcontrib-mermaid integration - Update docs with new sections and doctests * refactor: introduce Formatter facade with decorator-based format registry Replace duplicated if/elif chains in StateChart.__format__ and StateMachineMetaclass.__format__ with a Formatter class that uses a decorator-based registry following the Open/Closed Principle. Adding a new format now requires only a decorated function — no changes to __format__, factory.py, or statemachine.py. * feat: add SVG text format and use formatter in Sphinx directive - Register "svg" format in Formatter (DOT → SVG decoded as str) - Refactor Sphinx directive to use formatter.render() for both SVG and Mermaid instead of calling DotGraphMachine/MermaidGraphMachine directly - Update _prepare_svg and _resolve_target to work with str (not bytes) * feat: auto-expand {statechart:FORMAT} placeholders in class docstrings The metaclass now detects {statechart:FORMAT} placeholders in docstrings and replaces them at class definition time with the rendered output. The docstring always stays in sync with the actual states and transitions. Any registered format works: md, rst, mermaid, dot, etc. Indentation of the placeholder line is preserved in the output. * docs: revise diagram.md for new features and narrative coherence - Reorganize into unified "Text representations" section with format table (name, aliases, description, dependencies) - Add formatter API section with render(), supported_formats(), and custom format registration example - Add live Mermaid directive example in Sphinx section - Add --format dot to CLI examples - Replace MermaidGraphMachine usage with formatter - Add autodoc integration example with SimpleSC - Add auto-expanding docstrings section with format recommendations - Update release notes * docs: mention f-string/format() text representations in README and tutorial * docs: revise 3.1.0 release notes and fix broken cross-references * fix: work around Mermaid crash for transitions inside parallel regions Mermaid's stateDiagram-v2 crashes when a transition targets or originates from a compound state inside a parallel region (mermaid-js/mermaid#4052). The MermaidRenderer now redirects such endpoints to the compound's initial child state. Also filter dot-form event aliases (e.g. done.invoke.X) from diagram output — the fix lives in the extractor so all renderers benefit. Closes #594 * fix: render cross-boundary transitions and restrict Mermaid compound workaround to parallel regions The Mermaid renderer had two issues: 1. Cross-scope transitions (e.g., an outer state targeting a history pseudo-state inside a compound) were silently dropped because `_render_scope_transitions` only rendered transitions where both endpoints were direct members of the same scope. Now the scope check expands to include descendants of compound states, while skipping transitions fully internal to a single compound (handled by the inner scope). 2. The compound→initial-child redirect (workaround for mermaid-js/mermaid#4052) was applied universally, but the bug only affects compound states inside parallel regions. Now the redirect is restricted to parallel descendants, leaving compound states outside parallel regions unchanged. Adds a ParallelCompoundSC showcase that exercises the Mermaid bug pattern (transition targeting a compound inside a parallel region), with Graphviz vs Mermaid comparison in the visual showcase docs. * test: cover missing branches in sphinx_ext.py and extract.py Add tests for the :name: directive option on Mermaid format (with and without caption). Mark the defensive dedup guard in _format_event_names as pragma: no branch since Events already deduplicates at the container level.
1 parent 19556ce commit 2476d20

20 files changed

+2925
-67
lines changed

README.md

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,17 @@ True
7777

7878
```
7979

80-
Generate a diagram:
80+
Generate a diagram or get a text representation with f-strings:
81+
82+
```py
83+
>>> print(f"{sm:md}")
84+
| State | Event | Guard | Target |
85+
| ------ | ----- | ----- | ------ |
86+
| Green | cycle | | Yellow |
87+
| Yellow | cycle | | Red |
88+
| Red | cycle | | Green |
89+
90+
```
8191

8292
```python
8393
sm._graph().write_png("traffic_light.png")
@@ -341,7 +351,7 @@ There's a lot more to explore:
341351
- **`prepare_event`** callback — inject custom data into all callbacks
342352
- **Observer pattern** — register external listeners to watch events and state changes
343353
- **Django integration** — auto-discover state machines in Django apps with `MachineMixin`
344-
- **Diagram generation**from the CLI, at runtime, or in Jupyter notebooks
354+
- **Diagram generation**via f-strings (`f"{sm:mermaid}"`), CLI, Sphinx directive, or Jupyter
345355
- **Dictionary-based definitions** — create state machines from data structures
346356
- **Internationalization** — error messages in multiple languages
347357

docs/conf.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
"sphinx_gallery.gen_gallery",
5353
"sphinx_copybutton",
5454
"statemachine.contrib.diagram.sphinx_ext",
55+
"sphinxcontrib.mermaid",
5556
]
5657

5758
autosectionlabel_prefix_document = True

0 commit comments

Comments
 (0)