Ejemplo n.º 1
0
    def _execute(self, execute_inputs, execute_outputs, backward_execution=False):
        """Calls the custom execute function of the script.py of the state"""

        plugins.run_hook('pre_script')
        outcome_item = self._script.execute(self, execute_inputs, execute_outputs, backward_execution)
        plugins.run_hook('post_script')

        # in the case of backward execution the outcome is not relevant
        if backward_execution:
            return

        # If the state was preempted, the state must be left on the preempted outcome
        if self.preempted:
            return Outcome(-2, "preempted")

        # Outcome id was returned
        if outcome_item in self.outcomes:
            return self.outcomes[outcome_item]

        # Outcome name was returned
        for outcome_id, outcome in self.outcomes.items():
            if outcome.name == outcome_item:
                return self.outcomes[outcome_id]

        logger.error("Returned outcome of {0} not existing: {1}".format(self, outcome_item))
        return Outcome(-1, "aborted")
Ejemplo n.º 2
0
    def _finalize_hierarchy(self):
        """ This function finalizes the execution of a hierarchy state. It sets the correct status and manages
        the output data handling.
        :return:
        """
        if self.last_child:
            self.last_child.state_execution_status = StateExecutionStatus.INACTIVE

        if not self.backward_execution:
            if self.last_error:
                self.output_data['error'] = copy.deepcopy(self.last_error)
            self.write_output_data()
            self.check_output_data_type()
            self.execution_history.push_return_history_item(self, CallType.CONTAINER, self, self.output_data)
            # add error message from child_state to own output_data

        self.state_execution_status = StateExecutionStatus.WAIT_FOR_NEXT_STATE

        if self.preempted:
            self.final_outcome = Outcome(-2, "preempted")

        self.child_state = None
        self.last_child = None

        return self.finalize(self.final_outcome)
Ejemplo n.º 3
0
    def run(self):
        """ This defines the sequence of actions that are taken when the hierarchy is executed. A hierarchy state
        executes all its child states recursively. Principally this code collects all input data for the next
        child state, executes it, stores its output data and determines the next state
        based on the outcome of the child state.
        :return:
        """

        try:
            self._initialize_hierarchy()
            while self.child_state is not self:
                self.handling_execution_mode = True
                execution_mode = singleton.state_machine_execution_engine.handle_execution_mode(self, self.child_state)

                # in the case of starting the sm from a specific state not the transitions define the logic flow
                # but the the execution_engine.run_to_states; thus, do not alter the next state in this case
                if not self._start_state_modified:
                    # check if e.g. the state machine was paused and the next state was modified (e.g. removed)
                    self.check_if_child_state_was_modified()

                self.handling_execution_mode = False
                if self.state_execution_status is not StateExecutionStatus.EXECUTE_CHILDREN:
                    self.state_execution_status = StateExecutionStatus.EXECUTE_CHILDREN
                self.backward_execution = False  # TODO: why is this line needed?
                if self.preempted:
                    if self.last_transition and self.last_transition.from_outcome == -2:
                        logger.debug("Execute preemption handling for '{0}'".format(self.child_state))
                    else:
                        break
                elif execution_mode == StateMachineExecutionStatus.BACKWARD:
                    break_loop = self._handle_backward_execution_before_child_execution()
                    if break_loop:
                        break
                # This is only the case if this hierarchy-state is started in backward mode,
                # but the user directly switches to the forward execution mode
                if self.child_state is None:
                    break

                self._execute_current_child()

                if self.backward_execution:
                    break_loop = self._handle_backward_execution_after_child_execution()
                    if break_loop:
                        break
                else:
                    break_loop = self._handle_forward_execution_after_child_execution()
                    if break_loop:
                        break
            return self._finalize_hierarchy()

        except Exception as e:
            logger.exception("{0} had an internal error:".format(self))
            self.output_data["error"] = e
            self.state_execution_status = StateExecutionStatus.WAIT_FOR_NEXT_STATE
            self.child_state = None
            self.last_child = None
            return self.finalize(Outcome(-1, "aborted"))
