Working on a fun side project at HackComo, I needed a finite state machine. Well, this is a simple decorator for limiting when a method can be ran:
def fsm(target, whence='*', attr='state'): """ `target` -> (str): REQUIRED should be the target state. `whence` -> (list): '*' should be a *list* of states that you can change from. `attr` -> (str): 'state' is the that of the attribute that represents state. Example: class Car(object): state = 'off' @fsm('on', whence=['off']) def turn_on(self): pass @fsm('off', whence=['on']) def turn_off(self): pass car = Car() # state is 'off' car.turn_off() # raise Exception car.turn_off(silent=True) # fails silently # state is still 'off' car.turn_on() # state is 'on """ def dec(method): def inner(self, *args, **kwargs): silent = kwargs.pop('silent', False) # check that whence == curent state if whence == '*': pass elif getattr(self, attr) in whence: pass else: if not silent: raise Exception('You shall not pass!') #LOTR else: return None result = method(self, *args, **kwargs) setattr(self, attr, target) # set state to target return result return inner return dec |