コード例 #1
0
ファイル: ui.py プロジェクト: panesofglass/xstate-python
    def init_FSM(self):
        # Trafic light example
        # green -> yellow -> red -> green ..
        self.fsm = Machine({
            "id": "lights",
            "initial": "green",
            "states": {
                "green": {
                    "on": {
                        "TIMER": "yellow"
                    },
                },
                "yellow": {
                    "on": {
                        "TIMER": "red"
                    }
                },
                "red": {
                    "on": {
                        "TIMER": "green"
                    }
                },
            },
        })

        self.state = self.fsm.initial_state
        self.update_label()
コード例 #2
0
    def __init__(
        self,
        # { "type": "compound", "states": { ... } }
        config,
        machine: Machine,
        key: str,
        parent: Union[StateNode, Machine] = None,
    ):
        self.parent = parent
        self.id = (config.get("id", parent.id + "." + key)
                   if parent else config.get("id", machine.id + "." + key))
        self.entry = ([
            self.get_actions(entry_action)
            for entry_action in config.get("entry")
        ] if config.get("entry") else [])

        self.exit = ([
            self.get_actions(exit_action) for exit_action in config.get("exit")
        ] if config.get("exit") else [])

        self.key = key
        self.states = {
            k: StateNode(v, machine=machine, parent=self, key=k)
            for k, v in config.get("states", {}).items()
        }
        self.on = {}
        self.transitions = []
        for k, v in config.get("on", {}).items():
            transition = Transition(v, source=self, event=k)
            self.on[k] = transition
            self.transitions.append(transition)

        initial_key = config.get("initial")

        if not initial_key:
            self.initial = None
        else:
            self.initial = Transition(self.states.get(initial_key),
                                      source=self,
                                      event=None)

        self.type = config.get("type")

        if self.type is None:
            self.type = "atomic" if not self.states else "compound"

        if self.type == "final":
            self.donedata = config.get("data")

        if config.get("onDone"):
            done_event = f"done.state.{self.id}"
            done_transition = Transition(config.get("onDone"),
                                         source=self,
                                         event=done_event)
            self.on[done_event] = done_transition
            self.transitions.append(done_transition)

        machine._register(self)
コード例 #3
0
def test_is_parallel_state():
    machine = Machine({
        "id": "test",
        "initial": "foo",
        "states": {
            "foo": {
                "type": "parallel"
            }
        }
    })

    foo_state_node = machine._get_by_id("test.foo")

    assert is_parallel_state(foo_state_node) is True
コード例 #4
0
def test_action():
    entry_mock = Mock()
    exit_mock = Mock()

    machine = Machine(
        {
            "id": "machine",
            "initial": "on",
            "states": {
                "on" : {
                    "on": {"TOGGLE": "off"},
                    "entry": [{"type": "entry_action"}],
                    "exit": [{"type": "exit_action"}]
                },
                "off": {
                    "on": {"TOGGLE": "on"}
                }
            },
        },
        actions = {
            "entry_action": entry_mock,
            "exit_action": exit_mock,
        }
    )


    state = machine.initial_state
    assert state.value is "on"
    
    for action in state.actions:
        action()
    
    entry_mock.assert_called_with()
    assert entry_mock.call_count is 1
    assert exit_mock.call_count is 0
    
    # ------------------------
    
    state = machine.transition(state, "TOGGLE")
    
    assert state.value is "off"
    
    for action in state.actions:
        action()
    
    exit_mock.assert_called_with()
    assert entry_mock.call_count is 1
    assert exit_mock.call_count is 1
コード例 #5
0
def test_entry_action_inline():
    mock = Mock()

    machine = Machine(
        {
            "id": "machine",
            "initial": "on",
            "states": {
                "on" : {
                    "on": {"TOGGLE": "off"},
                    "entry": [
                        lambda: mock()
                    ]
                },
                "off": {
                    "on": {"TOGGLE": "on"}
                }
            },
        }
    )


    state = machine.initial_state
    assert state.value is "on"
    
    for action in state.actions:
        action()
    
    mock.assert_called_with()
    assert mock.call_count is 1
コード例 #6
0
def scxml_to_machine(source: str) -> Machine:
    tree = ET.parse(source)
    root = tree.getroot()
    result = convert(root)
    machine = Machine(result)

    return machine
