pyfcstm.model.model

Hierarchical state machine model and DSL conversion utilities.

This module provides the core model objects used to represent hierarchical state machines, along with conversion helpers that map between the internal model and the DSL/AST representation. The primary capabilities include:

  • Defining states, transitions, events, and variable definitions.

  • Representing entry, during, exit, and aspect-oriented actions.

  • Parsing a DSL AST into a structured StateMachine.

  • Exporting models to AST nodes and PlantUML diagrams.

The main public components are:

  • Operation - Operation assignments used in actions and transitions.

  • Event - Event definitions scoped to a state path.

  • Transition - Transition definitions with optional guards and effects.

  • OnStage - Entry/during/exit actions for a state.

  • OnAspect - Aspect-oriented during actions.

  • State - Hierarchical state container with actions and transitions.

  • VarDefine - Typed variable definitions.

  • StateMachine - Root container for the full state machine.

  • parse_dsl_node_to_state_machine() - DSL AST parsing utility.

Note

The parsing utilities validate state and variable references. Syntax errors are raised when invalid references or structural inconsistencies are found.

Example:

>>> from pyfcstm.dsl import node as dsl_nodes
>>> from pyfcstm.model.model import parse_dsl_node_to_state_machine
>>> program = dsl_nodes.StateMachineDSLProgram(
...     definitions=[],
...     root_state=dsl_nodes.StateDefinition("root")
... )
>>> sm = parse_dsl_node_to_state_machine(program)
>>> sm.root_state.name
'root'

__all__

pyfcstm.model.model.__all__ = ['OperationStatement', 'Operation', 'IfBlockBranch', 'IfBlock', 'Event', 'Transition', 'OnStage', 'OnAspect', 'State', 'VarDefine', 'StateMachine', 'parse_dsl_node_to_state_machine']

Built-in mutable sequence.

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

OperationStatement

class pyfcstm.model.model.OperationStatement[source]

Abstract base class for executable statements inside operation blocks.

Operation statements may be plain assignments or nested control-flow structures such as if blocks.

Return type:

OperationStatement

Operation

class pyfcstm.model.model.Operation(var_name: str, expr: Expr)[source]

Represents an operation that assigns a value to a variable.

An operation consists of a variable name and an expression that will be assigned to the variable when the operation is executed.

Parameters:
  • var_name (str) – The name of the variable to assign to

  • expr (Expr) – The expression to evaluate and assign to the variable

Example:

>>> op = Operation(var_name="counter", expr=some_expr)
>>> op.var_name
'counter'
to_ast_node() OperationAssignment[source]

Convert this operation to an AST node.

Returns:

An operation assignment AST node

Return type:

dsl_nodes.OperationAssignment

var_name_to_ast_node() Name[source]

Convert the variable name to an AST node.

Returns:

A name AST node

Return type:

dsl_nodes.Name

IfBlockBranch

class pyfcstm.model.model.IfBlockBranch(condition: Expr | None, statements: List[OperationStatement])[source]

Represents a single branch inside a model-layer if block.

Parameters:
  • condition (Optional[Expr]) – Branch condition, or None for the final else branch

  • statements (List[OperationStatement]) – Statements executed when the branch is selected

to_ast_node() OperationIfBranch[source]

Convert this branch back to a DSL AST node.

Returns:

Operation-if branch AST node

Return type:

dsl_nodes.OperationIfBranch

IfBlock

class pyfcstm.model.model.IfBlock(branches: List[IfBlockBranch])[source]

Represents an if / else if / else statement in a model operation block.

Parameters:

branches (List[IfBlockBranch]) – Ordered branch list

to_ast_node() OperationIf[source]

Convert this if-block back to a DSL AST node.

Returns:

Operation-if AST node

Return type:

dsl_nodes.OperationIf

Event

class pyfcstm.model.model.Event(name: str, state_path: Tuple[str, ...], extra_name: str | None = None)[source]

Represents an event that can trigger state transitions.

An event has a name and is associated with a specific state path in the state machine hierarchy.

Parameters:
  • name (str) – The name of the event

  • state_path (Tuple[str, ...]) – The path to the state that owns this event

  • extra_name (Optional[str]) – Optional extra name for display purposes

