(self, states, on_enter=None, on_exit=None,
                  ignore_invalid_triggers=None, parent=None, remap=None)
return new_states
Parses passed value to build a nested state structure recursively.
        Args:
            states (list, str, dict, or State): a list, a State instance, the
                name of a new state, or a dict with keywords to pass on to the
                State initializer. If a list, each element can be of any of the
                latter three types.
            on_enter (str or list): callbacks to trigger when the state is
                entered. Only valid if first argument is string.
            on_exit (str or list): callbacks to trigger when the state is
                exited. Only valid if first argument is string.
            ignore_invalid_triggers: when True, any calls to trigger methods
                that are not valid for the present state (e.g., calling an
                a_to_b() trigger when the current state is c) will be silently
                ignored rather than raising an invalid transition exception.
                Note that this argument takes precedence over the same
                argument defined at the Machine level, and is in turn
                overridden by any ignore_invalid_triggers explicitly
                passed in an individual state's initialization arguments.
            parent (NestedState or str): parent state for nested states.
            remap (dict): reassigns transitions named `key from nested machines to parent state `value`.
        Returns: list of new `NestedState` objects
Parses passed value to build a nested state structure recursively.
        Args:
            states (list, str, dict, or State): a list, a State instance, the
                name of a new state, or a dict with keywords to pass on to the
                State initializer. If a list, each element can be of any of the
                latter three types.
            on_enter (str or list): callbacks to trigger when the state is
                entered. Only valid if first argument is string.
            on_exit (str or list): callbacks to trigger when the state is
                exited. Only valid if first argument is string.
            ignore_invalid_triggers: when True, any calls to trigger methods
                that are not valid for the present state (e.g., calling an
                a_to_b() trigger when the current state is c) will be silently
                ignored rather than raising an invalid transition exception.
                Note that this argument takes precedence over the same
                argument defined at the Machine level, and is in turn
                overridden by any ignore_invalid_triggers explicitly
                passed in an individual state's initialization arguments.
            parent (NestedState or str): parent state for nested states.
            remap (dict): reassigns transitions named `key from nested machines to parent state `value`.
        Returns: list of new `NestedState` objects