コード例 #7
0
ファイル: ui.py プロジェクト: panesofglass/xstate-python
class ApplicationBasic():
    def __init__(self):
        self.init_ui()
        self.init_FSM()

    def init_FSM(self):
        # Trafic light example
        # green -> yellow -> red -> green ..
        self.fsm = Machine({
            "id": "lights",
            "initial": "green",
            "states": {
                "green": {
                    "on": {
                        "TIMER": "yellow"
                    },
                },
                "yellow": {
                    "on": {
                        "TIMER": "red"
                    }
                },
                "red": {
                    "on": {
                        "TIMER": "green"
                    }
                },
            },
        })

        self.state = self.fsm.initial_state
        self.update_label()

    def init_ui(self):
        self.fen = tkinter.Tk()
        self.label = tkinter.Label(self.fen, text="")
        self.label.pack()
        self.button = tkinter.Button(self.fen,
                                     text="TIMER",
                                     command=self.action)
        self.button.pack()

    def action(self):
        print("action")
        self.state = self.fsm.transition(self.state, "TIMER")
        self.update_label()

    def update_label(self):
        self.label["text"] = self.state.value

    def run(self):
        self.fen.mainloop()
コード例 #8
0
def test_exit_action_inline():
    mock = Mock()

    machine = Machine(
        {
            "id": "machine",
            "initial": "on",
            "states": {
                "on" : {
                    "on": {"TOGGLE": "off"},
                    "exit": [
                        lambda: mock()
                    ]
                },
                "off": {
                    "on": {"TOGGLE": "on"}
                }
            },
        }
    )


    state = machine.initial_state
    assert state.value is "on"
    
    for action in state.actions:
        action()
    
    assert mock.call_count is 0
    
    state = machine.transition(state, "TOGGLE")
    
    for action in state.actions:
        action()
        
    assert mock.call_count is 1
    
コード例 #9
0
import time


# Trafic light example with substate
# green -> yellow -> red.walk -> red.wait -> red.stop -> green ..

lights = Machine(
    {
        "id": "lights",
        "initial": "green",
        "states": {
            "green": {"entry": [{"type": "enterGreen"}], "on": {"TIMER": "yellow"},},
            "yellow": {"on": {"TIMER": "red"}},
            "red": { # subFSM
                "initial": "walk",
                "states": {
                    "walk": {"on": {"COUNTDOWN": "wait"}},
                    "wait": {"on": {"COUNTDOWN": "stop"}},
                    "stop": {"on": {"TIMEOUT": "timeout"}},
                    "timeout": {"type": "final"}, # type 'final' will make it to the onDone step of the superior FSM
                },
                "onDone": "green",
            },
        },
    }
)

if __name__ == "__main__":
    state = lights.initial_state
    print(state.value)
    time.sleep(0.5)
    
コード例 #10
0
# https://plantuml.com/state-diagram
from plantweb.render import render
from xstate.machine import Machine

# just a test
simple_machine = Machine({
    "id": "simple",
    "initial": "green",
    "states": {
        "green": {
            "on": {
                "JENNY_EVENT": "yellow"
            }
        },
        "yellow": {
            "on": {
                "NEXT_EVENT": "red"
            }
        },
        "red": {
            "on": {
                "NEXT_EVENT": "green"
            }
        }
    }
})

def state_node_to_viz(state_node):
    result = ""

    if not state_node.parent:
コード例 #11
0
lights = Machine(
    {
        "id": "lights",
        "initial": "green",
        "states": {
            "green": {
                "on": {
                    "TIMER": "yellow"
                },
                "entry": [{
                    "type": "enterGreen"
                }],
                "exit": [{
                    "type": "exitGreen"
                }]
            },
            "yellow": {
                "on": {
                    "TIMER": "red"
                },
                "entry": [{
                    "type": "enterYellow"
                }]
            },
            "red": {
                "on": {
                    "TIMER": "green"
                },
                "entry": [lambda: print("\tINLINE callback")]
            },
        },
    },
    actions={
        # action implementations
        "enterGreen": enterGreen,
        "exitGreen": exitGreen,
        "enterYellow": lambda: print("\tENTER_YELLOW callback")
    })