direct.fsm.FSM

from direct.fsm.FSM import FSM, Transition

The new Finite State Machine module. This replaces the module previously called FSM (now called ClassicFSM).

For more information on FSMs, consult the Finite State Machines section of the programming manual.

Inheritance diagram

digraph inheritancea721bc6e02 { bgcolor=transparent; rankdir=BT; size="8.0, 12.0"; "AlreadyInTransition" [URL="direct.fsm.FSM.html#direct.fsm.FSM.AlreadyInTransition",fillcolor=white,fontname="Vera Sans, DejaVu Sans, Liberation Sans, Arial, Helvetica, sans",fontsize=11,height=0.25,shape=box,style="",target="_top"]; "FSMException" -> "AlreadyInTransition" [arrowsize=0.75,style=""]; "DirectObject" [URL="direct.showbase.DirectObject.html#direct.showbase.DirectObject.DirectObject",fillcolor=white,fontname="Vera Sans, DejaVu Sans, Liberation Sans, Arial, Helvetica, sans",fontsize=11,height=0.25,shape=box,style="",target="_top",tooltip="This is the class that all Direct/SAL classes should inherit from"]; "FSM" [URL="direct.fsm.FSM.html#direct.fsm.FSM.FSM",fillcolor=white,fontname="Vera Sans, DejaVu Sans, Liberation Sans, Arial, Helvetica, sans",fontsize=11,height=0.25,shape=box,style="",target="_top",tooltip="A Finite State Machine. This is intended to be the base class"]; "DirectObject" -> "FSM" [arrowsize=0.75,style=""]; "FSMException" [URL="direct.fsm.FSM.html#direct.fsm.FSM.FSMException",fillcolor=white,fontname="Vera Sans, DejaVu Sans, Liberation Sans, Arial, Helvetica, sans",fontsize=11,height=0.25,shape=box,style="",target="_top"]; "RequestDenied" [URL="direct.fsm.FSM.html#direct.fsm.FSM.RequestDenied",fillcolor=white,fontname="Vera Sans, DejaVu Sans, Liberation Sans, Arial, Helvetica, sans",fontsize=11,height=0.25,shape=box,style="",target="_top"]; "FSMException" -> "RequestDenied" [arrowsize=0.75,style=""]; "Transition" [URL="direct.fsm.FSM.html#direct.fsm.FSM.Transition",fillcolor=white,fontname="Vera Sans, DejaVu Sans, Liberation Sans, Arial, Helvetica, sans",fontsize=11,height=0.25,shape=box,style="",target="_top",tooltip="Used for the return value of fsm.request(). Behaves like a tuple, for"]; }
exception AlreadyInTransition[source]

Bases: FSMException

class FSM(name)[source]

Bases: DirectObject

A Finite State Machine. This is intended to be the base class of any number of specific machines, which consist of a collection of states and transitions, and rules to switch between states according to arbitrary input data.

The states of an FSM are defined implicitly. Each state is identified by a string, which by convention begins with a capital letter. (Also by convention, strings passed to request that are not state names should begin with a lowercase letter.)

To define specialized behavior when entering or exiting a particular state, define a method named enterState() and/or exitState(), where “State” is the name of the state, e.g.:

def enterRed(self):
    ... do stuff ...

def exitRed(self):
    ... cleanup stuff ...

def enterYellow(self):
    ... do stuff ...

def exitYellow(self):
    ... cleanup stuff ...

def enterGreen(self):
    ... do stuff ...

def exitGreen(self):
    ... cleanup stuff ...

Both functions can access the previous state name as self.oldState, and the new state name we are transitioning to as self.newState. (Of course, in enterRed(), self.newState will always be “Red”, and the in exitRed(), self.oldState will always be “Red”.)

Both functions are optional. If either function is omitted, the state is still defined, but nothing is done when transitioning into (or out of) the state.

Additionally, you may define a filterState() function for each state. The purpose of this function is to decide what state to transition to next, if any, on receipt of a particular input. The input is always a string and a tuple of optional parameters (which is often empty), and the return value should either be None to do nothing, or the name of the state to transition into. For example:

def filterRed(self, request, args):
    if request in ['Green']:
        return (request,) + args
    return None

def filterYellow(self, request, args):
    if request in ['Red']:
        return (request,) + args
    return None

def filterGreen(self, request, args):
    if request in ['Yellow']:
        return (request,) + args
    return None

As above, the filterState() functions are optional. If any is omitted, the defaultFilter() method is called instead. A standard implementation of defaultFilter() is provided, which may be overridden in a derived class to change the behavior on an unexpected transition.

If self.defaultTransitions is left unassigned, then the standard implementation of defaultFilter() will return None for any lowercase transition name and allow any uppercase transition name (this assumes that an uppercase name is a request to go directly to a particular state by name).

self.state may be queried at any time other than during the handling of the enter() and exit() functions. During these functions, self.state contains the value None (you are not really in any state during the transition). However, during a transition you can query the outgoing and incoming states, respectively, via self.oldState and self.newState. At other times, self.state contains the name of the current state.

Initially, the FSM is in state ‘Off’. It does not call enterOff() at construction time; it is simply in Off already by convention. If you need to call code in enterOff() to initialize your FSM properly, call it explicitly in the constructor. Similarly, when cleanup() is called or the FSM is destructed, the FSM transitions back to ‘Off’ by convention. (It does call enterOff() at this point, but does not call exitOff().)

To implement nested hierarchical FSM’s, simply create a nested FSM and store it on the class within the appropriate enterState() function, and clean it up within the corresponding exitState() function.

There is a way to define specialized transition behavior between two particular states. This is done by defining a from<X>To<Y>() function, where X is the old state and Y is the new state. If this is defined, it will be run in place of the exit<X> and enter<Y> functions, so if you want that behavior, you’ll have to call them specifically. Otherwise, you can completely replace that transition’s behavior.

See the code in SampleFSM.py for further examples.

class EnumStates[source]

Bases: object

ANY = 1
DEFAULT = 2
SerialNum = 0
defaultTransitions = None
notify = <direct.directnotify.Notifier.Notifier object>
exception FSMException[source]

Bases: Exception

exception RequestDenied[source]

Bases: FSMException

class Transition(iterable=(), /)[source]

Bases: tuple

Used for the return value of fsm.request(). Behaves like a tuple, for historical reasons.