Add runners to features.rst & add a runner base & update docstrings
Change-Id: I18d7a656f537c3bf28257d24adc4a900e77906f3
This commit is contained in:
parent
9094074e5b
commit
ecf1263033
@ -49,15 +49,18 @@ class FiniteMachine(object):
|
|||||||
entering a new state.
|
entering a new state.
|
||||||
|
|
||||||
NOTE(harlowja): reactions will *only* be called when the generator/iterator
|
NOTE(harlowja): reactions will *only* be called when the generator/iterator
|
||||||
from ``runner.run_iter()`` does *not* send back a new event (they will
|
from :py:meth:`~automaton.runners.Runner.run_iter` does *not* send
|
||||||
always be called if the ``runner.run()`` method is used). This allows for
|
back a new event (they will always be called if the
|
||||||
two unique ways (these ways can also be intermixed) to use this state
|
:py:meth:`~automaton.runners.Runner.run` method is used). This allows
|
||||||
machine when using ``runner.run_iter()``; one where *external* events
|
for two unique ways (these ways can also be intermixed) to use this state
|
||||||
trigger the next state transition and one where *internal* reaction
|
machine when using :py:meth:`~automaton.runners.Runner.run`; one
|
||||||
callbacks trigger the next state transition. The other way to use this
|
where *external* event trigger the next state transition and one
|
||||||
state machine is to skip using ``runner.run()`` or ``runner.run_iter()``
|
where *internal* reaction callbacks trigger the next state
|
||||||
completely and use the ``process_event()`` method explicitly and trigger
|
transition. The other way to use this
|
||||||
the events via some *external* functionality/triggers...
|
state machine is to skip using :py:meth:`~automaton.runners.Runner.run`
|
||||||
|
or :py:meth:`~automaton.runners.Runner.run_iter`
|
||||||
|
completely and use the :meth:`.process_event` method explicitly and
|
||||||
|
trigger the events via some *external* functionality/triggers...
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Result of processing an event (cause and effect...)
|
# Result of processing an event (cause and effect...)
|
||||||
|
@ -14,6 +14,10 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
|
import abc
|
||||||
|
|
||||||
|
import six
|
||||||
|
|
||||||
from automaton import exceptions as excp
|
from automaton import exceptions as excp
|
||||||
from automaton import machines
|
from automaton import machines
|
||||||
|
|
||||||
@ -24,7 +28,33 @@ _JUMPER_NOT_FOUND_TPL = ("Unable to progress since no reaction (or"
|
|||||||
" in response to event '%s')")
|
" in response to event '%s')")
|
||||||
|
|
||||||
|
|
||||||
class FiniteRunner(object):
|
@six.add_metaclass(abc.ABCMeta)
|
||||||
|
class Runner(object):
|
||||||
|
"""Machine runner used to run a state machine.
|
||||||
|
|
||||||
|
Only **one** runner per machine should be active at the same time (aka
|
||||||
|
there should not be multiple runners using the same machine instance at
|
||||||
|
the same time).
|
||||||
|
"""
|
||||||
|
def __init__(self, machine):
|
||||||
|
self._machine = machine
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def run(self, event, initialize=True):
|
||||||
|
"""Runs the state machine, using reactions only."""
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def run_iter(self, event, initialize=True):
|
||||||
|
"""Returns a iterator/generator that will run the state machine.
|
||||||
|
|
||||||
|
NOTE(harlowja): only one runner iterator/generator should be active for
|
||||||
|
a machine, if this is not observed then it is possible for
|
||||||
|
initialization and other local state to be corrupted and cause issues
|
||||||
|
when running...
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
class FiniteRunner(Runner):
|
||||||
"""Finite machine runner used to run a finite machine.
|
"""Finite machine runner used to run a finite machine.
|
||||||
|
|
||||||
Only **one** runner per machine should be active at the same time (aka
|
Only **one** runner per machine should be active at the same time (aka
|
||||||
@ -36,21 +66,13 @@ class FiniteRunner(object):
|
|||||||
"""Create a runner for the given machine."""
|
"""Create a runner for the given machine."""
|
||||||
if not isinstance(machine, (machines.FiniteMachine,)):
|
if not isinstance(machine, (machines.FiniteMachine,)):
|
||||||
raise TypeError("FiniteRunner only works with FiniteMachine(s)")
|
raise TypeError("FiniteRunner only works with FiniteMachine(s)")
|
||||||
self._machine = machine
|
super(FiniteRunner, self).__init__(machine)
|
||||||
|
|
||||||
def run(self, event, initialize=True):
|
def run(self, event, initialize=True):
|
||||||
"""Runs the state machine, using reactions only."""
|
|
||||||
for transition in self.run_iter(event, initialize=initialize):
|
for transition in self.run_iter(event, initialize=initialize):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def run_iter(self, event, initialize=True):
|
def run_iter(self, event, initialize=True):
|
||||||
"""Returns a iterator/generator that will run the state machine.
|
|
||||||
|
|
||||||
NOTE(harlowja): only one runner iterator/generator should be active for
|
|
||||||
a machine, if this is not observed then it is possible for
|
|
||||||
initialization and other local state to be corrupted and cause issues
|
|
||||||
when running...
|
|
||||||
"""
|
|
||||||
if initialize:
|
if initialize:
|
||||||
self._machine.initialize()
|
self._machine.initialize()
|
||||||
while True:
|
while True:
|
||||||
@ -74,7 +96,7 @@ class FiniteRunner(object):
|
|||||||
event = cb(old_state, new_state, event, *args, **kwargs)
|
event = cb(old_state, new_state, event, *args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
class HierarchicalRunner(object):
|
class HierarchicalRunner(Runner):
|
||||||
"""Hierarchical machine runner used to run a hierarchical machine.
|
"""Hierarchical machine runner used to run a hierarchical machine.
|
||||||
|
|
||||||
Only **one** runner per machine should be active at the same time (aka
|
Only **one** runner per machine should be active at the same time (aka
|
||||||
@ -87,10 +109,9 @@ class HierarchicalRunner(object):
|
|||||||
if not isinstance(machine, (machines.HierarchicalFiniteMachine,)):
|
if not isinstance(machine, (machines.HierarchicalFiniteMachine,)):
|
||||||
raise TypeError("HierarchicalRunner only works with"
|
raise TypeError("HierarchicalRunner only works with"
|
||||||
" HierarchicalFiniteMachine(s)")
|
" HierarchicalFiniteMachine(s)")
|
||||||
self._machine = machine
|
super(HierarchicalRunner, self).__init__(machine)
|
||||||
|
|
||||||
def run(self, event, initialize=True):
|
def run(self, event, initialize=True):
|
||||||
"""Runs the state machine, using reactions only."""
|
|
||||||
for transition in self.run_iter(event, initialize=initialize):
|
for transition in self.run_iter(event, initialize=initialize):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -16,6 +16,9 @@ Machines
|
|||||||
Runners
|
Runners
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
.. autoclass:: automaton.runners.Runner
|
||||||
|
:members:
|
||||||
|
|
||||||
.. autoclass:: automaton.runners.FiniteRunner
|
.. autoclass:: automaton.runners.FiniteRunner
|
||||||
:members:
|
:members:
|
||||||
|
|
||||||
|
@ -2,7 +2,16 @@
|
|||||||
Features
|
Features
|
||||||
========
|
========
|
||||||
|
|
||||||
|
Machines
|
||||||
|
--------
|
||||||
|
|
||||||
* A :py:class:`.automaton.machines.FiniteMachine` state machine.
|
* A :py:class:`.automaton.machines.FiniteMachine` state machine.
|
||||||
* A :py:class:`.automaton.machines.HierarchicalFiniteMachine` hierarchical
|
* A :py:class:`.automaton.machines.HierarchicalFiniteMachine` hierarchical
|
||||||
state machine.
|
state machine.
|
||||||
|
|
||||||
|
Runners
|
||||||
|
-------
|
||||||
|
|
||||||
|
* A :py:class:`.automaton.runners.FiniteRunner` state machine runner.
|
||||||
|
* A :py:class:`.automaton.runners.HierarchicalRunner` hierarchical state
|
||||||
|
machine runner.
|
||||||
|
Loading…
Reference in New Issue
Block a user