plexus.cli.procedure.state_machine module

Procedure State Machine

Defines the state machine for Procedure workflow using python-statemachine library. This provides clean, validated state transitions and prevents invalid state changes.

class plexus.cli.procedure.state_machine.ProcedureStateMachine(procedure_id: str, current_state: str | None = None, client=None)

Bases: StateMachine

State machine for Procedure workflow.

States:
  • start: Initial state when procedure is created

  • evaluation: Running initial evaluation to gather metrics

  • hypothesis: Analyzing evaluation results and generating hypotheses

  • test: Testing hypothesis by generating and evaluating score version

  • insights: Analyzing test results and generating insights

  • completed: All work finished successfully

  • error: Procedure encountered an error

Transitions:
  • begin: start → evaluation (start initial evaluation)

  • analyze: evaluation → hypothesis (begin hypothesis generation)

  • start_testing: hypothesis → test (begin testing hypothesis)

  • analyze_results: test → insights (analyze test results)

  • continue_iteration: insights → hypothesis (loop back for next round)

  • finish_from_insights: insights → completed (insights complete, no more iterations)

  • finish_from_hypothesis: hypothesis → completed (decided no testing needed)

  • fail_*: any state → error (error occurred)

  • retry_from_error: error → evaluation (retry after error)

  • restart_from_error: error → start (full restart after error)

Initialize state machine for a procedure.

Args:

procedure_id: The procedure ID current_state: The current state (if resuming), or None for new procedure client: Optional PlexusDashboardClient for updating TaskStages

__init__(procedure_id: str, current_state: str | None = None, client=None)

Initialize state machine for a procedure.

Args:

procedure_id: The procedure ID current_state: The current state (if resuming), or None for new procedure client: Optional PlexusDashboardClient for updating TaskStages

analyze

An event is triggers a signal that something has happened.

They are send to a state machine and allow the state machine to react.

An event starts a Transition, which can be thought of as a “cause” that initiates a change in the state of the system.

See also events.

analyze_results

An event is triggers a signal that something has happened.

They are send to a state machine and allow the state machine to react.

An event starts a Transition, which can be thought of as a “cause” that initiates a change in the state of the system.

See also events.

begin

An event is triggers a signal that something has happened.

They are send to a state machine and allow the state machine to react.

An event starts a Transition, which can be thought of as a “cause” that initiates a change in the state of the system.

See also events.

completed

A State in a StateMachine describes a particular behavior of the machine. When we say that a machine is “in” a state, it means that the machine behaves in the way that state describes.

Args:
name: A human-readable representation of the state. Default is derived

from the name of the variable assigned to the state machine class. The name is derived from the id using this logic:

name = id.replace("_", " ").capitalize()
value: A specific value to the storage and retrieval of states.

If specified, you can use It to map a more friendly representation to a low-level value.

initial: Set True if the State is the initial one. There must be one and only

one initial state in a statemachine. Defaults to False.

final: Set True if represents a final state. A machine can have

optionally many final states. Final states have no transition starting from It. Defaults to False.

enter: One or more callbacks assigned to be executed when the state is entered.

See actions.

exit: One or more callbacks assigned to be executed when the state is exited.

See actions.

State is a core component on how this library implements an expressive API to declare StateMachines.

>>> from statemachine import State

Given a few states…

>>> draft = State("Draft", initial=True)
>>> producing = State("Producing")
>>> closed = State('Closed', final=True)

Transitions are declared using the State.to() or State.from_() (reversed) methods.

>>> draft.to(producing)
TransitionList([Transition(State('Draft', ...

The result is a TransitionList. Don’t worry about this internal class. But the good thing is that it implements the OR operator to combine transitions, so you can use the | syntax to compound a list of transitions and assign to the same event.

You can declare all transitions for a state in one single line …

>>> transitions = draft.to(draft) | producing.to(closed)

… and you can append additional transitions for a state to previous definitions.

>>> transitions |= closed.to(draft)
>>> [(t.source.name, t.target.name) for t in transitions]
[('Draft', 'Draft'), ('Producing', 'Closed'), ('Closed', 'Draft')]

There are handy shortcuts that you can use to express this same set of transitions.

The first one, draft.to(draft), is also called a self-transition, and can be expressed using an alternative syntax:

>>> draft.to.itself()
TransitionList([Transition(State('Draft', ...

You can even pass a list of target states to declare at once all transitions starting from the same state.

>>> transitions = draft.to(draft, producing, closed)
>>> [(t.source.name, t.target.name) for t in transitions]
[('Draft', 'Draft'), ('Draft', 'Producing'), ('Draft', 'Closed')]

Sometimes it’s easier to use the State.from_() method:

>>> transitions = closed.from_(draft, producing, closed)
>>> [(t.source.name, t.target.name) for t in transitions]
[('Draft', 'Closed'), ('Producing', 'Closed'), ('Closed', 'Closed')]
continue_iteration

An event is triggers a signal that something has happened.

They are send to a state machine and allow the state machine to react.

An event starts a Transition, which can be thought of as a “cause” that initiates a change in the state of the system.

See also events.

error

A State in a StateMachine describes a particular behavior of the machine. When we say that a machine is “in” a state, it means that the machine behaves in the way that state describes.

Args:
name: A human-readable representation of the state. Default is derived

from the name of the variable assigned to the state machine class. The name is derived from the id using this logic:

name = id.replace("_", " ").capitalize()
value: A specific value to the storage and retrieval of states.

If specified, you can use It to map a more friendly representation to a low-level value.

initial: Set True if the State is the initial one. There must be one and only

one initial state in a statemachine. Defaults to False.

final: Set True if represents a final state. A machine can have

optionally many final states. Final states have no transition starting from It. Defaults to False.

enter: One or more callbacks assigned to be executed when the state is entered.

See actions.

exit: One or more callbacks assigned to be executed when the state is exited.

See actions.

State is a core component on how this library implements an expressive API to declare StateMachines.

>>> from statemachine import State

Given a few states…

>>> draft = State("Draft", initial=True)
>>> producing = State("Producing")
>>> closed = State('Closed', final=True)

Transitions are declared using the State.to() or State.from_() (reversed) methods.

>>> draft.to(producing)
TransitionList([Transition(State('Draft', ...

The result is a TransitionList. Don’t worry about this internal class. But the good thing is that it implements the OR operator to combine transitions, so you can use the | syntax to compound a list of transitions and assign to the same event.

You can declare all transitions for a state in one single line …

>>> transitions = draft.to(draft) | producing.to(closed)

… and you can append additional transitions for a state to previous definitions.

>>> transitions |= closed.to(draft)
>>> [(t.source.name, t.target.name) for t in transitions]
[('Draft', 'Draft'), ('Producing', 'Closed'), ('Closed', 'Draft')]

There are handy shortcuts that you can use to express this same set of transitions.

The first one, draft.to(draft), is also called a self-transition, and can be expressed using an alternative syntax:

>>> draft.to.itself()
TransitionList([Transition(State('Draft', ...

You can even pass a list of target states to declare at once all transitions starting from the same state.

>>> transitions = draft.to(draft, producing, closed)
>>> [(t.source.name, t.target.name) for t in transitions]
[('Draft', 'Draft'), ('Draft', 'Producing'), ('Draft', 'Closed')]

Sometimes it’s easier to use the State.from_() method:

>>> transitions = closed.from_(draft, producing, closed)
>>> [(t.source.name, t.target.name) for t in transitions]
[('Draft', 'Closed'), ('Producing', 'Closed'), ('Closed', 'Closed')]
evaluation

A State in a StateMachine describes a particular behavior of the machine. When we say that a machine is “in” a state, it means that the machine behaves in the way that state describes.

Args:
name: A human-readable representation of the state. Default is derived

from the name of the variable assigned to the state machine class. The name is derived from the id using this logic:

name = id.replace("_", " ").capitalize()
value: A specific value to the storage and retrieval of states.

If specified, you can use It to map a more friendly representation to a low-level value.

initial: Set True if the State is the initial one. There must be one and only

one initial state in a statemachine. Defaults to False.

final: Set True if represents a final state. A machine can have

optionally many final states. Final states have no transition starting from It. Defaults to False.

enter: One or more callbacks assigned to be executed when the state is entered.

See actions.

exit: One or more callbacks assigned to be executed when the state is exited.

See actions.

State is a core component on how this library implements an expressive API to declare StateMachines.

>>> from statemachine import State

Given a few states…

>>> draft = State("Draft", initial=True)
>>> producing = State("Producing")
>>> closed = State('Closed', final=True)

Transitions are declared using the State.to() or State.from_() (reversed) methods.

>>> draft.to(producing)
TransitionList([Transition(State('Draft', ...

The result is a TransitionList. Don’t worry about this internal class. But the good thing is that it implements the OR operator to combine transitions, so you can use the | syntax to compound a list of transitions and assign to the same event.

You can declare all transitions for a state in one single line …

>>> transitions = draft.to(draft) | producing.to(closed)

… and you can append additional transitions for a state to previous definitions.

>>> transitions |= closed.to(draft)
>>> [(t.source.name, t.target.name) for t in transitions]
[('Draft', 'Draft'), ('Producing', 'Closed'), ('Closed', 'Draft')]

There are handy shortcuts that you can use to express this same set of transitions.

The first one, draft.to(draft), is also called a self-transition, and can be expressed using an alternative syntax:

>>> draft.to.itself()
TransitionList([Transition(State('Draft', ...

You can even pass a list of target states to declare at once all transitions starting from the same state.

>>> transitions = draft.to(draft, producing, closed)
>>> [(t.source.name, t.target.name) for t in transitions]
[('Draft', 'Draft'), ('Draft', 'Producing'), ('Draft', 'Closed')]

Sometimes it’s easier to use the State.from_() method:

>>> transitions = closed.from_(draft, producing, closed)
>>> [(t.source.name, t.target.name) for t in transitions]
[('Draft', 'Closed'), ('Producing', 'Closed'), ('Closed', 'Closed')]
fail_from_evaluation

An event is triggers a signal that something has happened.

They are send to a state machine and allow the state machine to react.

An event starts a Transition, which can be thought of as a “cause” that initiates a change in the state of the system.

See also events.

fail_from_hypothesis

An event is triggers a signal that something has happened.

They are send to a state machine and allow the state machine to react.

An event starts a Transition, which can be thought of as a “cause” that initiates a change in the state of the system.

See also events.

fail_from_insights

An event is triggers a signal that something has happened.

They are send to a state machine and allow the state machine to react.

An event starts a Transition, which can be thought of as a “cause” that initiates a change in the state of the system.

See also events.

fail_from_start

An event is triggers a signal that something has happened.

They are send to a state machine and allow the state machine to react.

An event starts a Transition, which can be thought of as a “cause” that initiates a change in the state of the system.

See also events.

fail_from_test

An event is triggers a signal that something has happened.

They are send to a state machine and allow the state machine to react.

An event starts a Transition, which can be thought of as a “cause” that initiates a change in the state of the system.

See also events.

final_states = [State('Completed', id='completed', value='completed', initial=False, final=True)]
finish_from_hypothesis

An event is triggers a signal that something has happened.

They are send to a state machine and allow the state machine to react.

An event starts a Transition, which can be thought of as a “cause” that initiates a change in the state of the system.

See also events.

finish_from_insights

An event is triggers a signal that something has happened.

They are send to a state machine and allow the state machine to react.

An event starts a Transition, which can be thought of as a “cause” that initiates a change in the state of the system.

See also events.

hypothesis

A State in a StateMachine describes a particular behavior of the machine. When we say that a machine is “in” a state, it means that the machine behaves in the way that state describes.

Args:
name: A human-readable representation of the state. Default is derived

from the name of the variable assigned to the state machine class. The name is derived from the id using this logic:

name = id.replace("_", " ").capitalize()
value: A specific value to the storage and retrieval of states.

If specified, you can use It to map a more friendly representation to a low-level value.

initial: Set True if the State is the initial one. There must be one and only

one initial state in a statemachine. Defaults to False.

final: Set True if represents a final state. A machine can have

optionally many final states. Final states have no transition starting from It. Defaults to False.

enter: One or more callbacks assigned to be executed when the state is entered.

See actions.

exit: One or more callbacks assigned to be executed when the state is exited.

See actions.

State is a core component on how this library implements an expressive API to declare StateMachines.

>>> from statemachine import State

Given a few states…

>>> draft = State("Draft", initial=True)
>>> producing = State("Producing")
>>> closed = State('Closed', final=True)

Transitions are declared using the State.to() or State.from_() (reversed) methods.

>>> draft.to(producing)
TransitionList([Transition(State('Draft', ...

The result is a TransitionList. Don’t worry about this internal class. But the good thing is that it implements the OR operator to combine transitions, so you can use the | syntax to compound a list of transitions and assign to the same event.

You can declare all transitions for a state in one single line …

>>> transitions = draft.to(draft) | producing.to(closed)

… and you can append additional transitions for a state to previous definitions.

>>> transitions |= closed.to(draft)
>>> [(t.source.name, t.target.name) for t in transitions]
[('Draft', 'Draft'), ('Producing', 'Closed'), ('Closed', 'Draft')]

There are handy shortcuts that you can use to express this same set of transitions.

The first one, draft.to(draft), is also called a self-transition, and can be expressed using an alternative syntax:

>>> draft.to.itself()
TransitionList([Transition(State('Draft', ...

You can even pass a list of target states to declare at once all transitions starting from the same state.

>>> transitions = draft.to(draft, producing, closed)
>>> [(t.source.name, t.target.name) for t in transitions]
[('Draft', 'Draft'), ('Draft', 'Producing'), ('Draft', 'Closed')]

Sometimes it’s easier to use the State.from_() method:

>>> transitions = closed.from_(draft, producing, closed)
>>> [(t.source.name, t.target.name) for t in transitions]
[('Draft', 'Closed'), ('Producing', 'Closed'), ('Closed', 'Closed')]
initial_state

A State in a StateMachine describes a particular behavior of the machine. When we say that a machine is “in” a state, it means that the machine behaves in the way that state describes.

Args:
name: A human-readable representation of the state. Default is derived

from the name of the variable assigned to the state machine class. The name is derived from the id using this logic:

name = id.replace("_", " ").capitalize()
value: A specific value to the storage and retrieval of states.

If specified, you can use It to map a more friendly representation to a low-level value.

initial: Set True if the State is the initial one. There must be one and only

one initial state in a statemachine. Defaults to False.

final: Set True if represents a final state. A machine can have

optionally many final states. Final states have no transition starting from It. Defaults to False.

enter: One or more callbacks assigned to be executed when the state is entered.

See actions.

exit: One or more callbacks assigned to be executed when the state is exited.

See actions.

State is a core component on how this library implements an expressive API to declare StateMachines.

>>> from statemachine import State

Given a few states…

>>> draft = State("Draft", initial=True)
>>> producing = State("Producing")
>>> closed = State('Closed', final=True)

Transitions are declared using the State.to() or State.from_() (reversed) methods.

>>> draft.to(producing)
TransitionList([Transition(State('Draft', ...

The result is a TransitionList. Don’t worry about this internal class. But the good thing is that it implements the OR operator to combine transitions, so you can use the | syntax to compound a list of transitions and assign to the same event.

You can declare all transitions for a state in one single line …

>>> transitions = draft.to(draft) | producing.to(closed)

… and you can append additional transitions for a state to previous definitions.

>>> transitions |= closed.to(draft)
>>> [(t.source.name, t.target.name) for t in transitions]
[('Draft', 'Draft'), ('Producing', 'Closed'), ('Closed', 'Draft')]

There are handy shortcuts that you can use to express this same set of transitions.

The first one, draft.to(draft), is also called a self-transition, and can be expressed using an alternative syntax:

>>> draft.to.itself()
TransitionList([Transition(State('Draft', ...

You can even pass a list of target states to declare at once all transitions starting from the same state.

>>> transitions = draft.to(draft, producing, closed)
>>> [(t.source.name, t.target.name) for t in transitions]
[('Draft', 'Draft'), ('Draft', 'Producing'), ('Draft', 'Closed')]

Sometimes it’s easier to use the State.from_() method:

>>> transitions = closed.from_(draft, producing, closed)
>>> [(t.source.name, t.target.name) for t in transitions]
[('Draft', 'Closed'), ('Producing', 'Closed'), ('Closed', 'Closed')]
insights

A State in a StateMachine describes a particular behavior of the machine. When we say that a machine is “in” a state, it means that the machine behaves in the way that state describes.

Args:
name: A human-readable representation of the state. Default is derived

from the name of the variable assigned to the state machine class. The name is derived from the id using this logic:

name = id.replace("_", " ").capitalize()
value: A specific value to the storage and retrieval of states.

If specified, you can use It to map a more friendly representation to a low-level value.

initial: Set True if the State is the initial one. There must be one and only

one initial state in a statemachine. Defaults to False.

final: Set True if represents a final state. A machine can have

optionally many final states. Final states have no transition starting from It. Defaults to False.

enter: One or more callbacks assigned to be executed when the state is entered.

See actions.

exit: One or more callbacks assigned to be executed when the state is exited.

See actions.

State is a core component on how this library implements an expressive API to declare StateMachines.

>>> from statemachine import State

Given a few states…

>>> draft = State("Draft", initial=True)
>>> producing = State("Producing")
>>> closed = State('Closed', final=True)

Transitions are declared using the State.to() or State.from_() (reversed) methods.

>>> draft.to(producing)
TransitionList([Transition(State('Draft', ...

The result is a TransitionList. Don’t worry about this internal class. But the good thing is that it implements the OR operator to combine transitions, so you can use the | syntax to compound a list of transitions and assign to the same event.

You can declare all transitions for a state in one single line …

>>> transitions = draft.to(draft) | producing.to(closed)

… and you can append additional transitions for a state to previous definitions.

>>> transitions |= closed.to(draft)
>>> [(t.source.name, t.target.name) for t in transitions]
[('Draft', 'Draft'), ('Producing', 'Closed'), ('Closed', 'Draft')]

There are handy shortcuts that you can use to express this same set of transitions.

The first one, draft.to(draft), is also called a self-transition, and can be expressed using an alternative syntax:

>>> draft.to.itself()
TransitionList([Transition(State('Draft', ...

You can even pass a list of target states to declare at once all transitions starting from the same state.

>>> transitions = draft.to(draft, producing, closed)
>>> [(t.source.name, t.target.name) for t in transitions]
[('Draft', 'Draft'), ('Draft', 'Producing'), ('Draft', 'Closed')]

Sometimes it’s easier to use the State.from_() method:

>>> transitions = closed.from_(draft, producing, closed)
>>> [(t.source.name, t.target.name) for t in transitions]
[('Draft', 'Closed'), ('Producing', 'Closed'), ('Closed', 'Closed')]
name = 'ProcedureStateMachine'
on_analyze()

Called when transitioning evaluation → hypothesis

on_analyze_results()

Called when transitioning test → insights

on_begin()

Called when transitioning start → evaluation

on_continue_iteration()

Called when transitioning insights → hypothesis (looping back for next round)

on_enter_error()

Called when entering error state

on_finish_from_hypothesis()

Called when transitioning hypothesis → completed

on_finish_from_insights()

Called when transitioning insights → completed

on_restart_from_error()

Called when transitioning error → start

on_retry_from_error()

Called when transitioning error → evaluation

on_start_testing()

Called when transitioning hypothesis → test

restart_from_error

An event is triggers a signal that something has happened.

They are send to a state machine and allow the state machine to react.

An event starts a Transition, which can be thought of as a “cause” that initiates a change in the state of the system.

See also events.

retry_from_error

An event is triggers a signal that something has happened.

They are send to a state machine and allow the state machine to react.

An event starts a Transition, which can be thought of as a “cause” that initiates a change in the state of the system.

See also events.

start

A State in a StateMachine describes a particular behavior of the machine. When we say that a machine is “in” a state, it means that the machine behaves in the way that state describes.

Args:
name: A human-readable representation of the state. Default is derived

from the name of the variable assigned to the state machine class. The name is derived from the id using this logic:

name = id.replace("_", " ").capitalize()
value: A specific value to the storage and retrieval of states.

If specified, you can use It to map a more friendly representation to a low-level value.

initial: Set True if the State is the initial one. There must be one and only

one initial state in a statemachine. Defaults to False.

final: Set True if represents a final state. A machine can have

optionally many final states. Final states have no transition starting from It. Defaults to False.

enter: One or more callbacks assigned to be executed when the state is entered.

See actions.

exit: One or more callbacks assigned to be executed when the state is exited.

See actions.

State is a core component on how this library implements an expressive API to declare StateMachines.

>>> from statemachine import State

Given a few states…

>>> draft = State("Draft", initial=True)
>>> producing = State("Producing")
>>> closed = State('Closed', final=True)

Transitions are declared using the State.to() or State.from_() (reversed) methods.

>>> draft.to(producing)
TransitionList([Transition(State('Draft', ...

The result is a TransitionList. Don’t worry about this internal class. But the good thing is that it implements the OR operator to combine transitions, so you can use the | syntax to compound a list of transitions and assign to the same event.

You can declare all transitions for a state in one single line …

>>> transitions = draft.to(draft) | producing.to(closed)

… and you can append additional transitions for a state to previous definitions.

>>> transitions |= closed.to(draft)
>>> [(t.source.name, t.target.name) for t in transitions]
[('Draft', 'Draft'), ('Producing', 'Closed'), ('Closed', 'Draft')]

There are handy shortcuts that you can use to express this same set of transitions.

The first one, draft.to(draft), is also called a self-transition, and can be expressed using an alternative syntax:

>>> draft.to.itself()
TransitionList([Transition(State('Draft', ...

You can even pass a list of target states to declare at once all transitions starting from the same state.

>>> transitions = draft.to(draft, producing, closed)
>>> [(t.source.name, t.target.name) for t in transitions]
[('Draft', 'Draft'), ('Draft', 'Producing'), ('Draft', 'Closed')]

Sometimes it’s easier to use the State.from_() method:

>>> transitions = closed.from_(draft, producing, closed)
>>> [(t.source.name, t.target.name) for t in transitions]
[('Draft', 'Closed'), ('Producing', 'Closed'), ('Closed', 'Closed')]
start_testing

An event is triggers a signal that something has happened.

They are send to a state machine and allow the state machine to react.

An event starts a Transition, which can be thought of as a “cause” that initiates a change in the state of the system.

See also events.

property state_value: str

Get the current state value as a string

states = [State('Start', id='start', value='start', initial=True, final=False), State('Evaluation', id='evaluation', value='evaluation', initial=False, final=False), State('Hypothesis', id='hypothesis', value='hypothesis', initial=False, final=False), State('Test', id='test', value='test', initial=False, final=False), State('Insights', id='insights', value='insights', initial=False, final=False), State('Completed', id='completed', value='completed', initial=False, final=True), State('Error', id='error', value='error', initial=False, final=False)]
states_map = {'completed': State('Completed', id='completed', value='completed', initial=False, final=True), 'error': State('Error', id='error', value='error', initial=False, final=False), 'evaluation': State('Evaluation', id='evaluation', value='evaluation', initial=False, final=False), 'hypothesis': State('Hypothesis', id='hypothesis', value='hypothesis', initial=False, final=False), 'insights': State('Insights', id='insights', value='insights', initial=False, final=False), 'start': State('Start', id='start', value='start', initial=True, final=False), 'test': State('Test', id='test', value='test', initial=False, final=False)}
test

A State in a StateMachine describes a particular behavior of the machine. When we say that a machine is “in” a state, it means that the machine behaves in the way that state describes.

Args:
name: A human-readable representation of the state. Default is derived

from the name of the variable assigned to the state machine class. The name is derived from the id using this logic:

name = id.replace("_", " ").capitalize()
value: A specific value to the storage and retrieval of states.

If specified, you can use It to map a more friendly representation to a low-level value.

initial: Set True if the State is the initial one. There must be one and only

one initial state in a statemachine. Defaults to False.

final: Set True if represents a final state. A machine can have

optionally many final states. Final states have no transition starting from It. Defaults to False.

enter: One or more callbacks assigned to be executed when the state is entered.

See actions.

exit: One or more callbacks assigned to be executed when the state is exited.

See actions.

State is a core component on how this library implements an expressive API to declare StateMachines.

>>> from statemachine import State

Given a few states…

>>> draft = State("Draft", initial=True)
>>> producing = State("Producing")
>>> closed = State('Closed', final=True)

Transitions are declared using the State.to() or State.from_() (reversed) methods.

>>> draft.to(producing)
TransitionList([Transition(State('Draft', ...

The result is a TransitionList. Don’t worry about this internal class. But the good thing is that it implements the OR operator to combine transitions, so you can use the | syntax to compound a list of transitions and assign to the same event.

You can declare all transitions for a state in one single line …

>>> transitions = draft.to(draft) | producing.to(closed)

… and you can append additional transitions for a state to previous definitions.

>>> transitions |= closed.to(draft)
>>> [(t.source.name, t.target.name) for t in transitions]
[('Draft', 'Draft'), ('Producing', 'Closed'), ('Closed', 'Draft')]

There are handy shortcuts that you can use to express this same set of transitions.

The first one, draft.to(draft), is also called a self-transition, and can be expressed using an alternative syntax:

>>> draft.to.itself()
TransitionList([Transition(State('Draft', ...

You can even pass a list of target states to declare at once all transitions starting from the same state.

>>> transitions = draft.to(draft, producing, closed)
>>> [(t.source.name, t.target.name) for t in transitions]
[('Draft', 'Draft'), ('Draft', 'Producing'), ('Draft', 'Closed')]

Sometimes it’s easier to use the State.from_() method:

>>> transitions = closed.from_(draft, producing, closed)
>>> [(t.source.name, t.target.name) for t in transitions]
[('Draft', 'Closed'), ('Producing', 'Closed'), ('Closed', 'Closed')]
plexus.cli.procedure.state_machine.create_state_machine(procedure_id: str, current_state: str | None = None, client=None) ProcedureStateMachine

Create a state machine for a procedure.

Args:

procedure_id: The procedure ID current_state: The current state (if resuming), or None for new procedure client: Optional PlexusDashboardClient for TaskStage updates

Returns:

ProcedureStateMachine instance

plexus.cli.procedure.state_machine.get_valid_transitions(current_state: str | None) list[str]

Get list of valid transitions from a given state.

Args:

current_state: The current state value

Returns:

List of valid next state values

plexus.cli.procedure.state_machine.is_valid_transition(from_state: str | None, to_state: str) bool

Check if a state transition is valid.

Args:

from_state: The current state (or None for initial state) to_state: The target state

Returns:

True if transition is valid, False otherwise