def py_name(self) -> str:
     """Pythonized name."""
     return pythonize_field_name(self.proto_name)
Example #2
0
def read_protobuf_type(item: DescriptorProto, path: List[int], proto_file,
                       content):
    input_package_name = content["input_package"]
    template_data = content["template_data"]
    data = {
        "name": item.name,
        "py_name": pythonize_class_name(item.name),
        "descriptor": item,
        "package": input_package_name,
    }
    if isinstance(item, DescriptorProto):
        # print(item, file=sys.stderr)
        if item.options.map_entry:
            # Skip generated map entry messages since we just use dicts
            return

        data.update({
            "type": "Message",
            "comment": get_comment(proto_file, path),
            "properties": [],
        })

        for i, f in enumerate(item.field):
            t = py_type(input_package_name, template_data["imports"], f)
            zero = get_py_zero(f.type)

            repeated = False
            packed = False

            field_type = f.Type.Name(f.type).lower()[5:]

            field_wraps = ""
            match_wrapper = re.match(r"\.google\.protobuf\.(.+)Value",
                                     f.type_name)
            if match_wrapper:
                wrapped_type = "TYPE_" + match_wrapper.group(1).upper()
                if hasattr(betterproto, wrapped_type):
                    field_wraps = f"betterproto.{wrapped_type}"

            map_types = None
            if f.type == 11:
                # This might be a map...
                message_type = f.type_name.split(".").pop().lower()
                # message_type = py_type(package)
                map_entry = f"{f.name.replace('_', '').lower()}entry"

                if message_type == map_entry:
                    for nested in item.nested_type:
                        if nested.name.replace("_", "").lower() == map_entry:
                            if nested.options.map_entry:
                                # print("Found a map!", file=sys.stderr)
                                k = py_type(
                                    input_package_name,
                                    template_data["imports"],
                                    nested.field[0],
                                )
                                v = py_type(
                                    input_package_name,
                                    template_data["imports"],
                                    nested.field[1],
                                )
                                t = f"Dict[{k}, {v}]"
                                field_type = "map"
                                map_types = (
                                    f.Type.Name(nested.field[0].type),
                                    f.Type.Name(nested.field[1].type),
                                )
                                template_data["typing_imports"].add("Dict")

            if f.label == 3 and field_type != "map":
                # Repeated field
                repeated = True
                t = f"List[{t}]"
                zero = "[]"
                template_data["typing_imports"].add("List")

                if f.type in [1, 2, 3, 4, 5, 6, 7, 8, 13, 15, 16, 17, 18]:
                    packed = True

            one_of = ""
            if f.HasField("oneof_index"):
                one_of = item.oneof_decl[f.oneof_index].name

            if "Optional[" in t:
                template_data["typing_imports"].add("Optional")

            if "timedelta" in t:
                template_data["datetime_imports"].add("timedelta")
            elif "datetime" in t:
                template_data["datetime_imports"].add("datetime")

            data["properties"].append({
                "name":
                f.name,
                "py_name":
                pythonize_field_name(f.name),
                "number":
                f.number,
                "comment":
                get_comment(proto_file, path + [2, i]),
                "proto_type":
                int(f.type),
                "field_type":
                field_type,
                "field_wraps":
                field_wraps,
                "map_types":
                map_types,
                "type":
                t,
                "zero":
                zero,
                "repeated":
                repeated,
                "packed":
                packed,
                "one_of":
                one_of,
            })
            # print(f, file=sys.stderr)

        template_data["messages"].append(data)
        return data
    elif isinstance(item, EnumDescriptorProto):
        # print(item.name, path, file=sys.stderr)
        data.update({
            "type":
            "Enum",
            "comment":
            get_comment(proto_file, path),
            "entries": [{
                "name": v.name,
                "value": v.number,
                "comment": get_comment(proto_file, path + [2, i]),
            } for i, v in enumerate(item.value)],
        })

        template_data["enums"].append(data)
        return data