Skip to content

ScatterHQ/machinist

Folders and files

NameName
Last commit message
Last commit date

Latest commit

1d1c017 · Jan 27, 2015
Jun 12, 2014
Jan 26, 2015
May 22, 2014
May 22, 2014
Jan 23, 2015
Apr 14, 2014
May 22, 2014
Jan 23, 2015
Jan 27, 2015
May 22, 2014

Repository files navigation

https://travis-ci.org/ClusterHQ/machinist.png https://coveralls.io/repos/hybridcluster/machinist/badge.png

Installation

$ 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]

Defining Inputs, Outputs, and States

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()

Defining the Transitions

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.

Putting together the Finite State Machine

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.

Transitioning the Finite State Machine

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)

Further Reading

For the rest of the example code, see doc/turnstile.py.

For more discussion of the benefits of using finite state machines, see: