From ecf12630330774e62baa28d41ddd8dc3bf15f7c5 Mon Sep 17 00:00:00 2001 From: Joshua Harlow Date: Sat, 27 Jun 2015 11:08:23 -0700 Subject: [PATCH] Add runners to features.rst & add a runner base & update docstrings Change-Id: I18d7a656f537c3bf28257d24adc4a900e77906f3 --- automaton/machines.py | 21 ++++++++++-------- automaton/runners.py | 47 +++++++++++++++++++++++++++++------------ doc/source/api.rst | 3 +++ doc/source/features.rst | 9 ++++++++ 4 files changed, 58 insertions(+), 22 deletions(-) diff --git a/automaton/machines.py b/automaton/machines.py index 5222b57..b45495f 100644 --- a/automaton/machines.py +++ b/automaton/machines.py @@ -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...) diff --git a/automaton/runners.py b/automaton/runners.py index 3bb28ed..5aa36fa 100644 --- a/automaton/runners.py +++ b/automaton/runners.py @@ -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 diff --git a/doc/source/api.rst b/doc/source/api.rst index 0faf9ae..920486d 100644 --- a/doc/source/api.rst +++ b/doc/source/api.rst @@ -16,6 +16,9 @@ Machines Runners ------- +.. autoclass:: automaton.runners.Runner + :members: + .. autoclass:: automaton.runners.FiniteRunner :members: diff --git a/doc/source/features.rst b/doc/source/features.rst index f2d7877..67a0d23 100644 --- a/doc/source/features.rst +++ b/doc/source/features.rst @@ -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.