Example:

>>> event = Event(name="button_pressed", state_path=("root", "idle"))
>>> event.path
('root', 'idle', 'button_pressed')
property path: Tuple[str, ...]

Get the full path of the event including the state path and event name.

Returns:

The full path to the event

Return type:

Tuple[str, …]

property path_name: str

Get the canonical dot-separated path string for this event.

The returned string serves as the stable identifier used by the runtime for event indexing and transition matching. This format matches the fully-qualified event paths used in the DSL.

Event paths follow the state hierarchy where the event is defined. For example, a local event Go defined in state System.Active would have the path System.Active.Go.

Returns:

Dot-separated event path matching the DSL structure

Return type:

str

Example:

>>> event = Event(name="Start", state_path=("System", "Idle"))
>>> event.path_name
'System.Idle.Start'

Note

This property is used internally by SimulationRuntime when building the event dictionary for transition matching. The returned string must be stable and unique within the state machine.

to_ast_node() EventDefinition[source]

Convert this event to an AST node.

Returns:

An event definition AST node

Return type:

dsl_nodes.EventDefinition

Transition

class pyfcstm.model.model.Transition(from_state: str | _StateSingletonMark, to_state: str | _StateSingletonMark, event: Event | None, guard: Expr | None, effects: List[OperationStatement], parent_ref: ReferenceType | None = None)[source]

Represents a transition between states in a state machine.

A transition defines how the state machine moves from one state to another, potentially triggered by an event, guarded by a condition, and with effects that execute when the transition occurs.

Parameters:
  • from_state (Union[str, dsl_nodes._StateSingletonMark]) – The source state name or special state marker

  • to_state (Union[str, dsl_nodes._StateSingletonMark]) – The target state name or special state marker

  • event (Optional[Event]) – The event that triggers this transition, if any

  • guard (Optional[Expr]) – The condition that must be true for the transition to occur, if any

  • effects (List[OperationStatement]) – Operation statements to execute when the transition occurs

  • parent_ref (Optional[weakref.ReferenceType]) – Weak reference to the parent state

Example:

>>> transition = Transition(
...     from_state="idle",
...     to_state="active",
...     event=None,
...     guard=None,
...     effects=[]
... )
property parent: State | None

Get the parent state of this transition.

Returns:

The parent state or None if no parent is set

Return type:

Optional[‘State’]

property parent: State | None

Get the parent state of this transition.

Returns:

The parent state or None if no parent is set

Return type:

Optional[‘State’]

to_ast_node() TransitionDefinition[source]

Convert this transition to an AST node.

Returns:

A transition definition AST node

Return type:

dsl_nodes.TransitionDefinition

OnStage

class pyfcstm.model.model.OnStage(stage: str, aspect: str | None, name: str | None, doc: str | None, operations: List[OperationStatement], is_abstract: bool, state_path: Tuple[str | None, ...], ref: OnStage | OnAspect | None = None, ref_state_path: Tuple[str, ...] | None = None, parent_ref: ReferenceType | None = None)[source]

Represents an action that occurs during a specific stage of a state’s lifecycle.

OnStage can represent enter, during, or exit actions, and can be either concrete operations or abstract function declarations.

Parameters:
  • stage (str) – The lifecycle stage (‘enter’, ‘during’, or ‘exit’)

  • aspect (Optional[str]) – For ‘during’ actions in composite states, specifies if the action occurs ‘before’ or ‘after’ substates

  • name (Optional[str]) – For abstract functions, the name of the function

  • doc (Optional[str]) – For abstract functions, the documentation string

  • operations (List[OperationStatement]) – For concrete actions, the list of operation statements to execute

  • is_abstract (bool) – Whether this is an abstract function declaration

  • state_path (Tuple[Optional[str], ...]) – The path to the state that owns this action

  • ref (Union['OnStage', 'OnAspect', None]) – Reference to another OnStage or OnAspect for function references

  • ref_state_path (Optional[Tuple[str, ...]]) – The path to the referenced state for function references

  • parent_ref (Optional[weakref.ReferenceType]) – Weak reference to the parent state

Example:

>>> on_enter = OnStage(
...     stage="enter",
...     aspect=None,
...     name="init_counter",
...     doc=None,
...     operations=[],
...     is_abstract=False,
...     state_path=("root", "init_counter")
... )
property func_name: str

Get the readable dot-separated path string for this action.

The returned string represents the action’s location in the state hierarchy, making it easy to identify which state owns the action in log messages and diagnostic output.

Unnamed actions (where the name component is None) are rendered with <unnamed> in the terminal position.

Returns:

Dot-separated action path with state hierarchy

Return type:

str

Example:

>>> # Named enter action
>>> action.func_name
'System.Active.Initialize'
>>> # Unnamed during action
>>> action.func_name
'System.Active.<unnamed>'
property is_aspect: bool

Check if this is an aspect-oriented action.

Returns:

False for OnStage instances (always)

Return type:

bool

property is_ref: bool

Check if this action is a reference to another function.

Returns:

True if this is a reference, False otherwise

Return type:

bool

property parent: State | None

Get the parent state of this action.

Returns:

The parent state or None if no parent is set

Return type:

Optional[‘State’]

property parent: State | None

Get the parent state of this action.

Returns:

The parent state or None if no parent is set

Return type:

Optional[‘State’]

to_ast_node() EnterStatement | DuringStatement | ExitStatement[source]

Convert this OnStage to an appropriate AST node based on the stage.

Returns:

An enter, during, or exit statement AST node

Return type:

Union[dsl_nodes.EnterStatement, dsl_nodes.DuringStatement, dsl_nodes.ExitStatement]

Raises:

ValueError – If the stage is not one of ‘enter’, ‘during’, or ‘exit’

OnAspect

class pyfcstm.model.model.OnAspect(stage: str, aspect: str | None, name: str | None, doc: str | None, operations: List[OperationStatement], is_abstract: bool, state_path: Tuple[str | None, ...], ref: OnStage | OnAspect | None = None, ref_state_path: Tuple[str, ...] | None = None, parent_ref: ReferenceType | None = None)[source]

Represents an aspect-oriented action that occurs during a specific stage of a state’s lifecycle.

OnAspect is specifically used for aspect-oriented programming features in the state machine, allowing actions to be defined that apply across multiple states.

Parameters:
  • stage (str) – The lifecycle stage (currently only supports ‘during’)

  • aspect (Optional[str]) – Specifies if the action occurs ‘before’ or ‘after’ substates

  • name (Optional[str]) – For abstract functions, the name of the function

  • doc (Optional[str]) – For abstract functions, the documentation string

  • operations (List[OperationStatement]) – For concrete actions, the list of operation statements to execute

  • is_abstract (bool) – Whether this is an abstract function declaration

  • state_path (Tuple[Optional[str], ...]) – The path to the state that owns this action

  • ref (Union['OnStage', 'OnAspect', None]) – Reference to another OnStage or OnAspect for function references

  • ref_state_path (Optional[Tuple[str, ...]]) – The path to the referenced state for function references

  • parent_ref (Optional[weakref.ReferenceType]) – Weak reference to the parent state

Example:

>>> aspect = OnAspect(
...     stage="during",
...     aspect="before",
...     name="log_entry",
...     doc=None,
...     operations=[],
...     is_abstract=True,
...     state_path=("root", "log_entry")
... )
property func_name: str

Get the readable dot-separated path string for this action.

The returned string represents the action’s location in the state hierarchy, making it easy to identify which state owns the action in log messages and diagnostic output.

Unnamed actions (where the name component is None) are rendered with <unnamed> in the terminal position.

Returns:

Dot-separated action path with state hierarchy

Return type:

str

Example:

>>> # Named aspect action
>>> action.func_name
'System.PreProcess'
>>> # Unnamed aspect action
>>> action.func_name
'System.<unnamed>'
property is_aspect: bool

Check if this is an aspect-oriented action.

Returns:

True for OnAspect instances (always)

Return type:

bool

property is_ref: bool

Check if this action is a reference to another function.

Returns:

True if this is a reference, False otherwise

Return type:

bool

property parent: State | None

Get the parent state of this aspect action.

Returns:

The parent state or None if no parent is set

Return type:

