Пример #1
0
def function_implemented(tree: AST, func_name: str) -> bool:
    """Body of unimplemented function (e.g. object/service feature) contains
    only 'raise Arcor2NotImplemented()'.

    :param tree:
    :return:
    """

    try:
        func_def = find_function(func_name, tree)
    except SourceException:
        return False

    raises = find_raises(func_def)

    if len(raises) != 1:
        return True

    exc = raises[0].exc

    if isinstance(exc, Call):
        # raise Arcor2NotImplemented("something")

        assert isinstance(exc.func, Name)

        if exc.func.id == Arcor2NotImplemented.__name__:
            return False

    if isinstance(exc, Name) and exc.id == Arcor2NotImplemented.__name__:
        # raise Arcor2NotImplemented
        return False

    return True
Пример #2
0
def test_meta() -> None:

    meta = ParameterMeta(param_name, StringEnumPlugin.type_name())
    StringEnumPlugin.meta(meta, TestObject.action, find_function(TestObject.action.__name__, parse_def(TestObject)))
    assert meta.extra

    extra = IntegerEnumExtra.from_json(meta.extra)

    assert extra.allowed_values == TestEnum.set()
Пример #3
0
def main_loop(tree: Module) -> While:
    main = find_function("main", tree)

    for node in main.body:
        if isinstance(
                node, While
        ):  # TODO more specific condition (test for True argument)
            return node

    raise SourceException("Main loop not found.")
Пример #4
0
def object_instance_from_res(
        tree: Module, object_name: str, object_id: str, cls_name: str,
        cls_type: Union[Literal["objects"], Literal["services"]]) -> None:

    main_body = find_function("main", tree).body
    last_assign_idx = -1

    for body_idx, body_item in enumerate(main_body):

        if isinstance(body_item, (Assign, AnnAssign)):
            last_assign_idx = body_idx

    assign = AnnAssign(target=Name(id=fix_object_name(object_name),
                                   ctx=Store()),
                       annotation=Name(id=cls_name, ctx=Load()),
                       value=Subscript(
                           value=get_name_attr('res', cls_type),
                           slice=Index(value=Str(s=object_id, kind='')),
                           ctx=Load()),
                       simple=1)

    main_body.insert(last_assign_idx + 1, assign)
Пример #5
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
Пример #6
0
def object_actions(plugins: Dict[Type, Type[ParameterPlugin]], type_def: Union[Type[Generic], Type[Service]],
                   source: str) -> ObjectActions:

    ret: ObjectActions = []
    tree = horast.parse(source)

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

        # TODO check also if the method has 'action' decorator (ast needed)
        if not hasattr(method_def, "__action__"):
            continue

        # action from ancestor, will be copied later (only if the action was not overridden)
        base_cls_def = type_def.__bases__[0]
        if hasattr(base_cls_def, method_name) and getattr(base_cls_def, method_name) == method_def:
            continue

        meta: ActionMetadata = method_def.__action__

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

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

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

        signature = inspect.signature(method_def)

        method_tree = find_function(method_name, tree)

        try:
            for name, ttype in get_type_hints(method_def).items():

                try:
                    param_type = plugins[ttype]
                except KeyError:
                    for k, v in plugins.items():
                        if not v.EXACT_TYPE and inspect.isclass(ttype) and issubclass(ttype, k):
                            param_type = v
                            break
                    else:
                        if name == "return":  # noqa: E721
                            # ...just ignore NoneType for returns
                            continue

                        # ignore action with unknown parameter type
                        raise IgnoreActionException(f"Parameter {name} of action {method_name}"
                                                    f" has unknown type {ttype}.")

                if name == "return":
                    data.returns = param_type.type_name()
                    continue

                args = ActionParameterMeta(name=name, type=param_type.type_name())
                try:
                    param_type.meta(args, method_def, method_tree)
                except ParameterPluginException as e:
                    # TODO log exception
                    raise IgnoreActionException(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 = def_val

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

                data.parameters.append(args)

        except IgnoreActionException as e:
            data.disabled = True
            data.problem = str(e)
            # TODO log exception

        ret.append(data)

    return ret