Exemplo n.º 1
0
def check_action_params(
    scene: CachedScene, project: CachedProject, action: common.Action, object_action: ObjectAction
) -> None:

    _, action_type = action.parse_type()

    assert action_type == object_action.name

    if len(object_action.parameters) != len(action.parameters):
        raise Arcor2Exception("Unexpected number of parameters.")

    for req_param in object_action.parameters:

        param = action.parameter(req_param.name)

        if param.type == common.ActionParameter.TypeEnum.CONSTANT:

            const = project.constant(param.str_from_value())

            param_meta = object_action.parameter(param.name)
            if param_meta.type != const.type:
                raise Arcor2Exception("Param type does not match constant type.")

        elif param.type == common.ActionParameter.TypeEnum.LINK:

            parsed_link = param.parse_link()

            if parsed_link.action_id == action.id:
                raise Arcor2Exception("Can't use own result as a parameter.")

            outputs = project.action(parsed_link.action_id).flow(parsed_link.flow_name).outputs

            assert len(outputs) == len(object_action.returns)

            param_meta = object_action.parameter(param.name)
            if param_meta.type != object_action.returns[parsed_link.output_index]:
                raise Arcor2Exception("Param type does not match action output type.")

        else:

            if param.type not in known_parameter_types():
                raise Arcor2Exception(f"Parameter {param.name} of action {action.name} has unknown type: {param.type}.")

            try:
                plugin_from_type_name(param.type).parameter_value(
                    get_types_dict(), scene, project, action.id, param.name
                )
            except ParameterPluginException as e:
                raise Arcor2Exception(f"Parameter {param.name} of action {action.name} has invalid value. {str(e)}")
Exemplo n.º 2
0
def check_action_params(scene: CachedScene, project: CachedProject,
                        action: common.Action,
                        object_action: ObjectAction) -> None:

    _, action_type = action.parse_type()

    assert action_type == object_action.name

    if len(object_action.parameters) != len(action.parameters):
        raise Arcor2Exception("Unexpected number of parameters.")

    for req_param in object_action.parameters:

        param = action.parameter(req_param.name)

        if param.type == common.ActionParameter.TypeEnum.PROJECT_PARAMETER:

            pparam = project.parameter(param.str_from_value())

            param_meta = object_action.parameter(param.name)
            if param_meta.type != pparam.type:
                raise Arcor2Exception(
                    "Action parameter type does not match project parameter type."
                )

        elif param.type == common.ActionParameter.TypeEnum.LINK:

            parsed_link = param.parse_link()

            if parsed_link.action_id == action.id:
                raise Arcor2Exception("Can't use own result as a parameter.")

            parent_action = project.action(parsed_link.action_id)
            source_action_pt = parent_action.parse_type()

            parent_action_meta = glob.OBJECT_TYPES[scene.object(
                source_action_pt.obj_id).type].actions[
                    source_action_pt.action_type]

            if len(parent_action.flow(parsed_link.flow_name).outputs) != len(
                    parent_action_meta.returns):
                raise Arcor2Exception(
                    "Source action does not have outputs specified.")

            param_meta = object_action.parameter(param.name)

            try:
                if param_meta.type != parent_action_meta.returns[
                        parsed_link.output_index]:
                    raise Arcor2Exception(
                        "Param type does not match action output type.")
            except IndexError:
                raise Arcor2Exception(
                    f"Index {parsed_link.output_index} is invalid for action {object_action.name},"
                    f" which returns {len(object_action.returns)} values.")

        else:

            if param.type not in known_parameter_types():
                raise Arcor2Exception(
                    f"Parameter {param.name} of action {action.name} has unknown type: {param.type}."
                )

            try:
                plugin_from_type_name(param.type).parameter_value(
                    get_types_dict(), scene, project, action.id, param.name)
            except ParameterPluginException as e:
                raise Arcor2Exception(
                    f"Parameter {param.name} of action {action.name} has invalid value. {str(e)}"
                )
Exemplo n.º 3
0
def object_actions(type_def: Type[Generic], tree: AST) -> Dict[str, ObjectAction]:

    ret: Dict[str, ObjectAction] = {}

    # ...inspect.ismethod does not work on un-initialized classes
    for method_name, method_def in iterate_over_actions(type_def):

        meta: ActionMetadata = method_def.__action__  # type: ignore

        data = ObjectAction(name=method_name, meta=meta)

        if method_name in type_def.CANCEL_MAPPING:
            meta.cancellable = True

        try:

            if not method_def.__doc__:
                doc = {}
            else:
                doc = parse_docstring(method_def.__doc__)
                doc_short = doc["short_description"]
                if doc_short:
                    data.description = doc_short

            signature = inspect.signature(method_def)  # sig.parameters is OrderedDict

            try:
                method_tree = find_function(method_name, tree)
            except SourceException:
                # function is probably defined in predecessor, will be added later
                continue

            hints = get_type_hints(method_def)  # standard (unordered) dict

            if "an" not in signature.parameters.keys():
                raise IgnoreActionException("Action is missing 'an' parameter.")

            try:
                if hints["an"] != Optional[str]:
                    raise IgnoreActionException("Parameter 'an' has invalid type annotation.")
            except KeyError:
                raise IgnoreActionException("Parameter 'an' is missing type annotation.")

            parameter_names_without_self = list(signature.parameters.keys())[1:]

            if not parameter_names_without_self or parameter_names_without_self[-1] != "an":
                raise IgnoreActionException("The 'an' parameter have to be the last one.")

            # handle return
            try:
                return_ttype = hints["return"]
            except KeyError:
                raise IgnoreActionException("Action is missing return type annotation.")

            # ...just ignore NoneType for returns
            if return_ttype != type(None):  # noqa: E721

                if typing_inspect.is_tuple_type(return_ttype):
                    for arg in typing_inspect.get_args(return_ttype):
                        resolved_param = plugin_from_type(arg)
                        if resolved_param is None:
                            raise IgnoreActionException("None in return tuple is not supported.")
                        data.returns.append(resolved_param.type_name())
                else:
                    # TODO resolving needed for e.g. enums - add possible values to action metadata somewhere?
                    data.returns = [plugin_from_type(return_ttype).type_name()]

            for name in parameter_names_without_self[:-1]:  # omit also an

                try:
                    ttype = hints[name]
                except KeyError:
                    raise IgnoreActionException(f"Parameter {name} is missing type annotation.")

                param_type = plugin_from_type(ttype)

                assert param_type is not None

                args = ParameterMeta(name=name, type=param_type.type_name())
                try:
                    param_type.meta(args, method_def, method_tree)
                except ParameterPluginException as e:
                    raise IgnoreActionException(e) from e

                if name in type_def.DYNAMIC_PARAMS:
                    args.dynamic_value = True
                    dvp = type_def.DYNAMIC_PARAMS[name][1]
                    if dvp:
                        args.dynamic_value_parents = dvp

                def_val = signature.parameters[name].default
                if def_val is not inspect.Parameter.empty:
                    args.default_value = param_type.value_to_json(def_val)

                try:
                    args.description = doc["params"][name].strip()
                except KeyError:
                    pass

                data.parameters.append(args)

        except Arcor2Exception as e:
            data.disabled = True
            data.problem = str(e)
            glob.logger.warn(f"Disabling action {method_name} of  {type_def.__name__}. {str(e)}")

        ret[data.name] = data

    return ret