Optional[‘State’]

property parent: State | None

Get the parent state of this aspect action.

Returns:

The parent state or None if no parent is set

Return type:

Optional[‘State’]

to_ast_node() DuringAspectStatement[source]

Convert this OnAspect to an appropriate AST node based on the stage.

Returns:

A during aspect statement AST node

Return type:

Union[dsl_nodes.DuringAspectStatement]

Raises:

ValueError – If the stage is not ‘during’

State

class pyfcstm.model.model.State(name: str, path: Tuple[str, ...], substates: Dict[str, State], events: Dict[str, Event] | None = None, transitions: List[Transition] | None = None, named_functions: Dict[str, OnStage | OnAspect] | None = None, on_enters: List[OnStage] | None = None, on_durings: List[OnStage] | None = None, on_exits: List[OnStage] | None = None, on_during_aspects: List[OnAspect] | None = None, parent_ref: ReferenceType | None = None, substate_name_to_id: Dict[str, int] | None = None, extra_name: str | None = None, is_pseudo: bool = False)[source]

Represents a state in a hierarchical state machine.

A state can contain substates, transitions between those substates, and actions that execute on enter, during, or exit of the state.

Parameters:
  • name (str) – The name of the state

  • path (Tuple[str, ...]) – The full path to this state in the hierarchy

  • substates (Dict[str, 'State']) – Dictionary mapping substate names to State objects

  • events (Dict[str, Event]) – Dictionary mapping event names to Event objects

  • transitions (List[Transition]) – List of transitions between substates

  • named_functions (Dict[str, Union[OnStage, OnAspect]]) – Dictionary mapping function names to their implementations

  • on_enters (List[OnStage]) – List of actions to execute when entering the state

  • on_durings (List[OnStage]) – List of actions to execute while in the state

  • on_exits (List[OnStage]) – List of actions to execute when exiting the state

  • on_during_aspects (List[OnAspect]) – List of aspect-oriented actions for the during stage

  • parent_ref (Optional[weakref.ReferenceType]) – Weak reference to the parent state

  • substate_name_to_id (Dict[str, int]) – Dictionary mapping substate names to numeric IDs

  • extra_name (Optional[str]) – Optional extra name for display purposes

  • is_pseudo (bool) – Whether this is a pseudo state

Example:

>>> state = State(
...     name="idle",
...     path=("root", "idle"),
...     substates={}
... )
>>> state.is_leaf_state
True
__post_init__() None[source]

Initialize default values for optional fields after instance creation.

property abstract_on_during_aspects: List[OnAspect]

Get all abstract during aspect actions.

Returns:

List of abstract during aspect actions

Return type:

List[OnAspect]

property abstract_on_durings: List[OnStage]

Get all abstract during actions.

Returns:

List of abstract during actions

Return type:

List[OnStage]

property abstract_on_enters: List[OnStage]

Get all abstract enter actions.

Returns:

List of abstract enter actions

Return type:

List[OnStage]

property abstract_on_exits: List[OnStage]

Get all abstract exit actions.

Returns:

List of abstract exit actions

Return type:

List[OnStage]

property init_transitions: List[Transition]

Get all transitions that start from the initial state (INIT_STATE).

Returns:

List of transitions from INIT_STATE

Return type:

List[Transition]

property is_leaf_state: bool

Check if this state is a leaf state (has no substates).

Returns:

True if this is a leaf state, False otherwise

Return type:

bool

property is_root_state: bool

Check if this state is the root state (has no parent).

Returns:

True if this is the root state, False otherwise

Return type:

bool

property is_stoppable: bool

Check if this state is stoppable (is a leaf state and not pseudo).

Returns:

True if this state is stoppable, False otherwise

Return type:

bool

iter_on_during_after_aspect_recursively(is_abstract: bool | None = None, with_ids: bool = False) Iterator[Tuple[int, State, OnAspect | OnStage] | Tuple[State, OnAspect | OnStage]][source]

Recursively iterate through ‘after’ aspect during actions from this state to the root state.

This method traverses the state hierarchy from this state to the root state, yielding all ‘after’ aspect during actions along the way.

Parameters:
  • is_abstract (Optional[bool]) – If provided, filter to only abstract (True) or non-abstract (False) actions

  • with_ids (bool) – Whether to include numeric IDs with the actions

Yield:

Tuples of (state, action) or (id, state, action) if with_ids is True

Return type:

Iterator[Union[Tuple[int, ‘State’, Union[OnAspect, OnStage]], Tuple[‘State’, Union[OnAspect, OnStage]]]]

iter_on_during_aspect_recursively(is_abstract: bool | None = None, with_ids: bool = False) Iterator[Tuple[int, State, OnAspect | OnStage] | Tuple[State, OnAspect | OnStage]][source]

Recursively iterate through all during actions in the proper execution order.

This method yields actions in the following order:

  1. ‘Before’ aspect actions from root state to this state

  2. Regular during actions for this state

  3. ‘After’ aspect actions from this state to root state

Parameters:
  • is_abstract (Optional[bool]) – If provided, filter to only abstract (True) or non-abstract (False) actions

  • with_ids (bool) – Whether to include numeric IDs with the actions

Yield:

Tuples of (state, action) or (id, state, action) if with_ids is True

Return type:

Iterator[Union[Tuple[int, ‘State’, Union[OnAspect, OnStage]], Tuple[‘State’, Union[OnAspect, OnStage]]]]

iter_on_during_before_aspect_recursively(is_abstract: bool | None = None, with_ids: bool = False) Iterator[Tuple[int, State, OnAspect | OnStage] | Tuple[State, OnAspect | OnStage]][source]

Recursively iterate through ‘before’ aspect during actions from parent states to this state.

This method traverses the state hierarchy from the root state to this state, yielding all ‘before’ aspect during actions along the way.

Parameters:
  • is_abstract (Optional[bool]) – If provided, filter to only abstract (True) or non-abstract (False) actions

  • with_ids (bool) – Whether to include numeric IDs with the actions

Yield:

Tuples of (state, action) or (id, state, action) if with_ids is True

Return type:

Iterator[Union[Tuple[int, ‘State’, Union[OnAspect, OnStage]], Tuple[‘State’, Union[OnAspect, OnStage]]]]

list_on_during_aspect_recursively(is_abstract: bool | None = None, with_ids: bool = False) List[Tuple[int, State, OnAspect | OnStage] | Tuple[State, OnAspect | OnStage]][source]

Get a list of all during actions in the proper execution order.

This is a convenience method that collects the results of iter_on_during_aspect_recursively.

Parameters:
  • is_abstract (Optional[bool]) – If provided, filter to only abstract (True) or non-abstract (False) actions

  • with_ids (bool) – Whether to include numeric IDs with the actions

Returns:

List of during actions in execution order

Return type:

List[Union[Tuple[int, ‘State’, Union[OnAspect, OnStage]], Tuple[‘State’, Union[OnAspect, OnStage]]]]

list_on_during_aspects(is_abstract: bool | None = None, aspect: str | None = None, with_ids: bool = False) List[Tuple[int, OnAspect] | OnAspect][source]

Get a list of during aspect actions, optionally filtered by abstract status, aspect, and with IDs.

Parameters:
  • is_abstract (Optional[bool]) – If provided, filter to only abstract (True) or non-abstract (False) actions

  • aspect (Optional[str]) – If provided, filter to only actions with the given aspect (‘before’ or ‘after’)

  • with_ids (bool) – Whether to include numeric IDs with the actions

Returns:

List of during aspect actions, optionally with IDs

Return type:

List[Union[Tuple[int, OnAspect], OnAspect]]

list_on_durings(is_abstract: bool | None = None, aspect: str | None = None, with_ids: bool = False) List[Tuple[int, OnStage] | OnStage][source]

Get a list of during actions, optionally filtered by abstract status, aspect, and with IDs.

Parameters:
  • is_abstract (Optional[bool]) – If provided, filter to only abstract (True) or non-abstract (False) actions

  • aspect (Optional[str]) – If provided, filter to only actions with the given aspect (‘before’ or ‘after’)

  • with_ids (bool) – Whether to include numeric IDs with the actions

Returns:

List of during actions, optionally with IDs

Return type:

List[Union[Tuple[int, OnStage], OnStage]]

list_on_enters(is_abstract: bool | None = None, with_ids: bool = False) List[Tuple[int, OnStage] | OnStage][source]

Get a list of enter actions, optionally filtered by abstract status and with IDs.

Parameters:
  • is_abstract (Optional[bool]) – If provided, filter to only abstract (True) or non-abstract (False) actions

  • with_ids (bool) – Whether to include numeric IDs with the actions

Returns:

List of enter actions, optionally with IDs

Return type:

List[Union[Tuple[int, OnStage], OnStage]]

list_on_exits(is_abstract: bool | None = None, with_ids: bool = False) List[Tuple[int, OnStage] | OnStage][source]

Get a list of exit actions, optionally filtered by abstract status and with IDs.

Parameters:
  • is_abstract (Optional[bool]) – If provided, filter to only abstract (True) or non-abstract (False) actions

  • with_ids (bool) – Whether to include numeric IDs with the actions

Returns:

List of exit actions, optionally with IDs

Return type:

List[Union[Tuple[int, OnStage], OnStage]]

property non_abstract_on_during_aspects: List[OnAspect]

Get all non-abstract during aspect actions.

Returns:

List of non-abstract during aspect actions

Return type:

List[OnAspect]

property non_abstract_on_durings: List[OnStage]

Get all non-abstract during actions.

Returns:

List of non-abstract during actions

Return type:

List[OnStage]

property non_abstract_on_enters: List[OnStage]

Get all non-abstract enter actions.

Returns:

List of non-abstract enter actions

Return type:

List[OnStage]

property non_abstract_on_exits: List[OnStage]

Get all non-abstract exit actions.

Returns:

List of non-abstract exit actions

Return type:

List[OnStage]

property parent: State | None

Get the parent state of this state.

Returns:

The parent state or None if this is the root state

Return type:

Optional[‘State’]

property parent: State | None

Get the parent state of this state.

Returns:

The parent state or None if this is the root state

Return type:

Optional[‘State’]

resolve_event(event_ref: str, *, collect_into: DiagnosticSink | None = None) Event | None[source]

Resolve an event reference string to an existing Event object in the state hierarchy.

This method supports three types of event references:

  1. Relative events (e.g., "xxx.yyy.zzz"): Resolved relative to the current state’s path. If the current state is XXX.YYY, the event resolves to XXX.YYY.xxx.yyy.zzz.

  2. Parent-relative events (e.g., ".xxx.yyy.zzz"): Each leading dot represents moving up one level in the state hierarchy. If the current state is XXX.YYY.ZZZ, then .xxx resolves to XXX.YYY.xxx (up one level), and ..xxx resolves to XXX.xxx (up two levels).

  3. Absolute events (e.g., "/xxx.yyy"): Resolved relative to the root state. If the root state is Root, the event resolves to Root.xxx.yyy.

Parameters:
  • event_ref (str) – The event reference string to resolve

  • collect_into (pyfcstm.diagnostics.DiagnosticSink, optional) –

    Optional structured-diagnostic sink. Behavior depends on which sink mode the caller picked:

    • None (the default) — raise ModelValueError or ModelLookupError immediately on failure. Both multi-inherit ValueError / LookupError for backwards compatibility with existing except ValueError: / except LookupError: callers.

    • DiagnosticSink(collect=True) — record the failure as a pyfcstm.utils.validate.ModelDiagnostic on the sink and return None instead of raising. Lets callers accumulate multiple diagnostics across many invocations in a single pass (IDE / agent loop usage).

    • DiagnosticSink(collect=False) (strict sink) — also raise, but route the diagnostic through the sink first so any previously accumulated entries (e.g. warnings) are carried into the raise. The raise still uses the typed ModelValueError / ModelLookupError subclass, preserving the legacy catch surface.

Returns:

The resolved Event object from the state hierarchy, or None when collect_into is a collect=True sink and resolution failed.

Return type:

Optional[Event]

Raises:
  • pyfcstm.utils.validate.ModelValueError – If the event reference is syntactically invalid (empty, malformed, exceeds root). Multi-inherits ValueError. Raised when collect_into is None or a strict sink.

  • pyfcstm.utils.validate.ModelLookupError – If the event reference parses but the targeted state or event does not exist. Multi-inherits LookupError. Raised when collect_into is None or a strict sink.

Example:

>>> # Assuming current state path is ("Root", "System", "Active")
>>> # and an event "critical" exists in state "Root.System.Active.error"
>>> state.resolve_event("error.critical")
Event(name="critical", state_path=("Root", "System", "Active", "error"))

>>> state.resolve_event(".error.critical")
Event(name="critical", state_path=("Root", "System", "error"))

>>> state.resolve_event("/global.shutdown")
Event(name="shutdown", state_path=("Root", "global"))
to_ast_node() StateDefinition[source]

Convert this state to an AST node.

Returns:

A state definition AST node

Return type:

dsl_nodes.StateDefinition

to_plantuml(options: PlantUMLOptions | Literal['minimal', 'normal', 'full'] | None = None, current_depth: int = 0, event_colors: Dict[str, str] | None = None) str[source]

Convert this state to PlantUML notation.

Parameters:
  • options (PlantUMLOptionsInput) – Configuration input for PlantUML generation

  • current_depth (int) – Current depth in the state hierarchy (for max_depth support)

  • event_colors (Optional[Dict[str, str]]) – Optional mapping of event paths to color codes

Returns:

PlantUML representation of the state

Return type:

str

to_transition_ast_node(transition: Transition) TransitionDefinition[source]

Convert a transition to an AST node in the context of this state.

Parameters:

transition (Transition) – The transition to convert

Returns:

A transition definition AST node

Return type:

dsl_nodes.TransitionDefinition

classmethod transition_to_ast_node(self: State | None, transition: Transition) TransitionDefinition[source]

Convert a transition to an AST node, considering the context of its parent state.

Parameters:
  • self (Optional['State']) – The parent state, or None

  • transition (Transition) – The transition to convert

Returns:

A transition definition AST node

Return type:

dsl_nodes.TransitionDefinition

property transitions_entering_children: List[Transition]

Get all transitions that start from the initial state (INIT_STATE).

These are the transitions that define the initial substate when entering this state.

Returns:

List of transitions from INIT_STATE

Return type:

List[Transition]

property transitions_entering_children_simplified: List[Transition | None]

Get a simplified list of transitions entering child states.

If there’s a default transition (no event or guard), only include that one. Otherwise include all transitions and add None at the end.

Returns:

List of transitions, possibly with None at the end

Return type:

List[Optional[Transition]]

property transitions_from: List[Transition]

Get all transitions that start from this state.

For non-root states, these are transitions in the parent state where this state is the source. For the root state, a synthetic transition to EXIT_STATE is returned.

Returns:

List of transitions from this state

Return type:

List[Transition]

property transitions_to: List[Transition]

Get all transitions that end at this state.

For non-root states, these are transitions in the parent state where this state is the target. For the root state, a synthetic transition from INIT_STATE is returned.

Returns:

List of transitions to this state

Return type:

List[Transition]

walk_states() Iterator[State][source]

Iterate through this state and all its substates recursively.

Yield:

Each state in the hierarchy, starting with this one

Return type:

Iterator[‘State’]

VarDefine

class pyfcstm.model.model.VarDefine(name: str, type: str, init: Expr)[source]

Represents a variable definition in a state machine.

Parameters:
  • name (str) – The name of the variable

  • type (str) – The type of the variable

  • init (Expr) – The initial value expression

Example:

>>> var_def = VarDefine(name="counter", type="int", init=some_expr)
>>> var_def.name
'counter'
name_ast_node() Name[source]

Convert the variable name to an AST node.

Returns:

A name AST node

Return type:

dsl_nodes.Name

to_ast_node() DefAssignment[source]

Convert this variable definition to an AST node.

Returns:

A definition assignment AST node

Return type:

dsl_nodes.DefAssignment

StateMachine

class pyfcstm.model.model.StateMachine(defines: Dict[str, VarDefine], root_state: State)[source]

Represents a complete state machine with variable definitions and a root state.

Parameters:
  • defines (Dict[str, VarDefine]) – Dictionary mapping variable names to their definitions

  • root_state (State) – The root state of the state machine

