예제 #1
0
def get_dataclass_params(type_def: Type[JsonSchemaMixin]) -> List[ParameterMeta]:
    """Analyzes properties of dataclass and returns their metadata.

    :param type_def:
    :return:
    """

    ret: List[ParameterMeta] = []

    sig = inspect.signature(type_def.__init__)

    # TODO Will this work for inherited properties? Make a test! There is also dataclasses.fields maybe...
    # TODO use inspect.signature to get reliable order of parameters
    for name, ttype in get_type_hints(type_def.__init__).items():
        if name == "return":
            continue

        if issubclass(ttype, JsonSchemaMixin):
            pm = ParameterMeta(name=name, type="dataclass")  # TODO come-up with plugin for this?
            pm.children = get_dataclass_params(ttype)
        else:
            param_type = plugin_from_type(ttype)
            assert param_type is not None
            pm = ParameterMeta(name=name, type=param_type.type_name())

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

            # TODO description, ranges, etc.

        ret.append(pm)

    return ret
예제 #2
0
def test_settings() -> None:

    meta = meta_from_def(TestObjectWithSettings)
    assert len(meta.settings) == 6

    assert meta.settings[0].name == "string"
    assert not meta.settings[0].children
    assert meta.settings[0].type == plugin_from_type(str).type_name()

    assert meta.settings[1].name == "integer"
    assert not meta.settings[1].children
    assert meta.settings[1].type == plugin_from_type(int).type_name()

    assert meta.settings[2].name == "boolean"
    assert not meta.settings[2].children
    assert meta.settings[2].type == plugin_from_type(bool).type_name()

    assert meta.settings[3].name == "double"
    assert not meta.settings[3].children
    assert meta.settings[3].type == plugin_from_type(float).type_name()

    assert meta.settings[4].name == "enum"
    assert not meta.settings[4].children
    assert meta.settings[4].type == plugin_from_type(StrEnum).type_name()

    assert meta.settings[5].name == "nested_settings"
    assert len(meta.settings[5].children) == 1
    assert meta.settings[5].type == "dataclass"  # TODO plugin for this?

    nested = meta.settings[5].children[0]

    assert nested.name == "boolean"
    assert not nested.children
    assert nested.type == plugin_from_type(bool).type_name()
예제 #3
0
def test_plugin_from_type() -> None:

    assert plugin_from_type(Image.Image) is ImagePlugin
예제 #4
0
def test_plugin_from_type() -> None:

    assert plugin_from_type(TestEnum) is StringEnumPlugin
예제 #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
파일: test_pose.py 프로젝트: ZdenekM/arcor2
def test_plugin_from_type() -> None:

    assert plugin_from_type(Pose) is PosePlugin
예제 #7
0
def test_plugin_from_type() -> None:

    assert plugin_from_type(str) is StringPlugin
예제 #8
0
def test_plugin_from_type() -> None:

    assert plugin_from_type(bool) is BooleanPlugin
예제 #9
0
def test_plugin_from_type() -> None:

    assert plugin_from_type(ProjectRobotJoints) is JointsPlugin