Skip to content

Commit

Permalink
nested: consider scope tree instead of source_path for exit strategy;
Browse files Browse the repository at this point in the history
bug discovered in #421
  • Loading branch information
aleneum committed Jun 24, 2020
1 parent 6bcfd73 commit 3a17f8f
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 16 deletions.
8 changes: 5 additions & 3 deletions Changelog.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Changelog

## 0.8.2 ()
## 0.8.2 (June 2020)

Release 0.8.2 is a minor release and contains several bugfixes and improvements:

Expand All @@ -9,11 +9,13 @@ Release 0.8.2 is a minor release and contains several bugfixes and improvements:
- Bugfix #440: Only allow explicit `dest=None` in `Machine.add_transition` (not just falsy) for internal transitions (thanks @Pathfinder216)
- Bugfix #419: Fix state creation of nested enums (thanks @thedrow)
- Bugfix #428: HierarchicalGraphMachine did not find/apply styling for parallel states (thanks @xiaohuihui1024)
- Bugfix: `Model.trigger` now considers the machine's and current state's `ignore_invalid_triggers` attribute and can be called with non-existing events (thanks @potens1)
- Bugfix: Child states may not have been exited when the executed transition had been defined on a parent (thanks @thedrow)
- Feature #429: Introduced `transitions.extensions.asyncio.AsyncTimeout` as a state decorator to avoid threads used in `transitions.extensions.state.Timeout` (thanks @potens1)
- Feature #444: `transitions` can now be tested online at mybinder.org
- PR #418: Use sets instead of lists to cache already covered transitions in nested state machines (thanks @thedrow)
- PR #422: Improve handling of unresolved attributes for easier inheritance (thanks @thedrow)
- `Model.trigger` now considers the machine's and current state's `ignore_invalid_triggers` attribute and can be called with non-existing events (thanks @potens1)
- Feature #444: `transitions` can now be tested online at mybinder.org
- PR #445: Refactored AsyncMachine to enable trio/anyio override

## 0.8.1 (April 2020)

Expand Down
40 changes: 37 additions & 3 deletions tests/test_nesting.py
Original file line number Diff line number Diff line change
Expand Up @@ -230,16 +230,23 @@ def test_enter_exit_nested_state(self):
def callback():
mock()
states = ['A', 'B', {'name': 'C', 'on_enter': callback, 'on_exit': callback,
'children': [{'name': '1', 'on_exit': callback}, '2', '3']}, 'D']
'children': [{'name': '1', 'on_enter': callback, 'on_exit': callback}, '2', '3']},
{'name': 'D', 'on_enter': callback, 'on_exit': callback}]
transitions = [['go', 'A', 'C{0}1'.format(State.separator)],
['go', 'C', 'D']]
m = self.stuff.machine_cls(states=states, transitions=transitions, initial='A')
m.go()
self.assertTrue(mock.called)
self.assertEqual(mock.call_count, 1)
self.assertEqual(2, mock.call_count)
m.go()
self.assertTrue(m.is_D())
self.assertEqual(mock.call_count, 3)
self.assertEqual(5, mock.call_count)
m.to_C()
self.assertEqual(7, mock.call_count)
m.to('C{0}1'.format(State.separator))
self.assertEqual(8, mock.call_count)
m.to('C{0}2'.format(State.separator))
self.assertEqual(9, mock.call_count)

def test_ordered_transitions(self):
State = self.state_cls
Expand Down Expand Up @@ -438,6 +445,33 @@ def to(self):
self.assertTrue(mock.called)
self.assertTrue(model2.is_B())

def test_trigger_parent(self):
parent_mock = MagicMock()
exit_mock = MagicMock()
enter_mock = MagicMock()

class Model():

def on_exit_A(self):
parent_mock()

def on_exit_A_1(self):
exit_mock()

def on_enter_A_2(self):
enter_mock()

model = Model()
machine = self.machine_cls(model, states=[{'name': 'A', 'children': ['1', '2']}],
transitions=[['go', 'A', 'A_2'], ['enter', 'A', 'A_1']], initial='A')

model.enter()
self.assertFalse(parent_mock.called)
model.go()
self.assertTrue(exit_mock.called)
self.assertTrue(enter_mock.called)
self.assertFalse(parent_mock.called)


class TestSeparatorsBase(TestCase):

Expand Down
10 changes: 7 additions & 3 deletions tests/test_parallel.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ def setUp(self):
{'name': '2', 'children': ['a', 'b'],
'initial': 'a',
'transitions': [['go', 'a', 'b']]}]}]
self.transitions = [['reset', '*', 'A']]
self.transitions = [['reset', 'C', 'A']]

def test_init(self):
m = self.stuff.machine_cls(states=self.states)
Expand Down Expand Up @@ -56,6 +56,7 @@ def on_exit_C_2(self):

model1 = Model()
m = self.stuff.machine_cls(model1, states=self.states, transitions=self.transitions, initial='A')
m.add_transition('reinit', 'C', 'C')
model1.to_C()
self.assertEqual(['C{0}1{0}a'.format(State.separator), 'C{0}2{0}a'.format(State.separator)], model1.state)
model1.reset()
Expand All @@ -64,15 +65,18 @@ def on_exit_C_2(self):

model2 = Model()
m.add_model(model2, initial='C')
model2.reinit()
self.assertEqual(['C{0}1{0}a'.format(State.separator), 'C{0}2{0}a'.format(State.separator)], model2.state)
self.assertEqual(3, model2.mock.call_count)
model2.reset()
self.assertTrue(model2.is_A())
self.assertEqual(3, model2.mock.call_count)
self.assertEqual(6, model2.mock.call_count)
for mod in m.models:
mod.trigger('to_C')
for mod in m.models:
mod.trigger('reset')
self.assertEqual(6, model1.mock.call_count)
self.assertEqual(6, model2.mock.call_count)
self.assertEqual(9, model2.mock.call_count)

def test_parent_transition(self):
m = self.stuff.machine_cls(states=self.states)
Expand Down
10 changes: 3 additions & 7 deletions transitions/extensions/nesting.py
Original file line number Diff line number Diff line change
Expand Up @@ -238,13 +238,9 @@ def _resolve_transition(self, event_data):
dst_name_path.pop(0)

scoped_tree = reduce(dict.get, scope + root, state_tree)
exit_partials = []
if src_name_path:
for state_name in _resolve_order(scoped_tree):
cb = partial(machine.get_state(root + state_name).scoped_exit,
event_data,
scope + root + state_name[:-1])
exit_partials.append(cb)
exit_partials = [partial(machine.get_state(root + state_name).scoped_exit,
event_data, scope + root + state_name[:-1])
for state_name in _resolve_order(scoped_tree)]
if dst_name_path:
new_states, enter_partials = self._enter_nested(root, dst_name_path, scope + root, event_data)
else:
Expand Down

0 comments on commit 3a17f8f

Please sign in to comment.