Parses passed value to build a nested state structure recursively . Args : states ( list str dict or State ) : a list a State instance the name of a new state or a dict with keywords to pass on to the State initializer . If a list each element can be of any of the latter three types . on_enter ( str or list ) : callbacks to trigger when the state is entered . Only valid if first argument is string . on_exit ( str or list ) : callbacks to trigger when the state is exited . Only valid if first argument is string . ignore_invalid_triggers : when True any calls to trigger methods that are not valid for the present state ( e . g . calling an a_to_b () trigger when the current state is c ) will be silently ignored rather than raising an invalid transition exception . Note that this argument takes precedence over the same argument defined at the Machine level and is in turn overridden by any ignore_invalid_triggers explicitly passed in an individual state s initialization arguments . parent ( NestedState or str ) : parent state for nested states . remap ( dict ) : reassigns transitions named key from nested machines to parent state value . Returns : list of new NestedState objects
def _traverse(self, states, on_enter=None, on_exit=None,
                  ignore_invalid_triggers=None, parent=None, remap=None):
        """ Parses passed value to build a nested state structure recursively.
        Args:
            states (list, str, dict, or State): a list, a State instance, the
                name of a new state, or a dict with keywords to pass on to the
                State initializer. If a list, each element can be of any of the
                latter three types.
            on_enter (str or list): callbacks to trigger when the state is
                entered. Only valid if first argument is string.
            on_exit (str or list): callbacks to trigger when the state is
                exited. Only valid if first argument is string.
            ignore_invalid_triggers: when True, any calls to trigger methods
                that are not valid for the present state (e.g., calling an
                a_to_b() trigger when the current state is c) will be silently
                ignored rather than raising an invalid transition exception.
                Note that this argument takes precedence over the same
                argument defined at the Machine level, and is in turn
                overridden by any ignore_invalid_triggers explicitly
                passed in an individual state's initialization arguments.
            parent (NestedState or str): parent state for nested states.
            remap (dict): reassigns transitions named `key from nested machines to parent state `value`.
        Returns: list of new `NestedState` objects
        """
        states = listify(states)
        new_states = []
        ignore = ignore_invalid_triggers
        remap = {} if remap is None else remap
        parent = self.get_state(parent) if isinstance(parent, (string_types, Enum)) else parent

        if ignore is None:
            ignore = self.ignore_invalid_triggers
        for state in states:
            tmp_states = []
            # other state representations are handled almost like in the base class but a parent parameter is added
            if isinstance(state, (string_types, Enum)):
                if state in remap:
                    continue
                tmp_states.append(self._create_state(state, on_enter=on_enter, on_exit=on_exit, parent=parent,
                                                     ignore_invalid_triggers=ignore))
            elif isinstance(state, dict):
                if state['name'] in remap:
                    continue

                # shallow copy the dictionary to alter/add some parameters
                state = copy(state)
                if 'ignore_invalid_triggers' not in state:
                    state['ignore_invalid_triggers'] = ignore
                if 'parent' not in state:
                    state['parent'] = parent

                try:
                    state_children = state.pop('children')  # throws KeyError when no children set
                    state_remap = state.pop('remap', None)
                    state_parent = self._create_state(**state)
                    nested = self._traverse(state_children, parent=state_parent, remap=state_remap)
                    tmp_states.append(state_parent)
                    tmp_states.extend(nested)
                except KeyError:
                    tmp_states.insert(0, self._create_state(**state))
            elif isinstance(state, HierarchicalMachine):
                # set initial state of parent if it is None
                if parent.initial is None:
                    parent.initial = state.initial
                # (deep) copy only states not mentioned in remap
                copied_states = [s for s in deepcopy(state.states).values() if s.name not in remap]
                # inner_states are the root states of the passed machine
                # which have be attached to the parent
                inner_states = [s for s in copied_states if s.level == 0]
                for inner in inner_states:
                    inner.parent = parent
                tmp_states.extend(copied_states)
                for trigger, event in state.events.items():
                    if trigger.startswith('to_'):
                        path = trigger[3:].split(self.state_cls.separator)
                        # do not copy auto_transitions since they would not be valid anymore;
                        # trigger and destination do not exist in the new environment
                        if path[0] in remap:
                            continue
                        ppath = parent.name.split(self.state_cls.separator)
                        path = ['to_' + ppath[0]] + ppath[1:] + path
                        trigger = '.'.join(path)
                    # (deep) copy transitions and
                    # adjust all transition start and end points to new state names
                    for transitions in deepcopy(event.transitions).values():
                        for transition in transitions:
                            src = transition.source
                            # transitions from remapped states will be filtered to prevent
                            # unexpected behaviour in the parent machine
                            if src in remap:
                                continue
                            dst = parent.name + self.state_cls.separator + transition.dest\
                                if transition.dest not in remap else remap[transition.dest]
                            conditions, unless = [], []
                            for cond in transition.conditions:
                                # split a list in two lists based on the accessors (cond.target) truth value
                                (unless, conditions)[cond.target].append(cond.func)
                            self._buffered_transitions.append({'trigger': trigger,
                                                               'source': parent.name + self.state_cls.separator + src,
                                                               'dest': dst,
                                                               'conditions': conditions,
                                                               'unless': unless,
                                                               'prepare': transition.prepare,
                                                               'before': transition.before,
                                                               'after': transition.after})

            elif isinstance(state, NestedState):
                tmp_states.append(state)
                if state.children:
                    tmp_states.extend(self._traverse(state.children, on_enter=on_enter, on_exit=on_exit,
                                                     ignore_invalid_triggers=ignore_invalid_triggers,
                                                     parent=state, remap=remap))
            else:
                raise ValueError("%s is not an instance or subclass of NestedState "
                                 "required by HierarchicalMachine." % state)
            new_states.extend(tmp_states)

        duplicate_check = []
        for new in new_states:
            if new.name in duplicate_check:
                # collect state names for the following error message
                state_names = [s.name for s in new_states]
                raise ValueError("State %s cannot be added since it is already in state list %s."
                                 % (new.name, state_names))
            else:
                duplicate_check.append(new.name)
        return new_states
def _traverse ( self , states , on_enter = None , on_exit = None , ignore_invalid_triggers = None , parent = None , remap = None ) : states = listify ( states ) new_states = [ ] ignore = ignore_invalid_triggers remap = { } if remap is None else remap parent = self . get_state ( parent ) if isinstance ( parent , ( string_types , Enum ) ) else parent if ignore is None : ignore = self . ignore_invalid_triggers for state in states : tmp_states = [ ] # other state representations are handled almost like in the base class but a parent parameter is added if isinstance ( state , ( string_types , Enum ) ) : if state in remap : continue tmp_states . append ( self . _create_state ( state , on_enter = on_enter , on_exit = on_exit , parent = parent , ignore_invalid_triggers = ignore ) ) elif isinstance ( state , dict ) : if state [ 'name' ] in remap : continue # shallow copy the dictionary to alter/add some parameters state = copy ( state ) if 'ignore_invalid_triggers' not in state : state [ 'ignore_invalid_triggers' ] = ignore if 'parent' not in state : state [ 'parent' ] = parent try : state_children = state . pop ( 'children' ) # throws KeyError when no children set state_remap = state . pop ( 'remap' , None ) state_parent = self . _create_state ( * * state ) nested = self . _traverse ( state_children , parent = state_parent , remap = state_remap ) tmp_states . append ( state_parent ) tmp_states . extend ( nested ) except KeyError : tmp_states . insert ( 0 , self . _create_state ( * * state ) ) elif isinstance ( state , HierarchicalMachine ) : # set initial state of parent if it is None if parent . initial is None : parent . initial = state . initial # (deep) copy only states not mentioned in remap copied_states = [ s for s in deepcopy ( state . states ) . values ( ) if s . name not in remap ] # inner_states are the root states of the passed machine # which have be attached to the parent inner_states = [ s for s in copied_states if s . level == 0 ] for inner in inner_states : inner . parent = parent tmp_states . extend ( copied_states ) for trigger , event in state . events . items ( ) : if trigger . startswith ( 'to_' ) : path = trigger [ 3 : ] . split ( self . state_cls . separator ) # do not copy auto_transitions since they would not be valid anymore; # trigger and destination do not exist in the new environment if path [ 0 ] in remap : continue ppath = parent . name . split ( self . state_cls . separator ) path = [ 'to_' + ppath [ 0 ] ] + ppath [ 1 : ] + path trigger = '.' . join ( path ) # (deep) copy transitions and # adjust all transition start and end points to new state names for transitions in deepcopy ( event . transitions ) . values ( ) : for transition in transitions : src = transition . source # transitions from remapped states will be filtered to prevent # unexpected behaviour in the parent machine if src in remap : continue dst = parent . name + self . state_cls . separator + transition . dest if transition . dest not in remap else remap [ transition . dest ] conditions , unless = [ ] , [ ] for cond in transition . conditions : # split a list in two lists based on the accessors (cond.target) truth value ( unless , conditions ) [ cond . target ] . append ( cond . func ) self . _buffered_transitions . append ( { 'trigger' : trigger , 'source' : parent . name + self . state_cls . separator + src , 'dest' : dst , 'conditions' : conditions , 'unless' : unless , 'prepare' : transition . prepare , 'before' : transition . before , 'after' : transition . after } ) elif isinstance ( state , NestedState ) : tmp_states . append ( state ) if state . children : tmp_states . extend ( self . _traverse ( state . children , on_enter = on_enter , on_exit = on_exit , ignore_invalid_triggers = ignore_invalid_triggers , parent = state , remap = remap ) ) else : raise ValueError ( "%s is not an instance or subclass of NestedState " "required by HierarchicalMachine." % state ) new_states . extend ( tmp_states ) duplicate_check = [ ] for new in new_states : if new . name in duplicate_check : # collect state names for the following error message state_names = [ s . name for s in new_states ] raise ValueError ( "State %s cannot be added since it is already in state list %s." % ( new . name , state_names ) ) else : duplicate_check . append ( new . name ) return new_states