def test_canceled_before_event_false(self):
     gsm = FysomGlobal(events=[('calm', 'red', 'yellow'),
                               ('clear', 'yellow', 'green')],
                       callbacks={'on_before_calm': lambda e: False},
                       initial='red',
                       state_field='state')
     obj = self.BaseModel()
     gsm.startup(obj)
     self.assertRaises(Canceled, gsm.calm, obj)
    def test_asynchronous_transition(self):
        def _func(event):
            event.obj.logs.append('function_callback')

        def on_leave_red(event):
            return False

        gsm = FysomGlobal(events=[('calm', 'red', 'yellow'),
                                  ('clear', 'yellow', 'green')],
                          callbacks={
                              'on_leave_red': on_leave_red,
                              'on_after_calm': _func
                          },
                          initial='red',
                          state_field='state')
        obj = self.BaseModel()
        gsm.startup(obj)
        self.assertTrue(gsm.is_state(obj, 'red'))
        gsm.calm(obj)
        self.assertTrue(gsm.is_state(obj, 'red'))
        self.assertTrue(hasattr(obj, 'transition'))
        self.assertFalse('functioon_callback' in obj.logs)
        obj.transition()
        self.assertTrue(gsm.is_state(obj, 'yellow'))
        self.assertFalse(hasattr(obj, 'transition'))
        self.assertTrue('function_callback' in obj.logs)
    def test_transition_with_args_kwargs(self):
        def _func(event):
            self.assertTrue(hasattr(event, 'args'))
            self.assertTrue(hasattr(event, 'kwargs'))
            self.assertTrue(hasattr(event, 'msg'))
            event.obj.logs.append('function_callback')

        gsm = FysomGlobal(events=[('calm', 'red', 'yellow'),
                                  ('clear', 'yellow', 'green')],
                          callbacks={'on_after_startup': _func},
                          initial='red',
                          state_field='state')
        obj = self.BaseModel()
        gsm.startup(obj, msg='msg')
        self.assertTrue('function_callback' in obj.logs)
 def test_cfg_parameter(self):
     gsm = FysomGlobal(
         cfg={
             'events': [
                 ('warn', 'green', 'yellow'),
                 {
                     'name':
                     'panic',
                     'src': ['green', 'yellow'],
                     'dst':
                     'red',
                     'cond': [  # can be function object or method name
                         'is_angry',  # by default target is "True"
                         {
                             True: 'is_very_angry',
                             'else': 'yellow'
                         }
                     ]
                 },
                 ('calm', 'red', 'yellow'),
                 ('clear', 'yellow', 'green')
             ]
         },
         initial='green',
         final='red',
         state_field='state')
     self.assertTrue(hasattr(gsm, 'warn'))
     self.assertTrue(hasattr(gsm, 'panic'))
     self.assertTrue(hasattr(gsm, 'calm'))
     self.assertTrue(hasattr(gsm, 'clear'))
 def test_wildcard_src(self):
     gsm = FysomGlobal(events=[{
         'name': 'calm',
         'dst': 'yellow'
     }],
                       initial='red',
                       state_field='state')
     obj = self.BaseModel()
     gsm.startup(obj)
     self.assertTrue(gsm.is_state(obj, 'red'))
     gsm.calm(obj)
     self.assertTrue(gsm.is_state(obj, 'yellow'))
    def test_function_callback(self):
        def _func(event):
            event.obj.logs.append('function_callback')

        gsm = FysomGlobal(events=[('calm', 'red', 'yellow'),
                                  ('clear', 'yellow', 'green')],
                          callbacks={'on_after_clear': _func},
                          initial='red',
                          state_field='state')
        obj = self.BaseModel()
        gsm.startup(obj)
        gsm.calm(obj)
        gsm.clear(obj)
        self.assertTrue('function_callback' in obj.logs)
 def test_manual_startup(self):
     gsm = FysomGlobal(events=[('calm', 'red', 'yellow'),
                               ('clear', 'yellow', 'green')],
                       initial='red',
                       state_field='state')
     obj = self.BaseModel()
     self.assertTrue(gsm.is_state(obj, 'none'))
     self.assertTrue(hasattr(gsm, 'startup'))
     gsm.startup(obj)
     self.assertTrue(gsm.is_state(obj, 'red'))
示例#8
0
class NavigationGameFSM(FysomGlobalMixin, object):

    GSM = FysomGlobal(initial='not_running',
                      events=[{
                          'name': 'run',
                          'src': ['not_running', 'has_won', 'dead'],
                          'dst': 'menu'
                      }, ('win', 'playing', 'has_won'),
                              ('next', 'menu', 'black_screen'),
                              ('play', 'black_screen', 'playing'),
                              ('die', 'playing', 'dead')],
                      state_field='state')

    def __init__(self):
        self.state = None
        super(NavigationGameFSM, self).__init__()
示例#9
0
文件: m.py 项目: moznuy/TestCoverage
class Model(FysomGlobalMixin, object):
    GSM = FysomGlobal(
        events=[
            ('warn', 'green', 'yellow'),
            {
                'name':
                'panic',
                'src': ['green', 'yellow'],
                'dst':
                'red',
                'cond': [  # can be function object or method name
                    'is_angry',  # by default target is "True"
                    {
                        True: 'is_very_angry',
                        'else': 'yellow'
                    }
                ]
            },
            ('calm', 'red', 'yellow'),
            ('clear', 'yellow', 'green')
        ],
        initial='green',
        final='red',
        state_field='state')

    def __init__(self):
        self._state = None
        super(Model, self).__init__()

    @property
    def state(self):
        return self._state

    @state.setter
    def state(self, value):
        self._state = value
        print(f'new state: {value}')

    def is_angry(self, event):
        return True

    def is_very_angry(self, event):
        return False

    def __str__(self):
        return self.state
示例#10
0
 def test_callable_or_basestring_condition(self):
     gsm = FysomGlobal(events=[{
         'name': 'calm',
         'src': 'red',
         'dst': 'yellow',
         'cond': lambda e: True,
     }, {
         'name': 'clear',
         'src': 'yellow',
         'dst': 'green',
         'cond': 'check_false'
     }],
                       initial='red',
                       state_field='state')
     obj = self.BaseModel()
     gsm.startup(obj)
     gsm.calm(obj)
     self.assertTrue(gsm.is_state(obj, 'yellow'))
     self.assertRaises(Canceled, gsm.clear, obj)
     self.assertTrue(gsm.is_state(obj, 'yellow'))
示例#11
0
 def test_manual_startup_event_name(self):
     gsm = FysomGlobal(events=[('calm', 'red', 'yellow'),
                               ('clear', 'yellow', 'green')],
                       initial={
                           'state': 'red',
                           'event': 'my_startup'
                       },
                       state_field='state')
     obj = self.BaseModel()
     self.assertTrue(gsm.is_state(obj, 'none'))
     self.assertTrue(hasattr(gsm, 'my_startup'))
     gsm.my_startup(obj)
     self.assertTrue(gsm.current(obj) == 'red')
示例#12
0
class Machine(FysomGlobalMixin, models.Model):
    GSM = FysomGlobal(
        events=[
            ('key_put',  'idle',  'engine_starting'),
            ('key_turn', 'engine_starting', 'stopped'),
            ('pedal_gas', 'stopped', 'moving'),
            ('pedal_stop', ['moving', 'stopped'], 'stopped'),
            ('key_out', 'stopped', 'idle'),
        ],
        initial='idle',
        state_field='state',
    )

    state = models.CharField(max_length=128)


    def on_enter_stopped(self, e):
        print(f"{self} stopped. Ready to move")

    def __str__(self):
        return f'Car "{self.state}" state'
示例#13
0
    def setUp(self):
        self.GSM = FysomGlobal(
            events=[
                ('warn', 'green', 'yellow'),
                {
                    'name':
                    'panic',
                    'src': ['green', 'yellow'],
                    'dst':
                    'red',
                    'cond': [  # can be function object or method name
                        'is_angry',  # by default target is "True"
                        {
                            True: 'is_very_angry',
                            'else': 'yellow'
                        }
                    ]
                },
                ('calm', 'red', 'yellow'),
                ('clear', 'yellow', 'green')
            ],
            initial='green',
            final='red',
            state_field='state')

        class BaseModel(object):
            def __init__(self):
                self.state = None
                self.can_angry = True
                self.can_very_angry = False
                self.logs = []

            def is_angry(self, event):
                return self.can_angry

            def is_very_angry(self, event):
                return self.can_very_angry

            def on_change_state(self, event):
                self.logs.append('on_change_state')

            def check_true(self, event):
                return True

            def check_false(self, event):
                return False

        for _state in ('green', 'yellow', 'red'):
            for _at in ('enter', 'reenter', 'leave'):
                attr_name = 'on_%s_%s' % (_at, _state)

                def f(obj, event, attr_name=attr_name):
                    obj.logs.append(attr_name)

                setattr(BaseModel, attr_name, f)

        for _event in ('warn', 'panic', 'calm', 'clear'):
            for _at in ('before', 'after'):
                attr_name = 'on_%s_%s' % (_at, _event)

                def f(obj, event, attr_name=attr_name):
                    obj.logs.append(attr_name)

                setattr(BaseModel, attr_name, f)

        self.BaseModel = BaseModel

        class MixinModel(FysomGlobalMixin, BaseModel):

            GSM = self.GSM

        self.MixinModel = MixinModel
示例#14
0
class FysomGlobalTests(unittest.TestCase):
    def setUp(self):
        self.GSM = FysomGlobal(
            events=[
                ('warn', 'green', 'yellow'),
                {
                    'name':
                    'panic',
                    'src': ['green', 'yellow'],
                    'dst':
                    'red',
                    'cond': [  # can be function object or method name
                        'is_angry',  # by default target is "True"
                        {
                            True: 'is_very_angry',
                            'else': 'yellow'
                        }
                    ]
                },
                ('calm', 'red', 'yellow'),
                ('clear', 'yellow', 'green')
            ],
            initial='green',
            final='red',
            state_field='state')

        class BaseModel(object):
            def __init__(self):
                self.state = None
                self.can_angry = True
                self.can_very_angry = False
                self.logs = []

            def is_angry(self, event):
                return self.can_angry

            def is_very_angry(self, event):
                return self.can_very_angry

            def on_change_state(self, event):
                self.logs.append('on_change_state')

            def check_true(self, event):
                return True

            def check_false(self, event):
                return False

        for _state in ('green', 'yellow', 'red'):
            for _at in ('enter', 'reenter', 'leave'):
                attr_name = 'on_%s_%s' % (_at, _state)

                def f(obj, event, attr_name=attr_name):
                    obj.logs.append(attr_name)

                setattr(BaseModel, attr_name, f)

        for _event in ('warn', 'panic', 'calm', 'clear'):
            for _at in ('before', 'after'):
                attr_name = 'on_%s_%s' % (_at, _event)

                def f(obj, event, attr_name=attr_name):
                    obj.logs.append(attr_name)

                setattr(BaseModel, attr_name, f)

        self.BaseModel = BaseModel

        class MixinModel(FysomGlobalMixin, BaseModel):

            GSM = self.GSM

        self.MixinModel = MixinModel

    def test_no_mixin_initial_state(self):
        obj = self.BaseModel()
        self.assertTrue(self.GSM.isstate(obj, 'none'))
        self.assertTrue(self.GSM.is_state(obj, 'none'))

    def test_mixin_initial_state(self):
        obj = self.MixinModel()
        self.assertTrue(obj.isstate('green'))
        self.assertTrue(obj.is_state('green'))

    def test_mixin_initial_event(self):
        obj = self.MixinModel()
        self.assertEqual(obj.logs, ['on_enter_green', 'on_change_state'])

    def test_mixin_current_property(self):
        obj = self.MixinModel()
        self.assertEqual(obj.current, 'green')
        obj.current = 'yellow'
        self.assertEqual(obj.current, 'yellow')

    def test_is_finished(self):
        obj = self.MixinModel()
        obj.can_very_angry = True
        obj.panic()
        self.assertTrue(obj.is_finished())

    def test_valid_transition_is_allowed(self):
        obj = self.MixinModel()
        self.assertTrue(obj.is_state('green'))
        obj.warn()
        self.assertTrue(obj.is_state('yellow'))

    def test_invalid_transition_is_not_allowed(self):
        obj = self.MixinModel()
        self.assertTrue(obj.is_state('green'))
        obj.can_very_angry = True
        obj.warn()
        self.assertTrue(obj.is_state('yellow'))
        obj.panic()
        self.assertTrue(obj.is_state('red'))
        self.assertRaises(FysomError, obj.clear)

    def tests_callbacks_order(self):
        obj = self.MixinModel()
        obj.logs = []
        obj.warn()
        self.assertEqual(obj.logs, [
            'on_before_warn', 'on_leave_green', 'on_enter_yellow',
            'on_change_state', 'on_after_warn'
        ])
        obj.can_angry = False
        obj.logs = []
        self.assertRaises(Canceled, obj.panic)
        self.assertEqual(obj.logs, [])
        self.assertTrue(obj.is_state('yellow'))
        obj.can_angry = True
        obj.can_very_angry = False
        obj.panic()
        self.assertEqual(
            obj.logs,
            ['on_before_panic', 'on_reenter_yellow', 'on_after_panic'])

    def test_ok_condition_passed(self):
        obj = self.MixinModel()
        obj.can_very_angry = True
        obj.panic()
        self.assertTrue(obj.is_state('red'))

    def test_not_ok_condition_rejected(self):
        obj = self.MixinModel()
        obj.can_angry = False
        self.assertRaises(Canceled, obj.panic)
        self.assertTrue(obj.is_state('green'))

    def test_conditional_transition_passed(self):
        obj = self.MixinModel()
        self.assertTrue(obj.is_state('green'))
        obj.panic()
        self.assertFalse(obj.is_state('red'))
        self.assertTrue(obj.is_state('yellow'))

    def test_canceled_exception_with_event(self):
        obj = self.MixinModel()
        obj.can_angry = False
        self.assertRaises(Canceled, obj.panic)
        try:
            obj.panic()
        except Canceled as err:
            self.assertTrue(hasattr(err, 'event'))
            exc_event = err.event
            self.assertTrue(hasattr(exc_event, 'fsm'))
            self.assertTrue(hasattr(exc_event, 'obj'))
            self.assertTrue(hasattr(exc_event, 'src'))
            self.assertEqual(exc_event.src, 'green')
            self.assertTrue(hasattr(exc_event, 'dst'))
            self.assertEqual(exc_event.dst, 'red')
            self.assertTrue(hasattr(exc_event, 'args'))
            self.assertTrue(hasattr(exc_event, 'kwargs'))

    def test_trigger_works(self):
        obj = self.MixinModel()
        obj.trigger('warn')
        self.assertEqual(obj.current, 'yellow')
        self.assertRaises(FysomError, obj.trigger, 'unknown_event')
        self.assertEqual(obj.current, 'yellow')

    def test_no_state_field_specified(self):
        def _t():
            gsm = FysomGlobal(events=[])

        self.assertRaises(FysomError, _t)

    def test_cfg_parameter(self):
        gsm = FysomGlobal(
            cfg={
                'events': [
                    ('warn', 'green', 'yellow'),
                    {
                        'name':
                        'panic',
                        'src': ['green', 'yellow'],
                        'dst':
                        'red',
                        'cond': [  # can be function object or method name
                            'is_angry',  # by default target is "True"
                            {
                                True: 'is_very_angry',
                                'else': 'yellow'
                            }
                        ]
                    },
                    ('calm', 'red', 'yellow'),
                    ('clear', 'yellow', 'green')
                ]
            },
            initial='green',
            final='red',
            state_field='state')
        self.assertTrue(hasattr(gsm, 'warn'))
        self.assertTrue(hasattr(gsm, 'panic'))
        self.assertTrue(hasattr(gsm, 'calm'))
        self.assertTrue(hasattr(gsm, 'clear'))

    def test_manual_startup(self):
        gsm = FysomGlobal(events=[('calm', 'red', 'yellow'),
                                  ('clear', 'yellow', 'green')],
                          initial='red',
                          state_field='state')
        obj = self.BaseModel()
        self.assertTrue(gsm.is_state(obj, 'none'))
        self.assertTrue(hasattr(gsm, 'startup'))
        gsm.startup(obj)
        self.assertTrue(gsm.is_state(obj, 'red'))

    def test_manual_startup_event_name(self):
        gsm = FysomGlobal(events=[('calm', 'red', 'yellow'),
                                  ('clear', 'yellow', 'green')],
                          initial={
                              'state': 'red',
                              'event': 'my_startup'
                          },
                          state_field='state')
        obj = self.BaseModel()
        self.assertTrue(gsm.is_state(obj, 'none'))
        self.assertTrue(hasattr(gsm, 'my_startup'))
        gsm.my_startup(obj)
        self.assertTrue(gsm.current(obj) == 'red')

    def test_function_callback(self):
        def _func(event):
            event.obj.logs.append('function_callback')

        gsm = FysomGlobal(events=[('calm', 'red', 'yellow'),
                                  ('clear', 'yellow', 'green')],
                          callbacks={'on_after_clear': _func},
                          initial='red',
                          state_field='state')
        obj = self.BaseModel()
        gsm.startup(obj)
        gsm.calm(obj)
        gsm.clear(obj)
        self.assertTrue('function_callback' in obj.logs)

    def test_asynchronous_transition(self):
        def _func(event):
            event.obj.logs.append('function_callback')

        def on_leave_red(event):
            return False

        gsm = FysomGlobal(events=[('calm', 'red', 'yellow'),
                                  ('clear', 'yellow', 'green')],
                          callbacks={
                              'on_leave_red': on_leave_red,
                              'on_after_calm': _func
                          },
                          initial='red',
                          state_field='state')
        obj = self.BaseModel()
        gsm.startup(obj)
        self.assertTrue(gsm.is_state(obj, 'red'))
        gsm.calm(obj)
        self.assertTrue(gsm.is_state(obj, 'red'))
        self.assertTrue(hasattr(obj, 'transition'))
        self.assertFalse('functioon_callback' in obj.logs)
        obj.transition()
        self.assertTrue(gsm.is_state(obj, 'yellow'))
        self.assertFalse(hasattr(obj, 'transition'))
        self.assertTrue('function_callback' in obj.logs)

    def test_transition_with_args_kwargs(self):
        def _func(event):
            self.assertTrue(hasattr(event, 'args'))
            self.assertTrue(hasattr(event, 'kwargs'))
            self.assertTrue(hasattr(event, 'msg'))
            event.obj.logs.append('function_callback')

        gsm = FysomGlobal(events=[('calm', 'red', 'yellow'),
                                  ('clear', 'yellow', 'green')],
                          callbacks={'on_after_startup': _func},
                          initial='red',
                          state_field='state')
        obj = self.BaseModel()
        gsm.startup(obj, msg='msg')
        self.assertTrue('function_callback' in obj.logs)

    def test_canceled_before_event_false(self):
        gsm = FysomGlobal(events=[('calm', 'red', 'yellow'),
                                  ('clear', 'yellow', 'green')],
                          callbacks={'on_before_calm': lambda e: False},
                          initial='red',
                          state_field='state')
        obj = self.BaseModel()
        gsm.startup(obj)
        self.assertRaises(Canceled, gsm.calm, obj)

    def test_callable_or_basestring_condition(self):
        gsm = FysomGlobal(events=[{
            'name': 'calm',
            'src': 'red',
            'dst': 'yellow',
            'cond': lambda e: True,
        }, {
            'name': 'clear',
            'src': 'yellow',
            'dst': 'green',
            'cond': 'check_false'
        }],
                          initial='red',
                          state_field='state')
        obj = self.BaseModel()
        gsm.startup(obj)
        gsm.calm(obj)
        self.assertTrue(gsm.is_state(obj, 'yellow'))
        self.assertRaises(Canceled, gsm.clear, obj)
        self.assertTrue(gsm.is_state(obj, 'yellow'))

    def test_unknown_event(self):
        obj = self.MixinModel()
        self.assertFalse(obj.can('unknown_event'))
        self.assertTrue(self.GSM.cannot(obj, 'unknown_event'))

    def test_wildcard_src(self):
        gsm = FysomGlobal(events=[{
            'name': 'calm',
            'dst': 'yellow'
        }],
                          initial='red',
                          state_field='state')
        obj = self.BaseModel()
        gsm.startup(obj)
        self.assertTrue(gsm.is_state(obj, 'red'))
        gsm.calm(obj)
        self.assertTrue(gsm.is_state(obj, 'yellow'))
示例#15
0
 def _t():
     gsm = FysomGlobal(events=[])
示例#16
0
class HVAC(FysomGlobalMixin):
    GSM = FysomGlobal(
        events=[('cool', 'idle', 'cool'), ('heat', 'idle', 'heat'),
                ('fan', 'idle', 'fan'),
                ('idle', ['idle', 'cool', 'heat'], 'idle')],
        callbacks={'on_before_idle': ready_for_change},
        initial='idle',
        state_field='state',
    )

    def __init__(self):
        # pin assignments
        self.ORANGE_PIN = 6
        self.YELLOW_PIN = 13
        self.GREEN_PIN = 19
        self.AUX_PIN = 26

        GPIO.setup(self.ORANGE_PIN, GPIO.OUT)
        GPIO.setup(self.YELLOW_PIN, GPIO.OUT)
        GPIO.setup(self.GREEN_PIN, GPIO.OUT)
        GPIO.setup(self.AUX_PIN, GPIO.OUT)

        self.SAFETY_TIMER = 300  # minimum seconds between state changes, protects compressor
        self.last_state_change = 0

        self.state = 'idle'
        super(HVAC, self).__init__()
        self.onchangestate = self.printstatechange

    def printstatechange(self, e):
        print('change from {}, to {}'.format(e.src, e.dst))
        last_state_change = time.time()

    def set_state(self, target_state):

        try:
            print("setting state")
            self.state = target_state
        except:
            print("FAILED")

        if (time.time() - self.last_state_change) > self.SAFETY_TIMER:
            print("enough time has passed sinced last state change")
            self.last_state_change = time.time()

            print("setting state, current state = {}".format(self.current))

            if self.is_state("cool"):
                print("COOLING")
                GPIO.output(self.ORANGE_PIN, True)
                GPIO.output(self.YELLOW_PIN, True)
                GPIO.output(self.GREEN_PIN, True)
                GPIO.output(self.AUX_PIN, False)
            elif self.current == "heat":
                print("HEATING")
                GPIO.output(self.ORANGE_PIN, False)
                GPIO.output(self.YELLOW_PIN, True)
                GPIO.output(self.GREEN_PIN, True)
                GPIO.output(self.AUX_PIN, False)
            elif self.current == "fan":
                GPIO.output(self.ORANGE_PIN, False)
                GPIO.output(self.YELLOW_PIN, False)
                GPIO.output(self.GREEN_PIN, True)
                GPIO.output(self.AUX_PIN, False)
            elif self.current == "aux":
                GPIO.output(self.ORANGE_PIN, False)
                GPIO.output(self.YELLOW_PIN, True)
                GPIO.output(self.GREEN_PIN, True)
                GPIO.output(self.AUX_PIN, True)
            elif self.current == "idle":
                print("IDLE")
                GPIO.output(self.ORANGE_PIN, False)
                GPIO.output(self.YELLOW_PIN, False)
                GPIO.output(self.GREEN_PIN, False)
                GPIO.output(self.AUX_PIN, False)
            else:
                GPIO.output(self.ORANGE_PIN, False)
                GPIO.output(self.YELLOW_PIN, False)
                GPIO.output(self.GREEN_PIN, False)
                GPIO.output(self.AUX_PIN, False)