diff --git a/statemachine/event_data.py b/statemachine/event_data.py index 9585072..9b916ee 100644 --- a/statemachine/event_data.py +++ b/statemachine/event_data.py @@ -3,7 +3,6 @@ from time import time from typing import TYPE_CHECKING from typing import Any -from uuid import uuid4 if TYPE_CHECKING: from .event import Event @@ -41,8 +40,6 @@ def __post_init__(self): self.model = self.machine.model delay = self.event.delay if self.event and self.event.delay else 0 self.execution_time = time() + (delay / 1000) - if self.send_id is None: - self.send_id = uuid4().hex @dataclass diff --git a/statemachine/io/scxml/actions.py b/statemachine/io/scxml/actions.py index 5a6e24b..aaab007 100644 --- a/statemachine/io/scxml/actions.py +++ b/statemachine/io/scxml/actions.py @@ -92,18 +92,32 @@ def get(self, name, default=None): return self.kwargs.get(name, default) +class OriginTypeSCXML(str): + """The origintype of the :ref:`Event` as specified by the SCXML namespace.""" + + def __eq__(self, other): + return other == "http://www.w3.org/TR/scxml/#SCXMLEventProcessor" or other == "scxml" + + class EventDataWrapper: origin: str = "" - origintype: str = "http://www.w3.org/TR/scxml/#SCXMLEventProcessor" + origintype: str = OriginTypeSCXML("scxml") """The origintype of the :ref:`Event` as specified by the SCXML namespace.""" + invokeid: str = "" + """If this event is generated from an invoked child process, the SCXML Processor MUST set + this field to the invoke id of the invocation that triggered the child process. + Otherwise it MUST leave it blank. + """ def __init__(self, event_data): self.event_data = event_data + self.sendid = event_data.trigger_data.send_id if event_data.trigger_data.event is None or event_data.trigger_data.event.internal: if "error.execution" == event_data.trigger_data.event: self.type = "platform" else: self.type = "internal" + self.origintype = "" else: self.type = "external" @@ -365,12 +379,12 @@ def send_action(*args, **kwargs): internal = target in ("#_internal", "internal") + send_id = None if action.id: send_id = action.id - else: + elif action.idlocation: send_id = uuid4().hex - if action.idlocation: - setattr(machine.model, action.idlocation, send_id) + setattr(machine.model, action.idlocation, send_id) delay = ParseTime.parse_delay(action.delay, action.delayexpr, **kwargs) names = [ @@ -380,6 +394,8 @@ def send_action(*args, **kwargs): ] params_values = {} for param in chain(names, action.params): + if param.expr is None: + continue params_values[param.name] = _eval(param.expr, **kwargs) Event(id=event, name=event, delay=delay, internal=internal, _sm=machine).put( diff --git a/statemachine/io/scxml/processor.py b/statemachine/io/scxml/processor.py index 2d4aed9..89a61d1 100644 --- a/statemachine/io/scxml/processor.py +++ b/statemachine/io/scxml/processor.py @@ -44,6 +44,9 @@ def __getitem__(self, name: str): def location(self): return self.machine.name + def get(self, name: str): + return getattr(self, name) + @dataclass class SessionData: diff --git a/statemachine/io/scxml/schema.py b/statemachine/io/scxml/schema.py index 21b71c1..ce1e4ef 100644 --- a/statemachine/io/scxml/schema.py +++ b/statemachine/io/scxml/schema.py @@ -49,7 +49,7 @@ class IfBranch(Action): actions: List[Action] = field(default_factory=list) def __str__(self): - return self.cond + return self.cond or "" def append(self, action: Action): self.actions.append(action) diff --git a/tests/scxml/w3c/mandatory/test330.fail.md b/tests/scxml/w3c/mandatory/test330.fail.md deleted file mode 100644 index 4630843..0000000 --- a/tests/scxml/w3c/mandatory/test330.fail.md +++ /dev/null @@ -1,31 +0,0 @@ -# Testcase: test330 - -AssertionError: Assertion failed. - -Final configuration: `['fail']` - ---- - -## Logs -```py -DEBUG statemachine.engines.base:base.py:415 States to enter: {S0} -DEBUG statemachine.engines.base:base.py:93 New event 'foo' put on the 'internal' queue -DEBUG statemachine.engines.sync:sync.py:64 Processing loop started: s0 -DEBUG statemachine.io.scxml.actions:actions.py:180 Cond hasattr(_event, "name") and hasattr(_event, "type") and hasattr(_event, "sendid") and hasattr(_event, "origin") and hasattr(_event, "origintype") and hasattr(_event, "invokeid") and hasattr(_event, "data") -> False -DEBUG statemachine.engines.sync:sync.py:89 Eventless/internal queue: {transition * from S0 to Fail} -DEBUG statemachine.engines.base:base.py:339 States to exit: {S0} -DEBUG statemachine.engines.base:base.py:415 States to enter: {Fail} - -``` - -## "On transition" events -```py -OnEnterState(state='s0', event='__initial__', data='{}') -OnTransition(source='s0', event='foo', data='{}', target='fail') -OnEnterState(state='fail', event='foo', data='{}') -``` - -## Traceback -```py -Assertion of the testcase failed. -``` diff --git a/tests/scxml/w3c/mandatory/test333.fail.md b/tests/scxml/w3c/mandatory/test333.fail.md deleted file mode 100644 index 51b747f..0000000 --- a/tests/scxml/w3c/mandatory/test333.fail.md +++ /dev/null @@ -1,36 +0,0 @@ -# Testcase: test333 - -AssertionError: Assertion failed. - -Final configuration: `['fail']` - ---- - -## Logs -```py -DEBUG pydot:__init__.py:15 pydot initializing -DEBUG pydot:__init__.py:16 pydot 3.0.3 -DEBUG pydot.dot_parser:dot_parser.py:43 pydot dot_parser module initializing -DEBUG pydot.core:core.py:20 pydot core module initializing -DEBUG statemachine.engines.base:base.py:415 States to enter: {S0} -DEBUG statemachine.engines.base:base.py:93 New event 'foo' put on the 'external' queue -DEBUG statemachine.engines.sync:sync.py:64 Processing loop started: s0 -DEBUG statemachine.engines.sync:sync.py:116 External event: foo -DEBUG statemachine.engines.base:base.py:93 New event 'error.execution' put on the 'internal' queue -DEBUG statemachine.engines.sync:sync.py:131 Enabled transitions: {transition * from S0 to Fail} -DEBUG statemachine.engines.base:base.py:339 States to exit: {S0} -DEBUG statemachine.engines.base:base.py:415 States to enter: {Fail} - -``` - -## "On transition" events -```py -OnEnterState(state='s0', event='__initial__', data='{}') -OnTransition(source='s0', event='foo', data='{}', target='fail') -OnEnterState(state='fail', event='foo', data='{}') -``` - -## Traceback -```py -Assertion of the testcase failed. -``` diff --git a/tests/scxml/w3c/mandatory/test337.fail.md b/tests/scxml/w3c/mandatory/test337.fail.md deleted file mode 100644 index 068db12..0000000 --- a/tests/scxml/w3c/mandatory/test337.fail.md +++ /dev/null @@ -1,31 +0,0 @@ -# Testcase: test337 - -AssertionError: Assertion failed. - -Final configuration: `['fail']` - ---- - -## Logs -```py -DEBUG statemachine.engines.base:base.py:415 States to enter: {S0} -DEBUG statemachine.engines.base:base.py:93 New event 'foo' put on the 'internal' queue -DEBUG statemachine.engines.sync:sync.py:64 Processing loop started: s0 -DEBUG statemachine.io.scxml.actions:actions.py:180 Cond not _event.origintype -> False -DEBUG statemachine.engines.sync:sync.py:89 Eventless/internal queue: {transition * from S0 to Fail} -DEBUG statemachine.engines.base:base.py:339 States to exit: {S0} -DEBUG statemachine.engines.base:base.py:415 States to enter: {Fail} - -``` - -## "On transition" events -```py -OnEnterState(state='s0', event='__initial__', data='{}') -OnTransition(source='s0', event='foo', data='{}', target='fail') -OnEnterState(state='fail', event='foo', data='{}') -``` - -## Traceback -```py -Assertion of the testcase failed. -``` diff --git a/tests/scxml/w3c/mandatory/test339.fail.md b/tests/scxml/w3c/mandatory/test339.fail.md deleted file mode 100644 index b1af484..0000000 --- a/tests/scxml/w3c/mandatory/test339.fail.md +++ /dev/null @@ -1,31 +0,0 @@ -# Testcase: test339 - -AssertionError: Assertion failed. - -Final configuration: `['fail']` - ---- - -## Logs -```py -DEBUG statemachine.engines.base:base.py:415 States to enter: {S0} -DEBUG statemachine.engines.base:base.py:93 New event 'foo' put on the 'internal' queue -DEBUG statemachine.engines.sync:sync.py:64 Processing loop started: s0 -DEBUG statemachine.engines.base:base.py:93 New event 'error.execution' put on the 'internal' queue -DEBUG statemachine.engines.sync:sync.py:89 Eventless/internal queue: {transition * from S0 to Fail} -DEBUG statemachine.engines.base:base.py:339 States to exit: {S0} -DEBUG statemachine.engines.base:base.py:415 States to enter: {Fail} - -``` - -## "On transition" events -```py -OnEnterState(state='s0', event='__initial__', data='{}') -OnTransition(source='s0', event='foo', data='{}', target='fail') -OnEnterState(state='fail', event='foo', data='{}') -``` - -## Traceback -```py -Assertion of the testcase failed. -``` diff --git a/tests/scxml/w3c/mandatory/test351.fail.md b/tests/scxml/w3c/mandatory/test351.fail.md deleted file mode 100644 index ea48b27..0000000 --- a/tests/scxml/w3c/mandatory/test351.fail.md +++ /dev/null @@ -1,56 +0,0 @@ -# Testcase: test351 - -AssertionError: Assertion failed. - -Final configuration: `['fail']` - ---- - -## Logs -```py -DEBUG statemachine.engines.base:base.py:415 States to enter: {S0} -DEBUG statemachine.engines.base:base.py:93 New event 'timeout' put on the 'external' queue -DEBUG statemachine.engines.base:base.py:93 New event 's0Event' put on the 'external' queue -DEBUG statemachine.engines.sync:sync.py:64 Processing loop started: s0 -DEBUG statemachine.engines.sync:sync.py:116 External event: s0Event -DEBUG statemachine.engines.sync:sync.py:131 Enabled transitions: {transition s0Event from S0 to S1} -DEBUG statemachine.engines.base:base.py:339 States to exit: {S0} -DEBUG statemachine.engines.base:base.py:415 States to enter: {S1} -DEBUG statemachine.io.scxml.actions:actions.py:477 Error executing actions -Traceback (most recent call last): - File "/home/macedo/projects/python-statemachine/statemachine/io/scxml/actions.py", line 473, in __call__ - action(*args, **kwargs) - ~~~~~~^^^^^^^^^^^^^^^^^ - File "/home/macedo/projects/python-statemachine/statemachine/io/scxml/actions.py", line 241, in __call__ - value = _eval(self.action.expr, **kwargs) - File "/home/macedo/projects/python-statemachine/statemachine/io/scxml/actions.py", line 138, in _eval - return eval(expr, {}, kwargs) - File "", line 1, in - import sys;exec(eval(sys.stdin.readline())) - ^^^^^^^^^^^^^ - File "/home/macedo/projects/python-statemachine/statemachine/io/scxml/actions.py", line 111, in __getattr__ - return getattr(self.event_data, name) -AttributeError: 'EventData' object has no attribute 'sendid' -DEBUG statemachine.engines.base:base.py:93 New event 'error.execution' put on the 'internal' queue -DEBUG statemachine.engines.sync:sync.py:116 External event: timeout -DEBUG statemachine.engines.sync:sync.py:131 Enabled transitions: {} -DEBUG statemachine.io.scxml.actions:actions.py:180 Cond Var1=='send1' -> False -DEBUG statemachine.engines.sync:sync.py:89 Eventless/internal queue: {transition from S1 to Fail} -DEBUG statemachine.engines.base:base.py:339 States to exit: {S1} -DEBUG statemachine.engines.base:base.py:415 States to enter: {Fail} - -``` - -## "On transition" events -```py -OnEnterState(state='s0', event='__initial__', data='{}') -OnTransition(source='s0', event='s0Event', data='{}', target='s1') -OnEnterState(state='s1', event='s0Event', data='{}') -OnTransition(source='s1', event='None', data='{}', target='fail') -OnEnterState(state='fail', event='None', data='{}') -``` - -## Traceback -```py -Assertion of the testcase failed. -``` diff --git a/tests/scxml/w3c/mandatory/test352.fail.md b/tests/scxml/w3c/mandatory/test352.fail.md deleted file mode 100644 index 74b634e..0000000 --- a/tests/scxml/w3c/mandatory/test352.fail.md +++ /dev/null @@ -1,41 +0,0 @@ -# Testcase: test352 - -AssertionError: Assertion failed. - -Final configuration: `['fail']` - ---- - -## Logs -```py -DEBUG statemachine.engines.base:base.py:415 States to enter: {S0} -DEBUG statemachine.engines.base:base.py:93 New event 'timeout' put on the 'external' queue -DEBUG statemachine.engines.base:base.py:93 New event 's0Event' put on the 'external' queue -DEBUG statemachine.engines.sync:sync.py:64 Processing loop started: s0 -DEBUG statemachine.engines.sync:sync.py:116 External event: s0Event -DEBUG statemachine.engines.sync:sync.py:131 Enabled transitions: {transition s0Event from S0 to S1} -DEBUG statemachine.engines.base:base.py:339 States to exit: {S0} -DEBUG statemachine.engines.base:base.py:415 States to enter: {S1} -DEBUG statemachine.io.scxml.actions:actions.py:259 Assign: Var1 = 'http://www.w3.org/TR/scxml/#SCXMLEventProcessor' -DEBUG statemachine.engines.sync:sync.py:116 External event: timeout -DEBUG statemachine.engines.sync:sync.py:131 Enabled transitions: {} -DEBUG statemachine.io.scxml.actions:actions.py:180 Cond Var1=='scxml' -> False -DEBUG statemachine.engines.sync:sync.py:89 Eventless/internal queue: {transition from S1 to Fail} -DEBUG statemachine.engines.base:base.py:339 States to exit: {S1} -DEBUG statemachine.engines.base:base.py:415 States to enter: {Fail} - -``` - -## "On transition" events -```py -OnEnterState(state='s0', event='__initial__', data='{}') -OnTransition(source='s0', event='s0Event', data='{}', target='s1') -OnEnterState(state='s1', event='s0Event', data='{}') -OnTransition(source='s1', event='None', data='{}', target='fail') -OnEnterState(state='fail', event='None', data='{}') -``` - -## Traceback -```py -Assertion of the testcase failed. -``` diff --git a/tests/scxml/w3c/mandatory/test500.fail.md b/tests/scxml/w3c/mandatory/test500.fail.md deleted file mode 100644 index 41491a1..0000000 --- a/tests/scxml/w3c/mandatory/test500.fail.md +++ /dev/null @@ -1,43 +0,0 @@ -# Testcase: test500 - -AssertionError: Assertion failed. - -Final configuration: `['fail']` - ---- - -## Logs -```py -DEBUG statemachine.engines.base:base.py:415 States to enter: {S0} -DEBUG statemachine.io.scxml.actions:actions.py:453 Error executing actions -Traceback (most recent call last): - File "/home/macedo/projects/python-statemachine/statemachine/io/scxml/actions.py", line 451, in datamodel - act(**kwargs) - ~~~^^^^^^^^^^ - File "/home/macedo/projects/python-statemachine/statemachine/io/scxml/actions.py", line 422, in data_initializer - value = _eval(action.expr, **kwargs) - File "/home/macedo/projects/python-statemachine/statemachine/io/scxml/actions.py", line 138, in _eval - return eval(expr, {}, kwargs) - File "", line 1, in - import sys;exec(eval(sys.stdin.readline())) -AttributeError: 'IOProcessor' object has no attribute 'get' -DEBUG statemachine.engines.base:base.py:93 New event 'error.execution' put on the 'internal' queue -DEBUG statemachine.engines.sync:sync.py:64 Processing loop started: s0 -DEBUG statemachine.io.scxml.actions:actions.py:180 Cond Var1 -> None -DEBUG statemachine.engines.sync:sync.py:89 Eventless/internal queue: {transition from S0 to Fail} -DEBUG statemachine.engines.base:base.py:339 States to exit: {S0} -DEBUG statemachine.engines.base:base.py:415 States to enter: {Fail} - -``` - -## "On transition" events -```py -OnEnterState(state='s0', event='__initial__', data='{}') -OnTransition(source='s0', event='None', data='{}', target='fail') -OnEnterState(state='fail', event='None', data='{}') -``` - -## Traceback -```py -Assertion of the testcase failed. -``` diff --git a/tests/scxml/w3c/mandatory/test501.fail.md b/tests/scxml/w3c/mandatory/test501.fail.md deleted file mode 100644 index 66e9d67..0000000 --- a/tests/scxml/w3c/mandatory/test501.fail.md +++ /dev/null @@ -1,48 +0,0 @@ -# Testcase: test501 - -AssertionError: Assertion failed. - -Final configuration: `['fail']` - ---- - -## Logs -```py -DEBUG statemachine.engines.base:base.py:415 States to enter: {S0} -DEBUG statemachine.io.scxml.actions:actions.py:453 Error executing actions -Traceback (most recent call last): - File "/home/macedo/projects/python-statemachine/statemachine/io/scxml/actions.py", line 451, in datamodel - act(**kwargs) - ~~~^^^^^^^^^^ - File "/home/macedo/projects/python-statemachine/statemachine/io/scxml/actions.py", line 422, in data_initializer - value = _eval(action.expr, **kwargs) - File "/home/macedo/projects/python-statemachine/statemachine/io/scxml/actions.py", line 138, in _eval - return eval(expr, {}, kwargs) - File "", line 1, in - import sys;exec(eval(sys.stdin.readline())) -AttributeError: 'IOProcessor' object has no attribute 'get' -DEBUG statemachine.engines.base:base.py:93 New event 'error.execution' put on the 'internal' queue -DEBUG statemachine.engines.base:base.py:93 New event 'foo' put on the 'external' queue -DEBUG statemachine.engines.base:base.py:93 New event 'timeout' put on the 'external' queue -DEBUG statemachine.engines.sync:sync.py:64 Processing loop started: s0 -DEBUG statemachine.engines.sync:sync.py:89 Eventless/internal queue: {transition * from S0 to Fail} -DEBUG statemachine.engines.base:base.py:339 States to exit: {S0} -DEBUG statemachine.engines.base:base.py:415 States to enter: {Fail} -DEBUG statemachine.engines.sync:sync.py:116 External event: foo -DEBUG statemachine.engines.sync:sync.py:131 Enabled transitions: {} -DEBUG statemachine.engines.sync:sync.py:116 External event: timeout -DEBUG statemachine.engines.sync:sync.py:131 Enabled transitions: {} - -``` - -## "On transition" events -```py -OnEnterState(state='s0', event='__initial__', data='{}') -OnTransition(source='s0', event='error.execution', data='{\'event_id\': None, \'error\': AttributeError("\'IOProcessor\' object has no attribute \'get\'")}', target='fail') -OnEnterState(state='fail', event='error.execution', data='{\'event_id\': None, \'error\': AttributeError("\'IOProcessor\' object has no attribute \'get\'")}') -``` - -## Traceback -```py -Assertion of the testcase failed. -```