summaryrefslogtreecommitdiff
path: root/examples
diff options
context:
space:
mode:
authorPaul McGuire <ptmcg@austin.rr.com>2019-05-27 20:36:04 -0500
committerPaul McGuire <ptmcg@austin.rr.com>2019-05-27 20:36:04 -0500
commitde5633bc975aad61d28ade5f96bf4af854657a6a (patch)
tree168adf36c42a7b70c98f2bd93d3918d8d653ab9b /examples
parentd2332c95675d71c10605eaf00b1171ef11d0970d (diff)
downloadpyparsing-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.py2
-rw-r--r--examples/statemachine/libraryBookDemo.py2
-rw-r--r--examples/statemachine/statemachine.py17
-rw-r--r--examples/statemachine/trafficLightDemo.py2
-rw-r--r--examples/statemachine/vending_machine.py76
-rw-r--r--examples/statemachine/video_demo.py48
-rw-r--r--examples/statemachine/videostate.pystate32
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