Code contained in statecharts¶
A statechart can write code to be executed under some circumstances.
For example, the on entry property on a statechart, guard or action on a transition or the
on entry and on exit property for a state.
In PySS, these pieces of code can be evaluated and executed by Evaluator instances.
Code evaluator¶
An Evaluator must provide two methods and an attribute:
-
class
pyss.evaluator.Evaluator¶ Base class for any evaluator.
An instance of this class defines what can be done with piece of codes contained in a statechart (condition, action, etc.).
-
context¶ The context of this evaluator. A context is a dict-like mapping between variables and values that is expected to be exposed through
evaluate_conditionandexecute_action.
-
evaluate_condition(condition: str, event: pyss.model.Event) → bool¶ Evaluate the condition of a guarded transition.
Parameters: - condition – A one-line Boolean expression
- event – The event (if any) that could fire the transition.
Returns: True or False
-
execute_action(action: str, event: pyss.model.Event=None) → list¶ Execute given action (multi-lines code) and return a (possibly empty) list of internal events to be considered by a statechart simulator.
Parameters: - action – A (possibly multi-lined) code to execute.
- event – an
Eventinstance in case of a transition action.
Returns: A possibly empty list of
Eventinstances
-
By default, PySS provides two built-in Evaluator subclasses:
- A
DummyEvaluatorthat always evaluate a guard toTrueand silently ignoresaction,on entryandon exit. Its context is an empty dictionary.- A
PythonEvaluatorthat brings Python into our statecharts and which is used by default.
Built-in Python code evaluator¶
An instance of PythonEvaluator can evaluate and execute Python code expressed in the statechart.
The key point to understand how it works is the concept of context, which is a dictionary-like structure that contains the data
that are exposed to the pieces of code of the statechart (ie. override __locals__).
As an example, consider the following partial statechart definition.
statechart:
# ...
on entry: x = 1
states:
- name: s1
on entry: x += 1
When the statechart is initialized, the context of a PythonEvaluator is {'x': 1}.
When s1 is entered, the code will be evaluated with this context.
After the execution of x += 1, the context associates 2 to x.
When a PythonEvaluator instance is initialized, a prepopulated context can be specified:
from pyss.evaluator import PythonEvaluator
import math as my_favorite_module
evaluator = PythonEvaluator({'x': 1, 'math': my_favorite_module})
By default, the context exposes an Event and a send function.
They can be used to send internal event to the simulator, eg., on entry: send(Event('Hello World!')).
Unless you override its entry in the context, the __builtins__ of Python are automatically exposed.
This implies you can use nearly everything from Python in your code.
-
class
pyss.evaluator.PythonEvaluator(initial_context: dict=None)¶ Evaluator that interprets Python code.
An initial context can be provided, as a dictionary (will be used as
__locals__). Unless overridden, the context also exposes:- The
__builtins__of Python, - The
Eventclass and, - A
sendmethod that takesEventinstances and send them to the statechart.
When one of
evaluate_conditionorexecute_actionmethod is called with an event parameter, it is also exposed by the context through the keyevent.Parameters: initial_context – a dictionary that will be used as __locals__- The
If an exception occurred while executing or evaluating a piece of code, it is propagated by the evaluator.
Examples¶
Consider the following statechart that performs simple arithmetic operations.
statechart:
name: statechart with executable content
on entry: |
x = 1
y = 2
initial: s1
states:
- name: s1
transitions:
- target: s2
action: |
x += 1
- name: s2
on_entry: |
y += 1
transitions:
- target: s3
- name: s3
type: final # x = 2, y = 3
The statechart here shows a more intricate example.