$ pip install machinist
Machinist's automatic structured logging depends on eliot. Logging is declared as a Machinist extra so you can automatically install this dependency:
$ pip install machinist[logging]
Inputs, outputs, and states are all twisted.python.constants.NamedConstant
.
Collections of inputs, outputs, and states are twisted.python.constants.Names
.
class TurnstileInput(Names):
FARE_PAID = NamedConstant()
ARM_UNLOCKED = NamedConstant()
ARM_TURNED = NamedConstant()
ARM_LOCKED = NamedConstant()
class TurnstileOutput(Names):
ENGAGE_LOCK = NamedConstant()
DISENGAGE_LOCK = NamedConstant()
class TurnstileState(Names):
LOCKED = NamedConstant()
UNLOCKED = NamedConstant()
ACTIVE = NamedConstant()
A transition is defined as an input to a state mapped to a series of outputs and the next state.
These transitions are added to a transition table.
table = TransitionTable()
# Any number of things like this
table = table.addTransitions(
TurnstileState.UNLOCKED, {
TurnstileInput.ARM_TURNED:
([TurnstileOutput.ENGAGE_LOCK], TurnstileState.ACTIVE),
})
If an input is received for a particular state for which it is not defined, an machinist.IllegalInput
would be raised.
In the example above, if FARE_PAID
is received as an input while the turnstile is in the UNLOCKED
state, machinist.IllegalInput
will be raised.
To build an instance of a finite state machine from the transition, pass the inputs, outputs, states, and table (previously defined) to the function machinist.constructFiniteStateMachine
.
turnstileFSM = constructFiniteStateMachine(
inputs=TurnstileInput,
outputs=TurnstileOutput,
states=TurnstileState,
table=table,
initial=TurnstileState.LOCKED,
richInputs=[]
inputContext={},
world=MethodSuffixOutputer(Turnstile(hardware)),
)
Note that richInputs
must be passed and it must be a list of IRichInput
providers mapped to the same input symbols (parameter inputs
) the FSM is created with.
Turnstile
is a class with methods named output_XXX
, where XXX
is one of the outputs.
There should be one such method for each output defined.
To provide an input to the FSM, receive
on the FSM must be called with an instance of an IRichInput
provider.
turnstileFSM.receive(TurnstileInput.FARE_PAID)
For the rest of the example code, see doc/turnstile.py.
For more discussion of the benefits of using finite state machines, see: