pyfcstm.model.plantuml

PlantUML generation configuration and options.

This module provides configuration classes for controlling PlantUML diagram generation from state machine models. The main class PlantUMLOptions allows fine-grained control over what elements are displayed in the generated diagrams.

The configuration system uses a hierarchical fallback mechanism:

  1. User-specified values (non-None)

  2. Parent configuration values (e.g., show_lifecycle_actions)

  3. detail_level preset values

  4. Final fallback defaults

The main public components are:

Example:

>>> from pyfcstm.model.plantuml import PlantUMLOptions
>>> options = PlantUMLOptions(
...     detail_level='normal',
...     show_lifecycle_actions=True,
... )
>>> config = options.to_config()
>>> config.show_enter_actions  # True (inherited from show_lifecycle_actions)

__all__

pyfcstm.model.plantuml.__all__ = ['DetailLevelLiteral', 'PlantUMLOptionsInput', 'PlantUMLOptions', 'format_state_name', 'format_event_name', 'escape_plantuml_table_cell', 'should_show_action', 'format_action_text', 'collect_event_transitions', 'assign_event_colors']

Built-in mutable sequence.

If no argument is given, the constructor creates a new empty list. The argument must be an iterable if specified.

DetailLevelLiteral

pyfcstm.model.plantuml.DetailLevelLiteral

alias of Literal[‘minimal’, ‘normal’, ‘full’]

PlantUMLOptionsInput

pyfcstm.model.plantuml.PlantUMLOptionsInput

alias of PlantUMLOptions | Literal[‘minimal’, ‘normal’, ‘full’] | None

PlantUMLOptions

class pyfcstm.model.plantuml.PlantUMLOptions(detail_level: Literal['minimal', 'normal', 'full'] = 'normal', show_variable_definitions: bool | None = None, variable_display_mode: Literal['note', 'legend', 'hide'] = 'legend', variable_legend_position: Literal['top left', 'top center', 'top right', 'bottom left', 'bottom center', 'bottom right', 'left', 'right', 'center'] = 'top left', state_name_format: Tuple[Literal['name', 'extra_name', 'path'], ...] = ('extra_name',), show_pseudo_state_style: bool | None = None, collapse_empty_states: bool = False, show_lifecycle_actions: bool | None = None, show_enter_actions: bool | None = None, show_during_actions: bool | None = None, show_exit_actions: bool | None = None, show_aspect_actions: bool | None = None, show_abstract_actions: bool | None = None, show_concrete_actions: bool | None = None, abstract_action_marker: Literal['text', 'symbol', 'none'] = 'text', max_action_lines: int | None = None, show_transition_guards: bool | None = None, show_transition_effects: bool | None = None, transition_effect_mode: Literal['note', 'inline', 'hide'] = 'note', show_events: bool | None = None, event_name_format: Tuple[Literal['name', 'extra_name', 'path', 'relpath'], ...] = ('extra_name', 'relpath'), event_visualization_mode: Literal['none', 'color', 'legend', 'both', 'dependency_view'] = 'none', event_legend_position: Literal['top left', 'top center', 'top right', 'bottom left', 'bottom center', 'bottom right', 'left', 'right', 'center'] = 'right', max_depth: int | None = None, collapsed_state_marker: str = '...', use_skinparam: bool = True, use_stereotypes: bool = True, custom_colors: dict | None = None)[source]

Configuration options for PlantUML diagram generation.

This class provides fine-grained control over what elements are displayed in generated PlantUML diagrams. It supports two usage modes:

  1. Quick mode: Use detail_level presets ('minimal', 'normal', 'full')

  2. Fine-grained mode: Configure individual options explicitly

Configuration Inheritance

The configuration system uses a hierarchical fallback mechanism:

  1. User-specified values (non-None parameters)

  2. Parent configuration values (e.g., show_lifecycle_actions controls child options)

  3. detail_level preset values

  4. Final fallback defaults

Inheritance relationships:

  • show_enter_actions, show_during_actions, show_exit_actions, show_aspect_actions inherit from show_lifecycle_actions

  • show_abstract_actions, show_concrete_actions inherit from show_lifecycle_actions

  • show_transition_guards, show_transition_effects are independently configurable

Detail Level Presets

minimal: Clean diagrams focusing on structure

  • Shows: variable definitions (legend), transition guards, transition effects, events

  • Hides: lifecycle actions, pseudo state styling

normal (default): Balanced view for typical use cases

  • Shows: variable definitions (legend), transition guards, transition effects, events, pseudo state styling

  • Hides: lifecycle actions

full: Complete information for detailed analysis

  • Shows: everything including variable definitions (legend) and lifecycle actions

Parameters

detail_levelDetailLevelLiteral, default=’normal’

Preset detail level. One of 'minimal', 'normal', or 'full'.

Example:

>>> PlantUMLOptions(detail_level='minimal')  # Clean structure view
>>> PlantUMLOptions(detail_level='full')     # Show all details
show_variable_definitionsOptional[bool], default=None

Whether to display variable definitions in the diagram.

  • True: Show variable definitions as note or legend

  • False: Hide variable definitions

  • None: Use detail_level preset (True for all levels)

Example:

>>> # Show variables in a note block
>>> PlantUMLOptions(show_variable_definitions=True, variable_display_mode='note')
>>> # Output: note as DefinitionNote
>>> #         defines {
>>> #             def int counter = 0;
>>> #         }
>>> #         end note
variable_display_modeLiteral[‘note’, ‘legend’, ‘hide’], default=’legend’

How to display variable definitions when show_variable_definitions=True.

  • 'note': Display as a floating note block

  • 'legend': Display as a legend table (more compact)

  • 'hide': Don’t display (same as show_variable_definitions=False)

Example:

>>> # Legend format (compact table)
>>> PlantUMLOptions(show_variable_definitions=True, variable_display_mode='legend')
>>> # Output: legend top left
>>> #         |= Variable |= Type |= Initial Value |
>>> #         | counter | int | 0 |
>>> #         endlegend
variable_legend_positionLiteral[‘top left’, ‘top center’, ‘top right’, ‘bottom left’, ‘bottom center’, ‘bottom right’, ‘left’, ‘right’, ‘center’], default=’top left’

Position of the variable legend when variable_display_mode='legend'.

  • 'top left': Legend at top-left corner (default)

  • 'top center': Legend at top-center

  • 'top right': Legend at top-right corner

  • 'bottom left': Legend at bottom-left corner

  • 'bottom center': Legend at bottom-center

  • 'bottom right': Legend at bottom-right corner

  • 'left': Legend on the left side

  • 'right': Legend on the right side

  • 'center': Legend in the center

Example:

>>> # Place legend at top-left (default)
>>> PlantUMLOptions(variable_display_mode='legend', variable_legend_position='top left')
>>> # Output: legend top left
>>> #         |= Variable |= Type |= Initial Value |
>>> #         endlegend

>>> # Place legend at bottom-right
>>> PlantUMLOptions(variable_display_mode='legend', variable_legend_position='bottom right')
>>> # Output: legend bottom right
>>> #         |= Variable |= Type |= Initial Value |
>>> #         endlegend
state_name_formatTuple[Literal[‘name’, ‘extra_name’, ‘path’], …], default=(‘extra_name’,)

Tuple of display elements for state names. Elements are combined with the first as the main display and others in parentheses.

  • 'name': State identifier (e.g., 'Running')

  • 'extra_name': Localized/display name (e.g., '运行中')

  • 'path': Full hierarchical path (e.g., 'System.Module.Running')

Example:

>>> # Show only extra_name (default)
>>> PlantUMLOptions(state_name_format=('extra_name',))
>>> # Output: state "运行中" as running

>>> # Show extra_name with name in parentheses
>>> PlantUMLOptions(state_name_format=('extra_name', 'name'))
>>> # Output: state "运行中 (Running)" as running

>>> # Show name with full path
>>> PlantUMLOptions(state_name_format=('name', 'path'))
>>> # Output: state "Running (System.Module.Running)" as system__module__running
show_pseudo_state_styleOptional[bool], default=None

Whether to apply visual styling to pseudo states (dotted border).

  • True: Pseudo states shown with #line.dotted style

  • False: Pseudo states shown without special styling

  • None: Use detail_level preset (False for minimal, True for normal/full)

Example:

>>> PlantUMLOptions(show_pseudo_state_style=True)
>>> # Output: state "PseudoState" as pseudo_state <<pseudo>> #line.dotted
collapse_empty_statesbool, default=False

Whether to hide action text for states with no lifecycle actions.

  • True: Empty states don’t show action text (cleaner diagrams)

  • False: All states show their structure

Example:

>>> # With collapse_empty_states=True, empty states are more compact
>>> PlantUMLOptions(collapse_empty_states=True)
>>> # State with no actions: state "EmptyState" as empty_state
>>> # (no "EmptyState :" line)
show_lifecycle_actionsOptional[bool], default=None

Master switch for all lifecycle actions (enter/during/exit/aspect).

  • True: Show all lifecycle actions (unless overridden by specific options)

  • False: Hide all lifecycle actions

  • None: Use detail_level preset (False for minimal/normal, True for full)

This option controls the default for show_enter_actions, show_during_actions, show_exit_actions, show_aspect_actions, show_abstract_actions, and show_concrete_actions.

Example:

>>> # Show all lifecycle actions
>>> PlantUMLOptions(show_lifecycle_actions=True)
>>> # Output: state "Active" as active
>>> #         active : enter {\n    counter = 0;\n}\nduring {\n    counter++;\n}
show_enter_actionsOptional[bool], default=None

Whether to show enter actions. Inherits from show_lifecycle_actions if None.

Example:

>>> # Show only enter actions, hide others
>>> PlantUMLOptions(show_lifecycle_actions=False, show_enter_actions=True)
show_during_actionsOptional[bool], default=None

Whether to show during actions. Inherits from show_lifecycle_actions if None.

show_exit_actionsOptional[bool], default=None

Whether to show exit actions. Inherits from show_lifecycle_actions if None.

show_aspect_actionsOptional[bool], default=None

Whether to show aspect actions (>> during before/after). Inherits from show_lifecycle_actions if None.

Example:

>>> # Show aspect actions for cross-cutting concerns
>>> PlantUMLOptions(show_lifecycle_actions=True, show_aspect_actions=True)
>>> # Output: state : >> during before abstract GlobalMonitor;
show_abstract_actionsOptional[bool], default=None

Whether to show abstract actions (actions without implementation). Inherits from show_lifecycle_actions if None.

Example:

>>> # Show only abstract actions (API surface)
>>> PlantUMLOptions(show_lifecycle_actions=True,
...                 show_abstract_actions=True,
...                 show_concrete_actions=False)
>>> # Output: state : enter abstract InitHardware;
show_concrete_actionsOptional[bool], default=None

Whether to show concrete actions (actions with implementation). Inherits from show_lifecycle_actions if None.

Example:

>>> # Show only concrete actions (implementation details)
>>> PlantUMLOptions(show_lifecycle_actions=True,
...                 show_abstract_actions=False,
...                 show_concrete_actions=True)
>>> # Output: state : enter {\n    counter = 0;\n}
abstract_action_markerLiteral[‘text’, ‘symbol’, ‘none’], default=’text’

How to mark abstract actions when displayed.

  • 'text': Use abstract keyword (e.g., enter abstract Init)

  • 'symbol': Use guillemet markers (e.g., enter «abstract» Init)

  • 'none': No marker (e.g., enter Init)

Example:

>>> PlantUMLOptions(show_lifecycle_actions=True, abstract_action_marker='symbol')
>>> # Output: state : enter «abstract» InitHardware;
max_action_linesOptional[int], default=None

Maximum number of lines to display per action. Lines beyond this limit are truncated with ... ellipsis.

  • None: No limit (show all lines)

  • > 0: Limit to specified number of lines

Example:

>>> # Limit actions to 3 lines for compact diagrams
>>> PlantUMLOptions(show_lifecycle_actions=True, max_action_lines=3)
>>> # Output: state : enter {\n    a = 1;\n    b = 2;\n...
show_transition_guardsOptional[bool], default=None

Whether to show guard conditions on transitions.

  • True: Show guard conditions (e.g., StateA -> StateB : [counter > 10])

  • False: Hide guard conditions

  • None: Use detail_level preset (True for all levels)

Example:

>>> PlantUMLOptions(show_transition_guards=True)
>>> # Output: idle --> active : [temperature > 25]
show_transition_effectsOptional[bool], default=None

Whether to show transition effects (operations executed during transition).

  • True: Show effects according to transition_effect_mode

  • False: Hide effects

  • None: Use detail_level preset (True for all levels)

Example:

>>> PlantUMLOptions(show_transition_effects=True, transition_effect_mode='inline')
>>> # Output: idle --> active : Start / counter = 0
transition_effect_modeLiteral[‘note’, ‘inline’, ‘hide’], default=’note’

How to display transition effects when show_transition_effects=True.

  • 'note': Display as note on link (detailed, multi-line)

  • 'inline': Display inline with / separator (compact, single-line)

  • 'hide': Don’t display (same as show_transition_effects=False)

Example:

>>> # Note format (detailed)
>>> PlantUMLOptions(show_transition_effects=True, transition_effect_mode='note')
>>> # Output: idle --> active : Start
>>> #         note on link
>>> #         effect {
>>> #             counter = 0;
>>> #         }
>>> #         end note

>>> # Inline format (compact)
>>> PlantUMLOptions(show_transition_effects=True, transition_effect_mode='inline')
>>> # Output: idle --> active : Start / counter = 0
show_eventsOptional[bool], default=None

Whether to show event names on transitions.

  • True: Show event names

  • False: Hide event names (show only guards/effects)

  • None: Use detail_level preset (True for all levels)

event_name_formatTuple[Literal[‘name’, ‘extra_name’, ‘path’, ‘relpath’], …], default=(‘extra_name’, ‘relpath’)

Tuple of display elements for event names.

  • 'name': Event identifier (e.g., 'Start')

  • 'extra_name': Localized/display name (e.g., '启动')

  • 'path': Absolute path (e.g., '/System.Start')

  • 'relpath': Relative path from transition source (e.g., 'State.Start')

Example:

>>> # Show extra_name with relative path
>>> PlantUMLOptions(event_name_format=('extra_name', 'relpath'))
>>> # Output: idle --> active : 启动 (State.Start)

>>> # Show only name
>>> PlantUMLOptions(event_name_format=('name',))
>>> # Output: idle --> active : Start
event_visualization_modeLiteral[‘none’, ‘color’, ‘legend’, ‘both’, ‘dependency_view’], default=’none’

How to visualize events in the diagram.

  • 'none': No special visualization

  • 'color': Apply colors to transitions by event (colorblind-friendly palette)

  • 'legend': Show event legend with transition counts

  • 'both': Apply colors and show legend

  • 'dependency_view': Reserved for future use

Example:

>>> # Color-code transitions by event
>>> PlantUMLOptions(event_visualization_mode='color')
>>> # Output: idle --> active : Start #4E79A7

>>> # Show event legend
>>> PlantUMLOptions(event_visualization_mode='legend')
>>> # Output: legend right
>>> #         Event Scoping
>>> #         * Start: 3 transitions
>>> #         endlegend
event_legend_positionLiteral[‘top left’, ‘top center’, ‘top right’, ‘bottom left’, ‘bottom center’, ‘bottom right’, ‘left’, ‘right’, ‘center’], default=’right’

Position of the event legend when event_visualization_mode is 'legend' or 'both'.

  • 'top left': Legend at top-left corner

  • 'top center': Legend at top-center

  • 'top right': Legend at top-right corner

  • 'bottom left': Legend at bottom-left corner

  • 'bottom center': Legend at bottom-center

  • 'bottom right': Legend at bottom-right corner

  • 'left': Legend on the left side

  • 'right': Legend on the right side (default)

  • 'center': Legend in the center

Example:

>>> # Place event legend on the right (default)
>>> PlantUMLOptions(event_visualization_mode='legend', event_legend_position='right')

>>> # Place event legend at bottom-right
>>> PlantUMLOptions(event_visualization_mode='legend', event_legend_position='bottom right')
max_depthOptional[int], default=None

Maximum depth to expand in state hierarchy. States beyond this depth are collapsed and shown with collapsed_state_marker.

  • None: Expand all levels (no limit)

  • 0: Show only root state

  • > 0: Expand to specified depth

Example:

>>> # Show only 2 levels deep
>>> PlantUMLOptions(max_depth=2, collapsed_state_marker='[...]')
>>> # Output: state "Level1" as level1 {
>>> #             state "Level2" as level1__level2 {
>>> #                 state "[...]" as level1__level2___collapsed_
>>> #             }
>>> #         }
collapsed_state_markerstr, default=’…’

Text marker to display for collapsed states when max_depth is exceeded.

Example:

>>> PlantUMLOptions(max_depth=1, collapsed_state_marker='[more states...]')
>>> # Output: state "[more states...]" as parent___collapsed_
use_skinparambool, default=True

Whether to include skinparam styling block for pseudo and composite states.

  • True: Include skinparam block with predefined colors

  • False: No skinparam block (use PlantUML defaults)

Example:

>>> PlantUMLOptions(use_skinparam=True)
>>> # Output: skinparam state {
>>> #           BackgroundColor<<pseudo>> LightGray
>>> #           BackgroundColor<<composite>> LightBlue
>>> #           BorderColor<<pseudo>> Gray
>>> #           FontStyle<<pseudo>> italic
>>> #         }
use_stereotypesbool, default=True

Whether to add stereotype markers (<<pseudo>>, <<composite>>) to states.

  • True: Add stereotypes for pseudo and composite states

  • False: No stereotypes

Example:

>>> PlantUMLOptions(use_stereotypes=True)
>>> # Output: state "Parent" as parent <<composite>> {
>>> #             state "Child" as parent__child
>>> #         }
custom_colorsOptional[Dict[str, str]], default=None

Custom color mapping for events. Keys are event paths (e.g., 'Root.Start'), values are hex color codes (e.g., '#FF0000').

Only used when event_visualization_mode is 'color' or 'both'.

Example:

>>> PlantUMLOptions(
...     event_visualization_mode='color',
...     custom_colors={'Root.Start': '#FF0000', 'Root.Stop': '#00FF00'}
... )
>>> # Output: idle --> active : Start #FF0000
>>> #         active --> idle : Stop #00FF00

Examples

Quick mode with presets:

>>> # Minimal diagram for presentations
>>> options = PlantUMLOptions(detail_level='minimal')
>>> sm.to_plantuml(options)

>>> # Full details for documentation
>>> options = PlantUMLOptions(detail_level='full')
>>> sm.to_plantuml(options)

Fine-grained control:

>>> # Show only abstract actions (API surface)
>>> options = PlantUMLOptions(
...     show_lifecycle_actions=True,
...     show_abstract_actions=True,
...     show_concrete_actions=False,
...     abstract_action_marker='symbol'
... )

>>> # Compact diagram with depth limit
>>> options = PlantUMLOptions(
...     max_depth=2,
...     collapsed_state_marker='[...]',
...     collapse_empty_states=True
... )

>>> # Event-focused view with colors
>>> options = PlantUMLOptions(
...     event_visualization_mode='both',
...     event_name_format=('extra_name', 'name'),
...     custom_colors={'Root.Start': '#00FF00'}
... )

Combining options:

>>> # Custom configuration inheriting from 'normal'
>>> options = PlantUMLOptions(
...     detail_level='normal',
...     show_lifecycle_actions=True,  # Override preset
...     show_enter_actions=True,      # Show only enter actions
...     show_during_actions=False,
...     show_exit_actions=False,
...     max_action_lines=5            # Limit verbosity
... )

See Also

format_state_name : Format state names according to configuration format_event_name : Format event names according to configuration

__post_init__()[source]

Validate configuration after initialization.

Raises:

ValueError – If name format tuples are empty

classmethod from_value(value: PlantUMLOptions | Literal['minimal', 'normal', 'full'] | None) PlantUMLOptions[source]

Normalize user-provided PlantUML option input to a PlantUMLOptions instance.

Parameters:

value (PlantUMLOptionsInput) – Input configuration value. Accepts an existing options object, detail-level string, or None.

Returns:

Normalized PlantUML options object

Return type:

PlantUMLOptions

Raises:

TypeError – If value is not supported

to_config() PlantUMLOptions[source]

Export resolved configuration with all Optional fields resolved.

This method resolves all Optional[bool] fields according to the inheritance hierarchy and detail_level presets, returning a new PlantUMLOptions instance where all fields have definite values (no None).

Resolution priority (highest to lowest):

  1. User-specified values (non-None)

  2. Parent configuration values (e.g., show_lifecycle_actions)

  3. detail_level preset values

  4. Final fallback defaults

Returns:

New PlantUMLOptions with all Optional fields resolved

Return type:

PlantUMLOptions

Example:

>>> options = PlantUMLOptions(
...     detail_level='normal',
...     show_lifecycle_actions=True,
...     show_enter_actions=None,
... )
>>> config = options.to_config()
>>> config.show_lifecycle_actions  # True
>>> config.show_enter_actions  # True (inherited)
>>> config.show_during_actions  # True (inherited)

format_state_name

pyfcstm.model.plantuml.format_state_name(state: State, name_format: Tuple[Literal['name', 'extra_name', 'path'], ...]) str[source]

Format state name according to the specified format tuple.

Parameters:
  • state (State) – State object to format

  • name_format (Tuple[Literal['name', 'extra_name', 'path'], ...]) – Tuple of display elements

Returns:

Formatted state name

Return type:

str

Example:

>>> format_state_name(state, ('extra_name', 'name'))
'系统运行中 (Running)'

format_event_name

pyfcstm.model.plantuml.format_event_name(event: Event, name_format: Tuple[Literal['name', 'extra_name', 'path', 'relpath'], ...], trans_node: object | None = None) str[source]

Format event name according to the specified format tuple.

Parameters:
  • event (Event) – Event object to format

  • name_format (Tuple[Literal['name', 'extra_name', 'path', 'relpath'], ...]) – Tuple of display elements

  • trans_node (Optional[object]) – Optional transition AST node for relpath computation

Returns:

Formatted event name

Return type:

str

Example:

>>> format_event_name(event, ('extra_name', 'name'))
'启动模块 (Start)'
>>> format_event_name(event, ('extra_name', 'relpath'), trans_node)
'启动模块 (State.Start)'

escape_plantuml_table_cell

pyfcstm.model.plantuml.escape_plantuml_table_cell(text: str) str[source]

Escape special characters in PlantUML table cells.

PlantUML uses pipe (|) as table cell delimiter, so any pipe characters in cell content must be escaped to prevent breaking the table structure.

Parameters:

text (str) – Text to escape

Returns:

Escaped text safe for use in PlantUML table cells

Return type:

str

Example:

>>> escape_plantuml_table_cell("2 | 5")
'2 \| 5'
>>> escape_plantuml_table_cell("normal text")
'normal text'

should_show_action

pyfcstm.model.plantuml.should_show_action(action: OnStage | OnAspect, config: PlantUMLOptions) bool[source]

Determine if an action should be shown based on abstract/concrete filtering.

Parameters:
Returns:

True if the action should be shown, False otherwise

Return type:

bool

Example:

>>> # For an abstract action
>>> should_show_action(action, config)
True

format_action_text

pyfcstm.model.plantuml.format_action_text(action: OnStage | OnAspect, config: PlantUMLOptions) str[source]

Format action text with abstract marker and line limit.

Parameters:
Returns:

Formatted action text

Return type:

str

Example:

>>> format_action_text(action, config)
'enter abstract InitHardware'

collect_event_transitions

pyfcstm.model.plantuml.collect_event_transitions(state_machine: StateMachine) Dict[str, List[Tuple[State, Transition]]][source]

Collect all events and their associated transitions from a state machine.

Parameters:

state_machine (StateMachine) – The state machine to analyze

Returns:

Dictionary mapping event paths to list of (state, transition) tuples

Return type:

Dict[str, List[Tuple[State, Transition]]]

Example:

>>> event_map = collect_event_transitions(sm)
>>> event_map['System.ErrorEvent']
[(state1, trans1), (state2, trans2)]

assign_event_colors

pyfcstm.model.plantuml.assign_event_colors(event_map: Dict[str, List], custom_colors: dict | None = None) Dict[str, str][source]

Assign colors to events for visualization.

Only assigns colors to events that appear 2 or more times. Events that appear only once will not be assigned a color (use default transition color).

Parameters:
  • event_map (Dict[str, List]) – Dictionary mapping event paths to transitions

  • custom_colors (Optional[dict]) – Optional custom color mapping

Returns:

Dictionary mapping event paths to color codes

Return type:

Dict[str, str]

Example:

>>> colors = assign_event_colors(event_map)
>>> colors['System.ErrorEvent']  # Only if ErrorEvent appears >= 2 times
'#FF6B6B'