Search code examples
pythonfsm

python FSM Fysom callbacks on the other way


I am using Fysom to create FSM. I want to use callbacks in an other way:

TABLE = {
'initial': 'OFF',
'events': [{'name': 'load', 'src': 'OFF', 'dst': 'LOADED'},],
'callbacks': {'onload': myfunction,}}

fsm = Fysom(TABLE)

Here if I launch fsm.onload() it will execute myfunction. Instead I want If I launch myfunction() it will lunch fsm.onload().

I took a look on the script and related part is here:

def _enter_state(self, e):
    '''
        Executes the callback for onenter_state_ or on_state_.
    '''
    for fnname in ['onenter' + e.dst, 'on' + e.dst]:
        if hasattr(self, fnname):
            return getattr(self, fnname)(e)

I don't see how to change this peace of code for my purpose.


Solution

  • You cannot implement callbacks "in the other direction" without touching myfunction. A callback is actually an inverted call (hollywood principle), so the inverse of a callback is a simple call.

    What this means is that myfunction should call the state machine transition directly. As a consequence, the state machine object must be in the scope of myfunction.

    At this point you have some possibilities for implementation :

    • Have myfunction be a closure :

      def outer():
          fsm = Fysom(TABLE)
          def myfunction():
              print("I call the state machine transition when called")
              fsm.onload()
          return fsm
      
    • Use a global state machine or scope it in a class :

      class Foo(object):
      
          def __init__(self):
              self.fsm = Fysom(TABLE)
      
          def my_method(self):
              self.fsm.onload()
      
    • Create a decorator that calls the state transition method before/after executing the function. Then decorate away with

      fsm = Fysom(TABLE)
      
      @transition(fsm, "onload")
      def myfunction():
          pass
      

      Note that this also requires fsm to be defined in this scope.