diff options
author | Paul McGuire <ptmcg@austin.rr.com> | 2019-05-27 20:36:04 -0500 |
---|---|---|
committer | Paul McGuire <ptmcg@austin.rr.com> | 2019-05-27 20:36:04 -0500 |
commit | de5633bc975aad61d28ade5f96bf4af854657a6a (patch) | |
tree | 168adf36c42a7b70c98f2bd93d3918d8d653ab9b /examples | |
parent | d2332c95675d71c10605eaf00b1171ef11d0970d (diff) | |
download | pyparsing-git-de5633bc975aad61d28ade5f96bf4af854657a6a.tar.gz |
Fine tuning of statemachine example, moving InvalidStateTransition declaration inside generated class; added video state machine demo; added vending machine state machine demo showing how to using statemachine without importing a .pystate file
Diffstat (limited to 'examples')
-rw-r--r-- | examples/statemachine/documentSignoffDemo.py | 2 | ||||
-rw-r--r-- | examples/statemachine/libraryBookDemo.py | 2 | ||||
-rw-r--r-- | examples/statemachine/statemachine.py | 17 | ||||
-rw-r--r-- | examples/statemachine/trafficLightDemo.py | 2 | ||||
-rw-r--r-- | examples/statemachine/vending_machine.py | 76 | ||||
-rw-r--r-- | examples/statemachine/video_demo.py | 48 | ||||
-rw-r--r-- | examples/statemachine/videostate.pystate | 32 |
7 files changed, 167 insertions, 12 deletions
diff --git a/examples/statemachine/documentSignoffDemo.py b/examples/statemachine/documentSignoffDemo.py index 0cbfc1f..2ca38c8 100644 --- a/examples/statemachine/documentSignoffDemo.py +++ b/examples/statemachine/documentSignoffDemo.py @@ -11,7 +11,7 @@ print('\n'.join(t.__name__ for t in documentsignoffstate.DocumentRevisionState.t class Document(documentsignoffstate.DocumentRevisionStateMixin): def __init__(self): - self.initialize_state(documentsignoffstate.New()) + self.initialize_state(documentsignoffstate.New) def run_demo(): diff --git a/examples/statemachine/libraryBookDemo.py b/examples/statemachine/libraryBookDemo.py index 5e73f07..a5e018d 100644 --- a/examples/statemachine/libraryBookDemo.py +++ b/examples/statemachine/libraryBookDemo.py @@ -10,7 +10,7 @@ import librarybookstate class Book(librarybookstate.BookStateMixin): def __init__(self): - self.initialize_state(librarybookstate.New()) + self.initialize_state(librarybookstate.New) class RestrictedBook(Book): diff --git a/examples/statemachine/statemachine.py b/examples/statemachine/statemachine.py index 7e4de86..398faa3 100644 --- a/examples/statemachine/statemachine.py +++ b/examples/statemachine/statemachine.py @@ -90,6 +90,8 @@ def expand_state_definition(source, loc, tokens): " self._state = None", " def initialize_state(self, init_state):", + " if isinstance(init_state, {baseStateClass}):".format(baseStateClass=baseStateClass), + " init_state = init_state()", " self._state = init_state", " @property", @@ -105,7 +107,7 @@ def expand_state_definition(source, loc, tokens): " return '{0}: {1}'.format(self.__class__.__name__, self._state)", ]) - return indent + ("\n" + indent).join(statedef) + "\n" + return ("\n" + indent).join(statedef) + "\n" stateMachine.setParseAction(expand_state_definition) @@ -151,14 +153,11 @@ def expand_named_state_definition(source, loc, tokens): statedef.extend("{tn_name}.transitionName = '{tn_name}'".format(tn_name=tn) for tn in transitions) - statedef.extend([ - "from statemachine import InvalidTransitionException as BaseTransitionException", - "class InvalidTransitionException(BaseTransitionException): pass", - ]) - # define base class for state classes statedef.extend([ "class %s(object):" % baseStateClass, + " from statemachine import InvalidTransitionException as BaseTransitionException", + " class InvalidTransitionException(BaseTransitionException): pass", " def __str__(self):", " return self.__class__.__name__", @@ -171,11 +170,11 @@ def expand_named_state_definition(source, loc, tokens): " try:", " return cls.tnmap[name]()", " except KeyError:", - " raise InvalidTransitionException('%s does not support transition %r'% (cls.__name__, name))", + " raise cls.InvalidTransitionException('%s does not support transition %r'% (cls.__name__, name))", " def __bad_tn(name):", " def _fn(cls):", - " raise InvalidTransitionException('%s does not support transition %r'% (cls.__name__, name))", + " raise cls.InvalidTransitionException('%s does not support transition %r'% (cls.__name__, name))", " _fn.__name__ = name", " return _fn", ]) @@ -228,7 +227,7 @@ def expand_named_state_definition(source, loc, tokens): " def {tn_name}(self): self._state = self._state.{tn_name}()".format(tn_name=tn) for tn in transitions ) - return indent + ("\n" + indent).join(statedef) + "\n" + return ("\n" + indent).join(statedef) + "\n" namedStateMachine.setParseAction(expand_named_state_definition) diff --git a/examples/statemachine/trafficLightDemo.py b/examples/statemachine/trafficLightDemo.py index 8358750..a8fac8c 100644 --- a/examples/statemachine/trafficLightDemo.py +++ b/examples/statemachine/trafficLightDemo.py @@ -10,7 +10,7 @@ import trafficlightstate class TrafficLight(trafficlightstate.TrafficLightStateMixin): def __init__(self): - self.initialize_state(trafficlightstate.Red()) + self.initialize_state(trafficlightstate.Red) def change(self): self._state = self._state.next_state() diff --git a/examples/statemachine/vending_machine.py b/examples/statemachine/vending_machine.py new file mode 100644 index 0000000..79158e5 --- /dev/null +++ b/examples/statemachine/vending_machine.py @@ -0,0 +1,76 @@ +# +# vending_machine.py +# +# Example of using the statemachine parser without importing a .pystate module. +# +# A vending machine that + +import statemachine + +# Vending machine buttons: +# A, B, C, D +# 1, 2, 3, 4 +# +vending_machine_state_description = """\ +statemachine VendingMachineState: + Idle-(press_alpha_button)->WaitingOnDigit + WaitingOnDigit-(press_alpha_button)->WaitingOnDigit + WaitingOnDigit-(press_digit_button)->DispenseProduct + DispenseProduct-(dispense)->Idle +""" + +# convert state machine text to state classes +generated = statemachine.namedStateMachine.transformString(vending_machine_state_description) +# print(generated) +# exec generated code to define state classes and state mixin +exec(generated) + +class VendingMachine(VendingMachineStateMixin): + def __init__(self): + self.initialize_state(Idle) + self._pressed = None + self._alpha_pressed = None + self._digit_pressed = None + + def press_button(self, button): + if button in "ABCD": + self._pressed = button + self.press_alpha_button() + elif button in "1234": + self._pressed = button + self.press_digit_button() + else: + print('Did not recognize button {!r}'.format(str(button))) + + def press_alpha_button(self): + try: + super(VendingMachine, self).press_alpha_button() + except VendingMachineState.InvalidTransitionException as ite: + print(ite) + else: + self._alpha_pressed = self._pressed + + def press_digit_button(self): + try: + super(VendingMachine, self).press_digit_button() + except VendingMachineState.InvalidTransitionException as ite: + print(ite) + else: + self._digit_pressed = self._pressed + self.dispense() + + def dispense(self): + try: + super(VendingMachine, self).dispense() + except VendingMachineState.InvalidTransitionException as ite: + print(ite) + else: + print("Dispensing at {}{}".format(self._alpha_pressed, self._digit_pressed)) + self._alpha_pressed = self._digit_pressed = None + + +vm = VendingMachine() +for button in "1 A B 1".split(): + print(">> pressing {!r}".format(button)) + vm.press_button(button) + print("Vending machine is now in {} state".format(vm.state)) diff --git a/examples/statemachine/video_demo.py b/examples/statemachine/video_demo.py new file mode 100644 index 0000000..fadfb9d --- /dev/null +++ b/examples/statemachine/video_demo.py @@ -0,0 +1,48 @@ +# +# video_demo.py +# +# Simple statemachine demo, based on the state transitions given in videostate.pystate +# + +import statemachine +import videostate + + +class Video(videostate.VideoStateMixin): + def __init__(self, title): + self.initialize_state(videostate.Stopped) + self.title = title + + +# ==== main loop - a REPL ==== + +v = Video("Die Hard.mp4") + +while True: + print(v.state) + cmd = input("Command ({})> ".format('/'.join(videostate.VideoState.transition_names))).lower().strip() + if not cmd: + continue + + if cmd in ('?', 'h', 'help'): + print('enter a transition {!r}'.format(videostate.VideoState.transition_names)) + print(' q - quit') + print(' ?, h, help - this message') + continue + + # quitting out + if cmd.startswith('q'): + break + + # get transition function for given command + state_transition_fn = getattr(v, cmd, None) + + if state_transition_fn is None: + print('???') + continue + + # invoke the input transition, handle invalid commands + try: + state_transition_fn() + except videostate.VideoState.InvalidTransitionException as e: + print(e) diff --git a/examples/statemachine/videostate.pystate b/examples/statemachine/videostate.pystate new file mode 100644 index 0000000..874001c --- /dev/null +++ b/examples/statemachine/videostate.pystate @@ -0,0 +1,32 @@ +# +# videostate.pystate +# +# Statemachine describing the playing of a video +# [] = stop +# > = play +# || = pause +# >> = fast forward +# << = rewind + +statemachine VideoState: + # basic >, [], and || controls + Stopped-(play)->Playing + Playing-(pause)-> Paused + Playing-(stop)-> Stopped + Paused-(stop)-> Stopped + Paused-(play)->Playing + + # add >> and << controls - different meanings if occur while playing or stopped + Playing-(fast_forward)->FastForward + FastForward-(play)->Playing + FastForward-(pause)->Paused + FastForward-(stop)->Stopped + Stopped-(fast_forward)->Forwardwinding + Forwardwinding-(stop)->Stopped + + Playing-(rewind)->ReversePlaying + ReversePlaying-(play)->Playing + ReversePlaying-(pause)->Paused + ReversePlaying-(stop)->Stopped + Stopped-(rewind)->Rewinding + Rewinding-(stop)->Stopped |