Add runners to features.rst & add a runner base & update docstrings

Change-Id: I18d7a656f537c3bf28257d24adc4a900e77906f3
This commit is contained in:
Joshua Harlow 2015-06-27 11:08:23 -07:00 committed by Joshua Harlow
parent 9094074e5b
commit ecf1263033
4 changed files with 58 additions and 22 deletions

View File

@ -49,15 +49,18 @@ class FiniteMachine(object):
entering a new state.
NOTE(harlowja): reactions will *only* be called when the generator/iterator
from ``runner.run_iter()`` does *not* send back a new event (they will
always be called if the ``runner.run()`` method is used). This allows for
two unique ways (these ways can also be intermixed) to use this state
machine when using ``runner.run_iter()``; one where *external* events
trigger the next state transition and one where *internal* reaction
callbacks trigger the next state transition. The other way to use this
state machine is to skip using ``runner.run()`` or ``runner.run_iter()``
completely and use the ``process_event()`` method explicitly and trigger
the events via some *external* functionality/triggers...
from :py:meth:`~automaton.runners.Runner.run_iter` does *not* send
back a new event (they will always be called if the
:py:meth:`~automaton.runners.Runner.run` method is used). This allows
for two unique ways (these ways can also be intermixed) to use this state
machine when using :py:meth:`~automaton.runners.Runner.run`; one
where *external* event trigger the next state transition and one
where *internal* reaction callbacks trigger the next state
transition. The other way to use this
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...)

View File

@ -14,6 +14,10 @@
# License for the specific language governing permissions and limitations
# under the License.
import abc
import six
from automaton import exceptions as excp
from automaton import machines
@ -24,7 +28,33 @@ _JUMPER_NOT_FOUND_TPL = ("Unable to progress since no reaction (or"
" 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.
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."""
if not isinstance(machine, (machines.FiniteMachine,)):
raise TypeError("FiniteRunner only works with FiniteMachine(s)")
self._machine = machine
super(FiniteRunner, self).__init__(machine)
def run(self, event, initialize=True):
"""Runs the state machine, using reactions only."""
for transition in self.run_iter(event, initialize=initialize):
pass
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:
self._machine.initialize()
while True:
@ -74,7 +96,7 @@ class FiniteRunner(object):
event = cb(old_state, new_state, event, *args, **kwargs)
class HierarchicalRunner(object):
class HierarchicalRunner(Runner):
"""Hierarchical machine runner used to run a hierarchical machine.
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,)):
raise TypeError("HierarchicalRunner only works with"
" HierarchicalFiniteMachine(s)")
self._machine = machine
super(HierarchicalRunner, self).__init__(machine)
def run(self, event, initialize=True):
"""Runs the state machine, using reactions only."""
for transition in self.run_iter(event, initialize=initialize):
pass

View File

@ -16,6 +16,9 @@ Machines
Runners
-------
.. autoclass:: automaton.runners.Runner
:members:
.. autoclass:: automaton.runners.FiniteRunner
:members:

View File

@ -2,7 +2,16 @@
Features
========
Machines
--------
* A :py:class:`.automaton.machines.FiniteMachine` state machine.
* A :py:class:`.automaton.machines.HierarchicalFiniteMachine` hierarchical
state machine.
Runners
-------
* A :py:class:`.automaton.runners.FiniteRunner` state machine runner.
* A :py:class:`.automaton.runners.HierarchicalRunner` hierarchical state
machine runner.