Exemple #1
0
def generate_collection_class(object_data):
    """
    Same as generate_class but specifically for objects being collections
    :param object_data: (dict) object infos
    :return: (str) python code
    """
    code = utils.MyStr()
    class_name = object_data.get("name")
    # find the num property holding the length of the collection. The length property does not have the real length...
    length_property = [prop_name for prop_name in object_data.get("props").keys() if "num" in prop_name]
    if not length_property:
        raise ValueError("Couldn't find any length/number property on {}".format(object_data.get("name")))
    if len(length_property) != 1:
        raise ValueError("Found mutliple properties that could be the length of {} : {}".format(object_data.get("name"), length_property))
    length_property = length_property[0]
    # find class name of item in the collection
    if object_data.get("collectionContent"):
        item_class_name = object_data.get("collectionContent")[0]["name"]
    else:
        item_class_name = class_name.replace("Collection", "")
    # write class declaration
    code = code.add_line("class {}(PymiereBaseCollection):".format(class_name))
    code = code.add_line("def __init__(self, pymiere_id, length, {}, **kwargs):".format(length_property), indent=1)
    code = code.add_line("if not all([k.isdigit() for k in kwargs.keys()]):", indent=2)
    code = code.add_line("raise ValueError('Got unexpected argument {}'.format(kwargs))", indent=3)
    code = code.add_line('super({}, self).__init__(pymiere_id, "{}")'.format(class_name, length_property), indent=2)
    code = code.add_empty_line()
    code = code.add_line("def __getitem__(self, index):", indent=1)
    code = code.add_line("return {}(**super({}, self).__getitem__(index))".format(item_class_name, class_name), indent=2)
    code = code.add_empty_line()
    code = code.add_line("def __iter__(self):", indent=1)
    code = code.add_line("return iter([self.__getitem__(i) for i in range(len(self))])", indent=2)
    code = code.add_empty_line(number=2)
    return code
Exemple #2
0
def generate_class(object_data, all_classes_names):
    is_collection = False
    # checks
    all_keys = list(object_data.keys())
    if not all([
            k in all_keys
            for k in ["name", "type", "description", "help", "props", "funcs"]
    ]) or len(all_keys) != 6:
        is_collection = True
        if not all([
                k in all_keys for k in [
                    "name", "type", "description", "help", "props", "funcs",
                    "collectionContent"
                ]
        ]) or len(all_keys) != 7:
            raise ValueError("Wrong keys found : {}".format(
                object_data.keys()))
    if object_data["type"] != "object":
        raise ValueError("Wrong type")

    if is_collection:
        return generate_collection_class(object_data)

    # ----- INIT CLASS ------
    code = utils.MyStr()
    # definition
    code = code.add_line("class {}(PymiereBaseObject):".format(
        object_data.get("name")))
    # docstring
    if object_data.get("help") or object_data.get("description"):
        raise NotImplementedError()
    if object_data.get("name") in comments_data and comments_data[
            object_data.get("name")]["comment"]:
        code = code.add_line('""" {} """'.format(
            comments_data[object_data.get("name")]["comment"]),
                             indent=1)
    # init
    code = code.add_line("def __init__(self, pymiere_id=None):", indent=1)
    code = code.add_line("super({}, self).__init__(pymiere_id)".format(
        object_data.get("name")),
                         indent=2)

    # ----- CLASS PROPERTIES -----
    code = code.add_empty_line()
    code = code.add_line("# ----- PROPERTIES -----", indent=1)
    for prop_name, prop_info in object_data.get("props").items():
        # docstring
        if prop_info.get("help"):
            raise NotImplementedError("help")
        if object_data.get(
                "name") in comments_data and prop_name in comments_data[
                    object_data.get("name")]["props"]:
            code = code.add_line('""" {} """'.format(comments_data[
                object_data.get("name")]["props"][prop_name]["comment"]),
                                 indent=1)
        # getter
        code = code.add_line("@property", indent=1)
        code = code.add_line("def {}(self):".format(prop_name), indent=1)
        if prop_info.get("description"):
            code = code.add_line('"""{}"""'.format(
                prop_info.get("description")),
                                 indent=2)
        if prop_info.get("dataType") in utils.TYPE_CORRESPONDENCE:
            code = code.add_line(
                "return self._eval_on_this_object('{0}')".format(prop_name),
                indent=2)
        elif not prop_info.get("dataType")[0].isupper():
            code = code.add_line(
                "# TODO : this is unsupported dataType {}".format(
                    prop_info.get("dataType")),
                indent=2)
            # raise ValueError("Don't know how to handle dataType {}".format(prop_info.get("dataType")))
        elif prop_info.get("dataType") not in all_classes_names:
            print(
                "Return type '{}' for property getter '{}.{}' seems unknown, using automatic ES class to py object"
                .format(prop_info.get("dataType"), object_data.get("name"),
                        prop_name))
            code = code.add_line(
                "return _format_object_to_py(self._eval_on_this_object('{0}'))"
                .format(prop_name),
                indent=2)
        else:
            code = code.add_line(
                "kwargs = self._eval_on_this_object('{0}')".format(prop_name),
                indent=2)
            code = code.add_line(
                "return {1}(**kwargs) if kwargs else None".format(
                    prop_name, prop_info.get("dataType")),
                indent=2)
        # setter
        code = code.add_line("@{}.setter".format(prop_name), indent=1)
        code = code.add_line("def {0}(self, {0}):".format(prop_name), indent=1)
        if prop_info.get("type") == "readwrite":
            check_cls = utils.TYPE_CORRESPONDENCE[prop_info.get(
                "dataType")] if prop_info.get(
                    "dataType"
                ) in utils.TYPE_CORRESPONDENCE else prop_info.get("dataType")
            if check_cls in all_classes_names:
                code = code.add_line(
                    "self._check_type({0}, {1}, '{2}.{0}')".format(
                        prop_name, check_cls, object_data.get("name")),
                    indent=2)
            else:
                print(
                    "value type '{}' for property setter of '{}.{}' seems unknown, no check for type will be performed"
                    .format(check_cls, object_data.get("name"), prop_name))
            line = """self._eval_on_this_object("{0} = {{}}".format(_format_object_to_es({0})))"""
            code = code.add_line(line.format(prop_name), indent=2)
        elif prop_info.get("type") == "readonly":
            code = code.add_line(
                """raise AttributeError("Attribute '{}' is read-only")""".
                format(prop_name),
                indent=2)
        else:
            raise ValueError("Not supported type for attribute '{}'".format(
                prop_info.get("type")))
        code = code.add_empty_line()

    # ----- FUNCTIONS -----
    code = code.add_empty_line()
    code = code.add_line("# ----- FUNCTIONS -----", indent=1)
    for func_name, func_info in object_data.get("funcs").items():
        # docstring
        if func_info.get("help"):
            raise NotImplementedError("help")
        # definition
        args = ""
        if func_info.get("arguments"):
            args = ", ".join([""] + list(func_info.get("arguments").keys()))
        code = code.add_line("def {}(self{}):".format(func_name, args),
                             indent=1)

        # docstring
        if func_info.get("arguments") or func_info.get(
                "description") or object_data.get(
                    "name") in comments_data and func_name in comments_data[
                        object_data.get("name")]["props"]:
            # pycharm compatible docstring for arg types
            code = code.add_line('"""', indent=2)
            if func_info.get("description"):
                code = code.add_line(func_info.get("description"), indent=2)
            if object_data.get(
                    "name") in comments_data and func_name in comments_data[
                        object_data.get("name")]["props"]:
                code = code.add_line(comments_data[object_data.get("name")]
                                     ["props"][func_name]["comment"],
                                     indent=2)
                if "args" in comments_data[object_data.get(
                        "name")]["props"][func_name]:
                    for k, v in comments_data[object_data.get(
                            "name")]["props"][func_name]["args"].items():
                        code = code.add_line(":param {}: {}".format(k, v),
                                             indent=2)
            for arg_name, arg_info in func_info.get("arguments",
                                                    dict()).items():
                if arg_info.get("help"):
                    raise NotImplementedError("help")
                if arg_info.get("description"):
                    code = code.add_line(":param {}: {}".format(
                        arg_name, arg_info.get("description")),
                                         indent=2)
                pytype = utils.TYPE_CORRESPONDENCE[arg_info.get(
                    "dataType")] if arg_info.get(
                        "dataType"
                    ) in utils.TYPE_CORRESPONDENCE else arg_info.get(
                        "dataType")
                code = code.add_line(":type {}: {}".format(arg_name, pytype),
                                     indent=2)
            code = code.add_line('"""', indent=2)

        if func_info.get("arguments"):
            # check type of function args in python
            for arg_name, arg_info in func_info.get("arguments").items():
                if arg_info.get("dataType") in utils.TYPE_CORRESPONDENCE:
                    check_cls = utils.TYPE_CORRESPONDENCE[arg_info.get(
                        "dataType")] if arg_info.get(
                            "dataType"
                        ) in utils.TYPE_CORRESPONDENCE else arg_info.get(
                            "dataType")
                elif arg_info.get("dataType") not in all_classes_names:
                    print(
                        "arg type '{}' for function '{}.{}({})' seems unknown, no check for type will be performed"
                        .format(arg_info.get("dataType"),
                                object_data.get("name"), func_name, arg_name))
                    continue
                else:
                    # raise NotImplementedError("arg type {} not supported for function {} of {}".format(arg_info.get("dataType"), func_name, object_data.get('name')))
                    check_cls = arg_info.get("dataType")
                code = code.add_line(
                    """self._check_type({0}, {1}, 'arg "{0}" of function "{2}.{3}"')"""
                    .format(arg_name, check_cls, object_data.get("name"),
                            func_name),
                    indent=2)
        # body
        line = ""
        if func_info.get("dataType") != "undefined":
            line = "return "
            if func_info.get("dataType") not in utils.TYPE_CORRESPONDENCE:
                if func_info.get("dataType") not in all_classes_names:
                    print(
                        "Return type '{}' for function '{}.{}' seems unknown, using automatic ES class to py object"
                        .format(func_info.get("dataType"),
                                object_data.get("name"), func_name))
                    line += "_format_object_to_py("
                else:
                    line += str(func_info.get("dataType")) + "(**"
        line += 'self._eval_on_this_object("{}('.format(func_name)
        if func_info.get("arguments"):
            line_args = list()
            format_args = list()
            for arg_name, arg_info in func_info.get("arguments").items():
                line_args.append("{}")
                format_args.append("_format_object_to_es({})".format(arg_name))
            line += ", ".join(line_args)
            line += ')".format({}))'.format(", ".join(format_args))
        else:
            line += ')")'
        if func_info.get("dataType") != "undefined" and func_info.get(
                "dataType") not in utils.TYPE_CORRESPONDENCE:
            line += ")"
        code = code.add_line(line, indent=2)
        code = code.add_empty_line()
    code = code.add_empty_line()
    return code