-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
## [0.3.2] - 2021-04-16 - **[Added]** `AtLeastOneState` that ends when one of its children states completes (all are run parallely) and return `success`.
- Loading branch information
Showing
10 changed files
with
191 additions
and
72 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
import sys | ||
|
||
from ..core import StateStatus, Board | ||
from .parallel_state import ParallelState | ||
|
||
|
||
class AtLeastOneState(ParallelState): | ||
""" An extension of parallel state where it stops and return if at least one of the children state | ||
is successful. | ||
""" | ||
|
||
def _statestatus_criteria(self) -> StateStatus: | ||
# check the state of all the children & return success if and only if all are successful | ||
for child in self._children: | ||
if child.check_status(StateStatus.SUCCESS): | ||
return StateStatus.SUCCESS | ||
return StateStatus.FAILED | ||
|
||
def tick(self, board: Board): | ||
# Note, this is very similar to the ParallelState tick function. Any fixes should also be applied there. | ||
# check if we should transition out of this state | ||
next_state = super().tick(board) | ||
if next_state == self: | ||
# we are staying in this state, tick each of the child | ||
at_least_one_running = False | ||
for child in self._children: | ||
# if the child is running, tick it | ||
if child.check_status(StateStatus.RUNNING): | ||
at_least_one_running = True | ||
child.tick(board) | ||
elif child.check_status(StateStatus.SUCCESS): | ||
self._children_complete_event.set() | ||
elif child.check_status(StateStatus.EXCEPTION): | ||
self.propergate_exception_information(child) | ||
self._child_exception = True | ||
self._children_complete_event.set() | ||
# if all child already done, we need to let the main process knows | ||
if not at_least_one_running: | ||
self._children_complete_event.set() | ||
# return itself since nothing transitioned | ||
return self | ||
else: | ||
# we are going to a new start, interrupt everthing that is going on | ||
if not self.interrupt(): | ||
# we wasn't able to complete the interruption. | ||
# This is bad.. meaning there are bunch of zombie threads running about | ||
print( | ||
f"ERROR {self._name} of type {self.__class__} unable to complete Interrupt Action. \ | ||
Zombie threads likely", file=sys.stderr) | ||
return next_state |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
import time | ||
import sys | ||
import io | ||
import pytest | ||
import typing | ||
|
||
from behavior_machine.core import Machine, State, StateStatus, Board | ||
from behavior_machine.library import PrintState, AtLeastOneState, SequentialState, IdleState, WaitState | ||
|
||
|
||
def test_atleastone_state(capsys): | ||
|
||
ps1 = PrintState('p1', "ps1") | ||
ws1 = WaitState("w1", 0.5) | ||
ps2 = PrintState('p2', "ps2") | ||
|
||
one = AtLeastOneState("one", children=[ | ||
ps2, | ||
SequentialState("seq", children=[ | ||
ws1, | ||
ps1 | ||
]) | ||
]) | ||
es = IdleState("endState") | ||
one.add_transition_on_success(es) | ||
exe = Machine("xe", one, end_state_ids=["endState"], rate=10) | ||
exe.run() | ||
|
||
assert capsys.readouterr().out == "ps2\n" | ||
|
||
|
||
def test_atleastone_interrupt(capsys): | ||
|
||
interrupted = False | ||
|
||
class WaitAndPrint(State): | ||
def execute(self, board: Board) -> typing.Optional[StateStatus]: | ||
time.sleep(0.5) | ||
if self.is_interrupted(): | ||
nonlocal interrupted | ||
interrupted = True | ||
return StateStatus.INTERRUPTED | ||
print("HelloWorld") | ||
return StateStatus.SUCCESS | ||
|
||
one = AtLeastOneState("one", children=[ | ||
PrintState('p5', "ps5"), | ||
WaitAndPrint("ws") | ||
]) | ||
es = IdleState("endState") | ||
one.add_transition_on_success(es) | ||
exe = Machine("xe", one, end_state_ids=["endState"], rate=10) | ||
exe.run() | ||
|
||
assert capsys.readouterr().out == "ps5\n" | ||
assert interrupted |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
import time | ||
|
||
from behavior_machine.core import Board, StateStatus, State, Machine | ||
|
||
|
||
def test_repeat_node_in_machine_fast(): | ||
|
||
counter = 0 | ||
|
||
class CounterState(State): | ||
def execute(self, board: Board) -> StateStatus: | ||
nonlocal counter | ||
counter += 1 | ||
return StateStatus.SUCCESS | ||
|
||
ds1 = CounterState("ds1") | ||
ds2 = CounterState("ds2") | ||
ds3 = CounterState("ds3") | ||
ds1.add_transition_on_success(ds2) | ||
ds2.add_transition_on_success(ds3) | ||
ds3.add_transition_on_success(ds1) | ||
|
||
exe = Machine('exe', ds1, rate=60) | ||
exe.start(None) | ||
time.sleep(2) | ||
exe.interrupt() | ||
# the performance of the computer might change this. | ||
assert counter >= (60 * 2) - 2 | ||
assert counter <= (60 * 2) + 1 | ||
|
||
|
||
def test_validate_transition_immediate(): | ||
|
||
counter = 0 | ||
|
||
class CounterState(State): | ||
def execute(self, board: Board) -> StateStatus: | ||
nonlocal counter | ||
counter += 1 | ||
return StateStatus.SUCCESS | ||
|
||
ds1 = CounterState("ds1") | ||
ds2 = CounterState("ds2") | ||
ds3 = CounterState("ds3") | ||
ds1.add_transition(lambda s, b: True, ds2) | ||
ds2.add_transition(lambda s, b: True, ds3) | ||
ds3.add_transition(lambda s, b: True, ds1) | ||
|
||
exe = Machine('exe', ds1, rate=60) | ||
exe.start(None) | ||
time.sleep(2) | ||
exe.interrupt() | ||
# the performance of the computer might change this. | ||
assert counter >= (60 * 2) - 2 | ||
assert counter <= (60 * 2) + 1 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters