A FSM bound to a Thing instance, returned when accessed as a instance attribute (self.state_machine).
There is no need to instantiate this class directly.
Source code in hololinked/hololinked/core/state_machine.py
classBoundFSM:""" A FSM bound to a `Thing` instance, returned when accessed as a instance attribute (`self.state_machine`). There is no need to instantiate this class directly. """def__init__(self,owner:Thing,state_machine:StateMachine)->None:self.descriptor=state_machineself.push_state_change_event=state_machine.push_state_change_eventself.owner=ownerself.logger=state_machine.loggerdefget_state(self)->str|StrEnum|None:""" return the current state, one can also access it using the property `current state`. Returns ------- str current state of the state machine """try:returnself.owner._state_machine_stateexceptAttributeError:returnself.initial_statedefset_state(self,value:str|StrEnum|Enum,push_event:bool=True,skip_callbacks:bool=False)->None:""" set state of state machine. Also triggers state change callbacks if `skip_callbacks=False` and pushes a state change event when `push_event=True` (when __init__ argument `push_state_change_event=True`). One can also set state using the '=' operator of the `current_state` property, in which case `skip_callbacks=False` and `push_event=True` will be used. If originally an enumeration for the list of allowed states was supplied, then an enumeration member must be used to set the state. If a list of strings were supplied, then a string is accepted. Raises ------ ValueError: if the state is not found in the allowed states """ifvalueinself.states:given_state=self.descriptor._get_machine_compliant_state(value)ifgiven_state==self.current_state:returnprevious_state=self.current_statenext_state=self.descriptor._get_machine_compliant_state(value)self.owner._state_machine_state=next_stateself.logger.info(f"state changed from {previous_state} to {next_state}")ifpush_eventandself.push_state_change_eventandhasattr(self.owner,"event_publisher"):self.owner.state# just acces to trigger the observable eventifskip_callbacks:returnifprevious_stateinself.on_exit:forfuncinself.on_exit[previous_state]:func(self.owner)ifnext_stateinself.on_enter:forfuncinself.on_enter[next_state]:func(self.owner)else:raiseValueError("given state '{}' not in set of allowed states : {}.".format(value,self.states))current_state=property(get_state,set_state,None,doc="""read and write current state of the state machine""")defcontains_object(self,object:Property|Callable)->bool:""" Check if specified object is found in any of the state machine states. Supply unbound method for checking methods, as state machine is specified at class level when the methods are unbound. """returnself.descriptor.contains_object(object)def__hash__(self):returnhash(self.owner.id+(str(state)forstateinself.states)+str(self.initial_state)+self.owner.__class__.__name__)def__str__(self):returnf"StateMachine(owner={self.owner.__class__.__name__} id={self.owner.id} initial_state={self.initial_state}, states={self.states})"def__eq__(self,other)->bool:ifnotisinstance(other,StateMachine):returnFalsereturn(self.states==other.statesandself.initial_state==other.initial_stateandself.owner.__class__==other.owner.__class__andself.owner.id==other.owner.id)def__contains__(self,state:str|StrEnum)->bool:returnstateinself.descriptor@propertydefinitial_state(self):"""initial state of the machine"""returnself.descriptor.initial_state@propertydefstates(self):"""list of allowed states"""returnself.descriptor.states@propertydefon_enter(self):"""callbacks to execute when a certain state is entered"""returnself.descriptor.on_enter@propertydefon_exit(self):"""callbacks to execute when certain state is exited"""returnself.descriptor.on_exit@propertydefmachine(self):"""the machine specification with state as key and objects as list"""returnself.descriptor.machine
set state of state machine. Also triggers state change callbacks if skip_callbacks=False and pushes a state
change event when push_event=True (when init argument push_state_change_event=True).
One can also set state using the '=' operator of the current_state property,
in which case skip_callbacks=False and push_event=True will be used.
If originally an enumeration for the list of allowed states was supplied,
then an enumeration member must be used to set the state. If a list of strings were supplied,
then a string is accepted.
Raises:
Type
Description
ValueError:
if the state is not found in the allowed states
Source code in hololinked/hololinked/core/state_machine.py
defset_state(self,value:str|StrEnum|Enum,push_event:bool=True,skip_callbacks:bool=False)->None:""" set state of state machine. Also triggers state change callbacks if `skip_callbacks=False` and pushes a state change event when `push_event=True` (when __init__ argument `push_state_change_event=True`). One can also set state using the '=' operator of the `current_state` property, in which case `skip_callbacks=False` and `push_event=True` will be used. If originally an enumeration for the list of allowed states was supplied, then an enumeration member must be used to set the state. If a list of strings were supplied, then a string is accepted. Raises ------ ValueError: if the state is not found in the allowed states """ifvalueinself.states:given_state=self.descriptor._get_machine_compliant_state(value)ifgiven_state==self.current_state:returnprevious_state=self.current_statenext_state=self.descriptor._get_machine_compliant_state(value)self.owner._state_machine_state=next_stateself.logger.info(f"state changed from {previous_state} to {next_state}")ifpush_eventandself.push_state_change_eventandhasattr(self.owner,"event_publisher"):self.owner.state# just acces to trigger the observable eventifskip_callbacks:returnifprevious_stateinself.on_exit:forfuncinself.on_exit[previous_state]:func(self.owner)ifnext_stateinself.on_enter:forfuncinself.on_enter[next_state]:func(self.owner)else:raiseValueError("given state '{}' not in set of allowed states : {}.".format(value,self.states))
get_state
get_state()->str|StrEnum|None
return the current state, one can also access it using the property current state.
Returns:
Type
Description
str
current state of the state machine
Source code in hololinked/hololinked/core/state_machine.py
defget_state(self)->str|StrEnum|None:""" return the current state, one can also access it using the property `current state`. Returns ------- str current state of the state machine """try:returnself.owner._state_machine_stateexceptAttributeError:returnself.initial_state
contains_object
contains_object(object:Property|Callable)->bool
Check if specified object is found in any of the state machine states.
Supply unbound method for checking methods, as state machine is specified at class level
when the methods are unbound.
Source code in hololinked/hololinked/core/state_machine.py
defcontains_object(self,object:Property|Callable)->bool:""" Check if specified object is found in any of the state machine states. Supply unbound method for checking methods, as state machine is specified at class level when the methods are unbound. """returnself.descriptor.contains_object(object)
Attributes
current_state
str instance-attribute, writable
read and write current state of the state machine
initial_state
str instance-attribute, read-only
initial state of the state machine
states
List[str] instance-attribute, read-only
list of allowed states
on_enter
typing.Dict instance-attribute, read-only
callbacks to execute when a certain state is entered
on_exit
str instance-attribute, read-only
callbacks to execute when a certain state is exited
machine
typing.Dict[str, List[Callable | Property]] instance-attribute, read-only
state machine definition, i.e. list of allowed properties and actions for each state