Ejemplo n.º 4
0
    def run(self):
        """ This defines the sequence of actions that are taken when the execution state is executed

        :return:
        """
        if self.is_root_state:
            self.execution_history.push_call_history_item(
                self, CallType.EXECUTE, None, self.input_data)

        logger.debug("Running {0}{1}".format(
            self, " (backwards)" if self.backward_execution else ""))
        if self.backward_execution:
            self.setup_backward_run()
        else:
            self.setup_run()

        try:
            outcome = self._execute(self.input_data, self.output_data,
                                    self.backward_execution)
            self.state_execution_status = StateExecutionStatus.WAIT_FOR_NEXT_STATE

            if self.backward_execution:
                # outcome handling is not required as we are in backward mode and the execution order is fixed
                result = self.finalize()
            else:
                # check output data
                self.check_output_data_type()
                result = self.finalize(outcome)

            if self.is_root_state:
                self.execution_history.push_return_history_item(
                    self, CallType.EXECUTE, None, self.output_data)
            return result
        except Exception as e:
            exc_type, exc_value, exc_traceback = sys.exc_info()
            formatted_exc = traceback.format_exception(exc_type, exc_value,
                                                       exc_traceback)
            truncated_exc = []
            for line in formatted_exc:
                if os.path.join("rafcon", "core") not in line:
                    truncated_exc.append(line)
            logger.error("{0} had an internal error: {1}: {2}\n{3}".format(
                self,
                type(e).__name__, e, ''.join(truncated_exc)))
            # write error to the output_data of the state
            self.output_data["error"] = e
            self.state_execution_status = StateExecutionStatus.WAIT_FOR_NEXT_STATE
            return self.finalize(Outcome(-1, "aborted"))
Ejemplo n.º 5
0
    def finalize_concurrency_state(self, outcome):
        """ Utility function to finalize the forward execution of the concurrency state.

        :param outcome:
        :return:
        """
        final_outcome = outcome
        self.write_output_data()
        self.check_output_data_type()
        self.execution_history.push_return_history_item(self, CallType.CONTAINER, self, self.output_data)
        self.state_execution_status = StateExecutionStatus.WAIT_FOR_NEXT_STATE

        singleton.state_machine_execution_engine.modify_run_to_states(self)

        if self.preempted:
            final_outcome = Outcome(-2, "preempted")
        return self.finalize(final_outcome)
Ejemplo n.º 6
0
    def run(self):
        """ This defines the sequence of actions that are taken when the barrier concurrency state is executed

        :return:
        """
        logger.debug("Starting execution of {0}{1}".format(self, " (backwards)" if self.backward_execution else ""))
        self.setup_run()

        # data to be accessed by the decider state
        child_errors = {}
        final_outcomes_dict = {}
        decider_state = self.states[UNIQUE_DECIDER_STATE_ID]

        try:
            concurrency_history_item = self.setup_forward_or_backward_execution()
            self.start_child_states(concurrency_history_item, decider_state)
            #######################################################
            # wait for all child threads to finish
            #######################################################
            for history_index, state in enumerate(self.states.values()):
                # skip the decider state
                if state is not decider_state:
                    self.join_state(state, history_index, concurrency_history_item)
                    self.add_state_execution_output_to_scoped_data(state.output_data, state)
                    self.update_scoped_variables_with_output_dictionary(state.output_data, state)
                    # save the errors of the child state executions for the decider state
                    if 'error' in state.output_data:
                        child_errors[state.state_id] = (state.name, state.output_data['error'])
                    final_outcomes_dict[state.state_id] = (state.name, state.final_outcome)
            #######################################################
            # handle backward execution case
            #######################################################
            if self.backward_execution:
                return self.finalize_backward_execution()
            else:
                self.backward_execution = False
            #######################################################
            # execute decider state
            #######################################################
            decider_state_error = self.run_decider_state(decider_state, child_errors, final_outcomes_dict)
            #######################################################
            # handle no transition
            #######################################################
            transition = self.get_transition_for_outcome(decider_state, decider_state.final_outcome)
            if transition is None:
                # final outcome is set here
                transition = self.handle_no_transition(decider_state)
            # if the transition is still None, then the child_state was preempted or aborted, in this case return
            decider_state.state_execution_status = StateExecutionStatus.INACTIVE
            if transition is None:
                self.output_data["error"] = RuntimeError("state aborted")
            else:
                if decider_state_error:
                    self.output_data["error"] = decider_state_error
                self.final_outcome = self.outcomes[transition.to_outcome]
            return self.finalize_concurrency_state(self.final_outcome)

        except Exception as e:
            logger.exception("{0} had an internal error:".format(self))
            self.output_data["error"] = e
            self.state_execution_status = StateExecutionStatus.WAIT_FOR_NEXT_STATE
            return self.finalize(Outcome(-1, "aborted"))
Ejemplo n.º 7
0
    def run(self):
        """ This defines the sequence of actions that are taken when the preemptive concurrency state is executed

        :return:
        """
        logger.debug("Starting execution of {0}{1}".format(
            self, " (backwards)" if self.backward_execution else ""))
        self.setup_run()

        try:
            concurrency_history_item = self.setup_forward_or_backward_execution(
            )
            concurrency_queue = self.start_child_states(
                concurrency_history_item)

            #######################################################
            # wait for the first threads to finish
            #######################################################
            finished_thread_id = concurrency_queue.get()
            finisher_state = self.states[finished_thread_id]
            finisher_state.join()

            # preempt all child states
            if not self.backward_execution:
                for state_id, state in self.states.items():
                    state.recursively_preempt_states()
            # join all states
            for history_index, state in enumerate(self.states.values()):
                self.join_state(state, history_index, concurrency_history_item)
                self.add_state_execution_output_to_scoped_data(
                    state.output_data, state)
                self.update_scoped_variables_with_output_dictionary(
                    state.output_data, state)

            # add the data of the first state now to overwrite data of the preempted states
            self.add_state_execution_output_to_scoped_data(
                finisher_state.output_data, finisher_state)
            self.update_scoped_variables_with_output_dictionary(
                finisher_state.output_data, finisher_state)
            #######################################################
            # handle backward execution case
            #######################################################
            if self.states[finished_thread_id].backward_execution:
                return self.finalize_backward_execution()

            else:
                self.backward_execution = False

            #######################################################
            # handle no transition
            #######################################################
            transition = self.get_transition_for_outcome(
                self.states[finished_thread_id],
                self.states[finished_thread_id].final_outcome)
            if transition is None:
                # final outcome is set here
                transition = self.handle_no_transition(
                    self.states[finished_thread_id])
            # it the transition is still None, then the state was preempted or aborted, in this case return
            if transition is None:
                self.output_data["error"] = RuntimeError("state aborted")
            else:
                if 'error' in self.states[finished_thread_id].output_data:
                    self.output_data["error"] = self.states[
                        finished_thread_id].output_data['error']
                self.final_outcome = self.outcomes[transition.to_outcome]

            return self.finalize_concurrency_state(self.final_outcome)

        except Exception as e:
            logger.exception("{0} had an internal error:".format(self))
            self.output_data["error"] = e
            self.state_execution_status = StateExecutionStatus.WAIT_FOR_NEXT_STATE
            return self.finalize(Outcome(-1, "aborted"))
