from __future__ import annotations from typing import Protocol, TypeVar from protobuf import Message, Registry from protobuf.wkt import ( api_pb, cpp_features_pb, descriptor_pb, duration_pb, empty_pb, field_mask_pb, go_features_pb, java_features_pb, source_context_pb, struct_pb, timestamp_pb, type_pb, wrappers_pb, ) CODEC_NAME_PROTO = "proto" CODEC_NAME_JSON = "json" DEFAULT_REGISTRY = Registry( api_pb.desc(), cpp_features_pb.desc(), descriptor_pb.desc(), duration_pb.desc(), empty_pb.desc(), field_mask_pb.desc(), go_features_pb.desc(), java_features_pb.desc(), source_context_pb.desc(), struct_pb.desc(), timestamp_pb.desc(), type_pb.desc(), wrappers_pb.desc(), ) T_contra = TypeVar("T_contra", contravariant=True) U = TypeVar("U") V = TypeVar("V", bound=Message) class Codec(Protocol[T_contra, U]): def name(self) -> str: """Returns the name of the codec. This corresponds to the content-type used in requests. """ ... def encode(self, message: T_contra) -> bytes: """Marshals the given message.""" ... def decode(self, data: bytes | bytearray, message_class: type[U]) -> U: """Unmarshals the given message.""" ... class ProtoBinaryCodec(Codec[Message, V]): """Codec for the Protocol Buffers binary format.""" def name(self) -> str: return "proto" def encode(self, message: Message) -> bytes: return message.to_binary() def decode(self, data: bytes | bytearray, message_class: type[V]) -> V: return message_class.from_binary(data) class ProtoJSONCodec(Codec[Message, V]): """Codec for the Protocol Buffers JSON format.""" def __init__(self, name: str = "json", registry: Registry | None = None) -> None: self._name = name self._registry = registry or DEFAULT_REGISTRY def name(self) -> str: return self._name def encode(self, message: Message) -> bytes: return message.to_json(registry=self._registry).encode() def decode(self, data: bytes | bytearray, message_class: type[V]) -> V: return message_class.from_json(data, registry=self._registry) _proto_binary_codec = ProtoBinaryCodec() _proto_json_codec = ProtoJSONCodec() _default_codecs: list[Codec] = [_proto_binary_codec, _proto_json_codec] def get_default_codecs() -> list[Codec]: return _default_codecs def proto_binary_codec() -> Codec: """Returns the Protocol Buffers binary codec.""" return _proto_binary_codec def proto_json_codec(registry: Registry | None = None) -> Codec: """Returns the Protocol Buffers JSON codec. Args: registry: An optional protobuf Registry to use for marshaling Any and extensions in messages. If not provided, a default registry containing WKTs will be used. """ if registry: return ProtoJSONCodec(name=CODEC_NAME_JSON, registry=registry) return _proto_json_codec