fix inheritance of status codes attached to state functions
This commit is contained in:
parent
bd0f3a0b07
commit
79b8cd7b2d
@ -27,30 +27,27 @@ handles status depending on statemachine state
|
||||
|
||||
|
||||
from secop.core import BUSY, IDLE, ERROR, Parameter, Command, Done
|
||||
from secop.errors import ProgrammingError
|
||||
from secop.lib.newstatemachine import StateMachine, Retry, Finish, Start, Stop
|
||||
|
||||
|
||||
class status_code:
|
||||
"""decorator for state methods"""
|
||||
def __init__(self, code, text=None):
|
||||
self.code = code
|
||||
self.text = text
|
||||
def status_code(code, text=None):
|
||||
"""decorator, attaching a status to a state function
|
||||
|
||||
def __set_name__(self, owner, name):
|
||||
if not issubclass(owner, HasStates):
|
||||
raise ProgrammingError('when using decorator "status_code", %s must inherit HasStates' % owner.__name__)
|
||||
self.cls = owner
|
||||
self.name = name
|
||||
if 'statusMap' not in owner.__dict__:
|
||||
# we need a copy on each inheritance level
|
||||
owner.statusMap = owner.statusMap.copy()
|
||||
owner.statusMap[name] = self.code, name.replace('_', ' ') if self.text is None else self.text
|
||||
setattr(owner, name, self.func) # replace with original method
|
||||
:param code: the first element of the secop status tuple
|
||||
:param text: the second element of the secop status tuple. if not given,
|
||||
the name of the state function is used (underscores replaced by spaces)
|
||||
:return: the decorator function
|
||||
|
||||
def __call__(self, func):
|
||||
self.func = func
|
||||
return self
|
||||
if a state function has not attached status and is a method of the module running
|
||||
the state machine, the status is inherited from an overridden method, if available
|
||||
|
||||
a state function without attached status does not change the status, or, if it is
|
||||
used as the start function, BUSY is taken as default status code
|
||||
"""
|
||||
def wrapper(func):
|
||||
func.status = code, func.__name__.replace('_', ' ') if text is None else text
|
||||
return func
|
||||
return wrapper
|
||||
|
||||
|
||||
class HasStates:
|
||||
@ -58,7 +55,7 @@ class HasStates:
|
||||
all_status_changes = False # when true, send also updates for status changes within a cycle
|
||||
_state_machine = None
|
||||
_status = IDLE, ''
|
||||
statusMap = {}
|
||||
statusMap = None
|
||||
|
||||
def init_state_machine(self, **kwds):
|
||||
self._state_machine = StateMachine(
|
||||
@ -71,6 +68,7 @@ class HasStates:
|
||||
|
||||
def initModule(self):
|
||||
super().initModule()
|
||||
self.statusMap = {}
|
||||
self.init_state_machine()
|
||||
|
||||
def state_transition(self, sm, newstate):
|
||||
@ -97,7 +95,22 @@ class HasStates:
|
||||
status = self._state_machine.idle_status or (ERROR, 'Finish was returned without final status')
|
||||
else:
|
||||
name = statefunc.__name__
|
||||
status = self.statusMap.get(name)
|
||||
try:
|
||||
# look up in statusMap cache
|
||||
status = self.statusMap[name]
|
||||
except KeyError:
|
||||
# try to get status from method or inherited method
|
||||
cls = type(self)
|
||||
for base in cls.__mro__:
|
||||
try:
|
||||
status = getattr(base, name, None).status
|
||||
break
|
||||
except AttributeError:
|
||||
pass
|
||||
else:
|
||||
status = None
|
||||
# store it in the cache for all further calls
|
||||
self.statusMap[name] = status
|
||||
if status is None and default_code is not None:
|
||||
status = default_code, name.replace('_', ' ')
|
||||
return status
|
||||
@ -108,8 +121,7 @@ class HasStates:
|
||||
return Done
|
||||
return sm.status
|
||||
|
||||
def doPoll(self):
|
||||
super().doPoll()
|
||||
def cycle_machine(self):
|
||||
sm = self._state_machine
|
||||
sm.cycle()
|
||||
if sm.statefunc is None:
|
||||
@ -118,6 +130,10 @@ class HasStates:
|
||||
self.setFastPoll(False)
|
||||
self.read_status()
|
||||
|
||||
def doPoll(self):
|
||||
super().doPoll()
|
||||
self.cycle_machine()
|
||||
|
||||
def on_cleanup(self, sm):
|
||||
if isinstance(sm.cleanup_reason, Exception):
|
||||
return self.on_error(sm)
|
||||
|
Loading…
x
Reference in New Issue
Block a user