Ejemplo n.º 8
0
def load_state_recursively(parent, state_path=None, dirty_states=[]):
    """Recursively loads the state

    It calls this method on each sub-state of a container state.

    :param parent:  the root state of the last load call to which the loaded state will be added
    :param state_path: the path on the filesystem where to find the meta file for the state
    :param dirty_states: a dict of states which changed during loading
    :return:
    """
    from rafcon.core.states.execution_state import ExecutionState
    from rafcon.core.states.container_state import ContainerState
    from rafcon.core.states.hierarchy_state import HierarchyState
    from rafcon.core.singleton import library_manager

    path_core_data = get_core_data_path(state_path)
    path_meta_data = get_meta_data_path(state_path)

    logger.debug("Load state recursively: {0}".format(str(state_path)))

    try:
        state_info = load_data_file(path_core_data)
    except ValueError as e:
        logger.exception("Error while loading state data: {0}".format(e))
        return
    except LibraryNotFoundException as e:
        if global_config.get_config_value(
                "RAISE_ERROR_ON_MISSING_LIBRARY_STATES",
                False) or not library_manager.show_dialog:
            raise
        logger.error(
            "Library could not be loaded: {0}\n"
            "Skipping library and continuing loading the state machine".format(
                e))
        state_info = storage_utils.load_objects_from_json(path_core_data,
                                                          as_dict=True)
        missing_library_meta_data = None
        if os.path.exists(path_meta_data):
            missing_library_meta_data = Vividict(
                storage_utils.load_objects_from_json(path_meta_data))
        state_id = state_info["state_id"]
        outcomes = {
            outcome['outcome_id']: Outcome(outcome['outcome_id'],
                                           outcome['name'])
            for outcome in state_info["outcomes"].values()
        }
        dummy_state = HierarchyState(
            LIBRARY_NOT_FOUND_DUMMY_STATE_NAME,
            state_id=state_id,
            outcomes=outcomes,
            is_dummy=True,
            missing_library_meta_data=missing_library_meta_data)
        library_name = state_info['library_name']
        path_parts = os.path.join(state_info['library_path'],
                                  library_name).split(os.sep)
        dummy_state.description = 'The Missing Library Path: %s\nThe Missing Library Name: %s\n\n' % (
            state_info['library_path'], library_name)
        from rafcon.core.singleton import library_manager
        if path_parts[0] in library_manager.library_root_paths:
            dummy_state.description += 'The Missing Library OS Path: %s' % os.path.join(
                library_manager.library_root_paths[path_parts[0]], *
                path_parts[1:])
        else:
            dummy_state.description += 'The missing library was located in the missing library root "%s"' % path_parts[
                0]
        # set parent of dummy state
        if isinstance(parent, ContainerState):
            parent.add_state(dummy_state, storage_load=True)
        else:
            dummy_state.parent = parent
        return dummy_state
    except LibraryNotFoundSkipException:
        return None

    # Transitions and data flows are not added when loading a state, as also states are not added.
    # We have to wait until the child states are loaded, before adding transitions and data flows, as otherwise the
    # validity checks for transitions and data flows would fail
    if not isinstance(state_info, tuple):
        state = state_info
    else:
        state = state_info[0]
        transitions = state_info[1]
        data_flows = state_info[2]

    # set parent of state
    if parent is not None and isinstance(parent, ContainerState):
        parent.add_state(state, storage_load=True)
    else:
        state.parent = parent

    # read script file if state is an ExecutionState
    if isinstance(state, ExecutionState):
        script_text = read_file(state_path, state.script.filename)
        state.script.set_script_without_compilation(script_text)

    # load semantic data
    try:
        semantic_data = load_data_file(
            os.path.join(state_path, SEMANTIC_DATA_FILE))
        state.semantic_data = semantic_data
    except Exception as e:
        # semantic data file does not have to be there
        pass

    # load child states
    for p in os.listdir(state_path):
        child_state_path = os.path.join(state_path, p)
        if os.path.isdir(child_state_path):
            if not os.path.exists(
                    os.path.join(child_state_path, FILE_NAME_CORE_DATA)):
                # this means that child_state_path is a folder, not containing a valid state
                # this also happens when pip creates __pycache__ folders for the script.py files upon installing rafcon
                continue
            child_state = load_state_recursively(state, child_state_path,
                                                 dirty_states)
            if not child_state:
                return None

    # Now we can add transitions and data flows, as all child states were added
    if isinstance(state_info, tuple):
        safe_init = global_config.get_config_value("LOAD_SM_WITH_CHECKS", True)
        if safe_init:
            # this will trigger all validity checks the state machine
            state.transitions = transitions
        else:
            state._transitions = transitions
            state._data_flows = data_flows
        for _, transition in state.transitions.items():
            transition._parent = ref(state)
        state._data_flows = data_flows
        for _, data_flow in state.data_flows.items():
            data_flow._parent = ref(state)

    state.file_system_path = state_path

    if state.marked_dirty:
        dirty_states.append(state)

    return state