Example:

>>> sm = StateMachine(defines={}, root_state=some_state)
>>> list(sm.walk_states())  # Get all states in the machine
[...]
resolve_event(event_path: str, *, collect_into: DiagnosticSink | None = None) Event | None[source]

Resolve a full event path to an existing Event object in the state machine.

This method requires a complete event path in the format State1.State2.State3.event_name, where the path must include all states from the root to the event location. Unlike State.resolve_event(), this method does not support relative, parent-relative, or absolute path notations (no leading dots or slashes).

Parameters:
  • event_path (str) – The complete event path (e.g., "Root.System.Active.error")

  • collect_into (pyfcstm.diagnostics.DiagnosticSink, optional) –

    Optional structured-diagnostic sink. Behavior depends on the sink mode (see State.resolve_event() for the full matrix):

    • None — raise ModelValueError / ModelLookupError immediately.

    • DiagnosticSink(collect=True) — accumulate on the sink and return None.

    • DiagnosticSink(collect=False) (strict) — also raise the typed subclass, but route through the sink first so any previously accumulated entries are preserved into the raise.

Returns:

The resolved Event object, or None when collect_into is a collect=True sink and resolution failed.

Return type:

Optional[Event]

Raises:

Example:

>>> # Assuming a state machine with Root -> System -> Active -> error event
>>> sm = StateMachine(defines={}, root_state=root_state)
>>> event = sm.resolve_event("Root.System.Active.error")
>>> event.name
'error'
to_ast_node() StateMachineDSLProgram[source]

Convert this state machine to an AST node.

Returns:

A state machine DSL program AST node

Return type:

dsl_nodes.StateMachineDSLProgram

to_plantuml(options: PlantUMLOptions | Literal['minimal', 'normal', 'full'] | None = None) str[source]

Convert this state machine to PlantUML notation.

Parameters:

options (PlantUMLOptionsInput) – Configuration input for PlantUML generation

Returns:

PlantUML representation of the state machine

Return type:

str

walk_states() Iterator[State][source]

Iterate through all states in the state machine.

Yield:

Each state in the hierarchy

Return type:

Iterator[State]

parse_dsl_node_to_state_machine

pyfcstm.model.model.parse_dsl_node_to_state_machine(dnode: StateMachineDSLProgram, path: str | None = None, *, collect: bool = False) StateMachine | Tuple[StateMachine | None, List[ModelDiagnostic]][source]

Parse a state machine DSL program AST node into a StateMachine object.

This function validates the state machine structure and builds a complete StateMachine object with all states, transitions, events, and variable definitions.

The implementation routes every semantic error through a pyfcstm.diagnostics.DiagnosticSink. In the default strict mode (collect=False), the first error raises pyfcstm.utils.validate.ModelValidationError carrying a pyfcstm.utils.validate.ModelDiagnostic list. In collect mode (collect=True), all detected errors are accumulated and returned alongside the partially-built model (which may be None if construction could not progress past a fatal point).

The ModelValidationError exception multi-inherits from SyntaxError, so callers using except SyntaxError: continue to work after this refactor.

Parameters:
  • dnode (dsl_nodes.StateMachineDSLProgram) – The state machine DSL program AST node to parse

  • path (Optional[str]) – Optional path contract reserved for import-aware assembly. When provided, the value defines the current DSL location for import resolution. When omitted, the current working directory is used. Existing directories are treated as import base directories directly, while file paths use their parent directory as the import base.

  • collect (bool) – When True, return (model_or_None, diagnostics) instead of raising on the first error. Defaults to False.

Returns:

The parsed state machine, or a (model, diagnostics) tuple when collect=True.

Return type:

Union[StateMachine, Tuple[Optional[StateMachine], List[ModelDiagnostic]]]

Raises:

pyfcstm.utils.validate.ModelValidationError – When collect=False and the DSL contains a semantic error. Multi-inherits from SyntaxError for backwards compatibility.

Example:

>>> # Assuming you have a parsed DSL node
>>> state_machine = parse_dsl_node_to_state_machine(
...     dsl_program_node,
...     path="root.fcstm",
... )
>>> state_machine.root_state.name
'root'