From db56d13a1be2efcbe0f49045a93c2c2ccf8a1404 Mon Sep 17 00:00:00 2001 From: Adrien Vannson Date: Fri, 8 Nov 2024 17:53:05 +0100 Subject: [PATCH 01/37] Mark repeated fields --- src/betterproto/__init__.py | 66 +- .../lib/google/protobuf/__init__.py | 2519 ++++++++++++++++- src/betterproto/plugin/models.py | 2 + 3 files changed, 2554 insertions(+), 33 deletions(-) diff --git a/src/betterproto/__init__.py b/src/betterproto/__init__.py index 8eee6f4c4..cb03f4390 100644 --- a/src/betterproto/__init__.py +++ b/src/betterproto/__init__.py @@ -218,6 +218,7 @@ def dataclass_field( group: Optional[str] = None, wraps: Optional[str] = None, optional: bool = False, + repeated: bool = False, ) -> dataclasses.Field: """Creates a dataclass field with attached protobuf metadata.""" return dataclasses.field( @@ -235,96 +236,96 @@ def dataclass_field( # out at runtime. The generated dataclass variables are still typed correctly. -def enum_field(number: int, group: Optional[str] = None, optional: bool = False) -> Any: - return dataclass_field(number, TYPE_ENUM, group=group, optional=optional) +def enum_field(number: int, group: Optional[str] = None, optional: bool = False, repeated: bool = False,) -> Any: + return dataclass_field(number, TYPE_ENUM, group=group, optional=optional, repeated=repeated) -def bool_field(number: int, group: Optional[str] = None, optional: bool = False) -> Any: - return dataclass_field(number, TYPE_BOOL, group=group, optional=optional) +def bool_field(number: int, group: Optional[str] = None, optional: bool = False, repeated: bool = False,) -> Any: + return dataclass_field(number, TYPE_BOOL, group=group, optional=optional, repeated=repeated) def int32_field( - number: int, group: Optional[str] = None, optional: bool = False + number: int, group: Optional[str] = None, optional: bool = False, repeated: bool = False, ) -> Any: - return dataclass_field(number, TYPE_INT32, group=group, optional=optional) + return dataclass_field(number, TYPE_INT32, group=group, optional=optional, repeated=repeated) def int64_field( - number: int, group: Optional[str] = None, optional: bool = False + number: int, group: Optional[str] = None, optional: bool = False, repeated: bool = False, ) -> Any: - return dataclass_field(number, TYPE_INT64, group=group, optional=optional) + return dataclass_field(number, TYPE_INT64, group=group, optional=optional, repeated=repeated) def uint32_field( - number: int, group: Optional[str] = None, optional: bool = False + number: int, group: Optional[str] = None, optional: bool = False, repeated: bool = False, ) -> Any: - return dataclass_field(number, TYPE_UINT32, group=group, optional=optional) + return dataclass_field(number, TYPE_UINT32, group=group, optional=optional, repeated=repeated) def uint64_field( - number: int, group: Optional[str] = None, optional: bool = False + number: int, group: Optional[str] = None, optional: bool = False, repeated: bool = False, ) -> Any: - return dataclass_field(number, TYPE_UINT64, group=group, optional=optional) + return dataclass_field(number, TYPE_UINT64, group=group, optional=optional, repeated=repeated) def sint32_field( - number: int, group: Optional[str] = None, optional: bool = False + number: int, group: Optional[str] = None, optional: bool = False, repeated: bool = False, ) -> Any: - return dataclass_field(number, TYPE_SINT32, group=group, optional=optional) + return dataclass_field(number, TYPE_SINT32, group=group, optional=optional, repeated=repeated) def sint64_field( - number: int, group: Optional[str] = None, optional: bool = False + number: int, group: Optional[str] = None, optional: bool = False, repeated: bool = False, ) -> Any: - return dataclass_field(number, TYPE_SINT64, group=group, optional=optional) + return dataclass_field(number, TYPE_SINT64, group=group, optional=optional, repeated=repeated) def float_field( - number: int, group: Optional[str] = None, optional: bool = False + number: int, group: Optional[str] = None, optional: bool = False, repeated: bool = False, ) -> Any: - return dataclass_field(number, TYPE_FLOAT, group=group, optional=optional) + return dataclass_field(number, TYPE_FLOAT, group=group, optional=optional, repeated=repeated) def double_field( - number: int, group: Optional[str] = None, optional: bool = False + number: int, group: Optional[str] = None, optional: bool = False, repeated: bool = False, ) -> Any: - return dataclass_field(number, TYPE_DOUBLE, group=group, optional=optional) + return dataclass_field(number, TYPE_DOUBLE, group=group, optional=optional, repeated=repeated) def fixed32_field( - number: int, group: Optional[str] = None, optional: bool = False + number: int, group: Optional[str] = None, optional: bool = False, repeated: bool = False, ) -> Any: - return dataclass_field(number, TYPE_FIXED32, group=group, optional=optional) + return dataclass_field(number, TYPE_FIXED32, group=group, optional=optional, repeated=repeated) def fixed64_field( - number: int, group: Optional[str] = None, optional: bool = False + number: int, group: Optional[str] = None, optional: bool = False, repeated: bool = False, ) -> Any: - return dataclass_field(number, TYPE_FIXED64, group=group, optional=optional) + return dataclass_field(number, TYPE_FIXED64, group=group, optional=optional, repeated=repeated) def sfixed32_field( - number: int, group: Optional[str] = None, optional: bool = False + number: int, group: Optional[str] = None, optional: bool = False, repeated: bool = False, ) -> Any: - return dataclass_field(number, TYPE_SFIXED32, group=group, optional=optional) + return dataclass_field(number, TYPE_SFIXED32, group=group, optional=optional, repeated=repeated) def sfixed64_field( - number: int, group: Optional[str] = None, optional: bool = False + number: int, group: Optional[str] = None, optional: bool = False, repeated: bool = False, ) -> Any: - return dataclass_field(number, TYPE_SFIXED64, group=group, optional=optional) + return dataclass_field(number, TYPE_SFIXED64, group=group, optional=optional, repeated=repeated) def string_field( - number: int, group: Optional[str] = None, optional: bool = False + number: int, group: Optional[str] = None, optional: bool = False, repeated: bool = False, ) -> Any: - return dataclass_field(number, TYPE_STRING, group=group, optional=optional) + return dataclass_field(number, TYPE_STRING, group=group, optional=optional, repeated=repeated) def bytes_field( - number: int, group: Optional[str] = None, optional: bool = False + number: int, group: Optional[str] = None, optional: bool = False, repeated: bool = False, ) -> Any: - return dataclass_field(number, TYPE_BYTES, group=group, optional=optional) + return dataclass_field(number, TYPE_BYTES, group=group, optional=optional, repeated=repeated) def message_field( @@ -332,6 +333,7 @@ def message_field( group: Optional[str] = None, wraps: Optional[str] = None, optional: bool = False, + repeated: bool = False, ) -> Any: return dataclass_field( number, TYPE_MESSAGE, group=group, wraps=wraps, optional=optional diff --git a/src/betterproto/lib/google/protobuf/__init__.py b/src/betterproto/lib/google/protobuf/__init__.py index dfc9d5586..d3885ae54 100644 --- a/src/betterproto/lib/google/protobuf/__init__.py +++ b/src/betterproto/lib/google/protobuf/__init__.py @@ -1 +1,2518 @@ -from betterproto.lib.std.google.protobuf import * +# Generated by the protocol buffer compiler. DO NOT EDIT! +# sources: google/protobuf/any.proto, google/protobuf/api.proto, google/protobuf/descriptor.proto, google/protobuf/duration.proto, google/protobuf/empty.proto, google/protobuf/field_mask.proto, google/protobuf/source_context.proto, google/protobuf/struct.proto, google/protobuf/timestamp.proto, google/protobuf/type.proto, google/protobuf/wrappers.proto +# plugin: python-betterproto +# This file has been @generated + +__all__ = ( + "Syntax", + "FieldKind", + "FieldCardinality", + "FieldDescriptorProtoType", + "FieldDescriptorProtoLabel", + "FileOptionsOptimizeMode", + "FieldOptionsCType", + "FieldOptionsJsType", + "MethodOptionsIdempotencyLevel", + "NullValue", + "Any", + "SourceContext", + "Type", + "Field", + "Enum", + "EnumValue", + "Option", + "Api", + "Method", + "Mixin", + "FileDescriptorSet", + "FileDescriptorProto", + "DescriptorProto", + "DescriptorProtoExtensionRange", + "DescriptorProtoReservedRange", + "ExtensionRangeOptions", + "FieldDescriptorProto", + "OneofDescriptorProto", + "EnumDescriptorProto", + "EnumDescriptorProtoEnumReservedRange", + "EnumValueDescriptorProto", + "ServiceDescriptorProto", + "MethodDescriptorProto", + "FileOptions", + "MessageOptions", + "FieldOptions", + "OneofOptions", + "EnumOptions", + "EnumValueOptions", + "ServiceOptions", + "MethodOptions", + "UninterpretedOption", + "UninterpretedOptionNamePart", + "SourceCodeInfo", + "SourceCodeInfoLocation", + "GeneratedCodeInfo", + "GeneratedCodeInfoAnnotation", + "Duration", + "Empty", + "FieldMask", + "Struct", + "Value", + "ListValue", + "Timestamp", + "DoubleValue", + "FloatValue", + "Int64Value", + "UInt64Value", + "Int32Value", + "UInt32Value", + "BoolValue", + "StringValue", + "BytesValue", +) + +import warnings +from dataclasses import dataclass +from typing import ( + Dict, + List, +) + +import betterproto + + +class Syntax(betterproto.Enum): + """The syntax in which a protocol buffer element is defined.""" + + PROTO2 = 0 + """Syntax `proto2`.""" + + PROTO3 = 1 + """Syntax `proto3`.""" + + +class FieldKind(betterproto.Enum): + """Basic field types.""" + + TYPE_UNKNOWN = 0 + """Field type unknown.""" + + TYPE_DOUBLE = 1 + """Field type double.""" + + TYPE_FLOAT = 2 + """Field type float.""" + + TYPE_INT64 = 3 + """Field type int64.""" + + TYPE_UINT64 = 4 + """Field type uint64.""" + + TYPE_INT32 = 5 + """Field type int32.""" + + TYPE_FIXED64 = 6 + """Field type fixed64.""" + + TYPE_FIXED32 = 7 + """Field type fixed32.""" + + TYPE_BOOL = 8 + """Field type bool.""" + + TYPE_STRING = 9 + """Field type string.""" + + TYPE_GROUP = 10 + """Field type group. Proto2 syntax only, and deprecated.""" + + TYPE_MESSAGE = 11 + """Field type message.""" + + TYPE_BYTES = 12 + """Field type bytes.""" + + TYPE_UINT32 = 13 + """Field type uint32.""" + + TYPE_ENUM = 14 + """Field type enum.""" + + TYPE_SFIXED32 = 15 + """Field type sfixed32.""" + + TYPE_SFIXED64 = 16 + """Field type sfixed64.""" + + TYPE_SINT32 = 17 + """Field type sint32.""" + + TYPE_SINT64 = 18 + """Field type sint64.""" + + +class FieldCardinality(betterproto.Enum): + """Whether a field is optional, required, or repeated.""" + + CARDINALITY_UNKNOWN = 0 + """For fields with unknown cardinality.""" + + CARDINALITY_OPTIONAL = 1 + """For optional fields.""" + + CARDINALITY_REQUIRED = 2 + """For required fields. Proto2 syntax only.""" + + CARDINALITY_REPEATED = 3 + """For repeated fields.""" + + +class FieldDescriptorProtoType(betterproto.Enum): + """ """ + + TYPE_DOUBLE = 1 + """ + 0 is reserved for errors. + Order is weird for historical reasons. + """ + + TYPE_FLOAT = 2 + """ + + """ + + TYPE_INT64 = 3 + """ + Not ZigZag encoded. Negative numbers take 10 bytes. Use TYPE_SINT64 if + negative values are likely. + """ + + TYPE_UINT64 = 4 + """ + + """ + + TYPE_INT32 = 5 + """ + Not ZigZag encoded. Negative numbers take 10 bytes. Use TYPE_SINT32 if + negative values are likely. + """ + + TYPE_FIXED64 = 6 + """ + + """ + + TYPE_FIXED32 = 7 + """ + + """ + + TYPE_BOOL = 8 + """ + + """ + + TYPE_STRING = 9 + """ + + """ + + TYPE_GROUP = 10 + """ + Tag-delimited aggregate. + Group type is deprecated and not supported in proto3. However, Proto3 + implementations should still be able to parse the group wire format and + treat group fields as unknown fields. + """ + + TYPE_MESSAGE = 11 + """Length-delimited aggregate.""" + + TYPE_BYTES = 12 + """New in version 2.""" + + TYPE_UINT32 = 13 + """ + + """ + + TYPE_ENUM = 14 + """ + + """ + + TYPE_SFIXED32 = 15 + """ + + """ + + TYPE_SFIXED64 = 16 + """ + + """ + + TYPE_SINT32 = 17 + """Uses ZigZag encoding.""" + + TYPE_SINT64 = 18 + """Uses ZigZag encoding.""" + + +class FieldDescriptorProtoLabel(betterproto.Enum): + """ """ + + LABEL_OPTIONAL = 1 + """0 is reserved for errors""" + + LABEL_REQUIRED = 2 + """ + + """ + + LABEL_REPEATED = 3 + """ + + """ + + +class FileOptionsOptimizeMode(betterproto.Enum): + """Generated classes can be optimized for speed or code size.""" + + SPEED = 1 + """Generate complete code for parsing, serialization,""" + + CODE_SIZE = 2 + """ + etc. + + Use ReflectionOps to implement these methods. + """ + + LITE_RUNTIME = 3 + """Generate code using MessageLite and the lite runtime.""" + + +class FieldOptionsCType(betterproto.Enum): + """ """ + + STRING = 0 + """Default mode.""" + + CORD = 1 + """ + + """ + + STRING_PIECE = 2 + """ + + """ + + +class FieldOptionsJsType(betterproto.Enum): + """ """ + + JS_NORMAL = 0 + """Use the default type.""" + + JS_STRING = 1 + """Use JavaScript strings.""" + + JS_NUMBER = 2 + """Use JavaScript numbers.""" + + +class MethodOptionsIdempotencyLevel(betterproto.Enum): + """ + Is this method side-effect-free (or safe in HTTP parlance), or idempotent, + or neither? HTTP based RPC implementation may choose GET verb for safe + methods, and PUT verb for idempotent methods instead of the default POST. + """ + + IDEMPOTENCY_UNKNOWN = 0 + """ + + """ + + NO_SIDE_EFFECTS = 1 + """implies idempotent""" + + IDEMPOTENT = 2 + """idempotent, but may have side effects""" + + +class NullValue(betterproto.Enum): + """ + `NullValue` is a singleton enumeration to represent the null value for the + `Value` type union. + + The JSON representation for `NullValue` is JSON `null`. + """ + + _ = 0 + """Null value.""" + + +@dataclass(eq=False, repr=False) +class Any(betterproto.Message): + """ + `Any` contains an arbitrary serialized protocol buffer message along with a + URL that describes the type of the serialized message. + + Protobuf library provides support to pack/unpack Any values in the form + of utility functions or additional generated methods of the Any type. + + Example 1: Pack and unpack a message in C++. + + Foo foo = ...; + Any any; + any.PackFrom(foo); + ... + if (any.UnpackTo(&foo)) { + ... + } + + Example 2: Pack and unpack a message in Java. + + Foo foo = ...; + Any any = Any.pack(foo); + ... + if (any.is(Foo.class)) { + foo = any.unpack(Foo.class); + } + + Example 3: Pack and unpack a message in Python. + + foo = Foo(...) + any = Any() + any.Pack(foo) + ... + if any.Is(Foo.DESCRIPTOR): + any.Unpack(foo) + ... + + Example 4: Pack and unpack a message in Go + + foo := &pb.Foo{...} + any, err := ptypes.MarshalAny(foo) + ... + foo := &pb.Foo{} + if err := ptypes.UnmarshalAny(any, foo); err != nil { + ... + } + + The pack methods provided by protobuf library will by default use + 'type.googleapis.com/full.type.name' as the type URL and the unpack + methods only use the fully qualified type name after the last '/' + in the type URL, for example "foo.bar.com/x/y.z" will yield type + name "y.z". + + JSON + ==== + The JSON representation of an `Any` value uses the regular + representation of the deserialized, embedded message, with an + additional field `@type` which contains the type URL. Example: + + package google.profile; + message Person { + string first_name = 1; + string last_name = 2; + } + + { + "@type": "type.googleapis.com/google.profile.Person", + "firstName": , + "lastName": + } + + If the embedded message type is well-known and has a custom JSON + representation, that representation will be embedded adding a field + `value` which holds the custom JSON in addition to the `@type` + field. Example (for message [google.protobuf.Duration][]): + + { + "@type": "type.googleapis.com/google.protobuf.Duration", + "value": "1.212s" + } + """ + + type_url: str = betterproto.string_field(1) + """ + A URL/resource name that uniquely identifies the type of the serialized + protocol buffer message. This string must contain at least + one "/" character. The last segment of the URL's path must represent + the fully qualified name of the type (as in + `path/google.protobuf.Duration`). The name should be in a canonical form + (e.g., leading "." is not accepted). + + In practice, teams usually precompile into the binary all types that they + expect it to use in the context of Any. However, for URLs which use the + scheme `http`, `https`, or no scheme, one can optionally set up a type + server that maps type URLs to message definitions as follows: + + * If no scheme is provided, `https` is assumed. + * An HTTP GET on the URL must yield a [google.protobuf.Type][] + value in binary format, or produce an error. + * Applications are allowed to cache lookup results based on the + URL, or have them precompiled into a binary to avoid any + lookup. Therefore, binary compatibility needs to be preserved + on changes to types. (Use versioned type names to manage + breaking changes.) + + Note: this functionality is not currently available in the official + protobuf release, and it is not used for type URLs beginning with + type.googleapis.com. + + Schemes other than `http`, `https` (or the empty scheme) might be + used with implementation specific semantics. + """ + + value: bytes = betterproto.bytes_field(2) + """ + Must be a valid serialized protocol buffer of the above specified type. + """ + + +@dataclass(eq=False, repr=False) +class SourceContext(betterproto.Message): + """ + `SourceContext` represents information about the source of a + protobuf element, like the file in which it is defined. + """ + + file_name: str = betterproto.string_field(1) + """ + The path-qualified name of the .proto file that contained the associated + protobuf element. For example: `"google/protobuf/source_context.proto"`. + """ + + +@dataclass(eq=False, repr=False) +class Type(betterproto.Message): + """A protocol buffer message type.""" + + name: str = betterproto.string_field(1) + """The fully qualified message name.""" + + fields: List["Field"] = betterproto.message_field(2, repeated=True) + """The list of fields.""" + + oneofs: List[str] = betterproto.string_field(3, repeated=True) + """The list of types appearing in `oneof` definitions in this type.""" + + options: List["Option"] = betterproto.message_field(4, repeated=True) + """The protocol buffer options.""" + + source_context: "SourceContext" = betterproto.message_field(5) + """The source context.""" + + syntax: "Syntax" = betterproto.enum_field(6) + """The source syntax.""" + + +@dataclass(eq=False, repr=False) +class Field(betterproto.Message): + """A single field of a message type.""" + + kind: "FieldKind" = betterproto.enum_field(1) + """The field type.""" + + cardinality: "FieldCardinality" = betterproto.enum_field(2) + """The field cardinality.""" + + number: int = betterproto.int32_field(3) + """The field number.""" + + name: str = betterproto.string_field(4) + """The field name.""" + + type_url: str = betterproto.string_field(6) + """ + The field type URL, without the scheme, for message or enumeration + types. Example: `"type.googleapis.com/google.protobuf.Timestamp"`. + """ + + oneof_index: int = betterproto.int32_field(7) + """ + The index of the field type in `Type.oneofs`, for message or enumeration + types. The first type has index 1; zero means the type is not in the list. + """ + + packed: bool = betterproto.bool_field(8) + """Whether to use alternative packed wire representation.""" + + options: List["Option"] = betterproto.message_field(9, repeated=True) + """The protocol buffer options.""" + + json_name: str = betterproto.string_field(10) + """The field JSON name.""" + + default_value: str = betterproto.string_field(11) + """ + The string value of the default value of this field. Proto2 syntax only. + """ + + +@dataclass(eq=False, repr=False) +class Enum(betterproto.Message): + """Enum type definition.""" + + name: str = betterproto.string_field(1) + """Enum type name.""" + + enumvalue: List["EnumValue"] = betterproto.message_field( + 2, wraps=betterproto.TYPE_ENUM, repeated=True + ) + """Enum value definitions.""" + + options: List["Option"] = betterproto.message_field(3, repeated=True) + """Protocol buffer options.""" + + source_context: "SourceContext" = betterproto.message_field(4) + """The source context.""" + + syntax: "Syntax" = betterproto.enum_field(5) + """The source syntax.""" + + +@dataclass(eq=False, repr=False) +class EnumValue(betterproto.Message): + """Enum value definition.""" + + name: str = betterproto.string_field(1) + """Enum value name.""" + + number: int = betterproto.int32_field(2) + """Enum value number.""" + + options: List["Option"] = betterproto.message_field(3, repeated=True) + """Protocol buffer options.""" + + +@dataclass(eq=False, repr=False) +class Option(betterproto.Message): + """ + A protocol buffer option, which can be attached to a message, field, + enumeration, etc. + """ + + name: str = betterproto.string_field(1) + """ + The option's name. For protobuf built-in options (options defined in + descriptor.proto), this is the short name. For example, `"map_entry"`. + For custom options, it should be the fully-qualified name. For example, + `"google.api.http"`. + """ + + value: "Any" = betterproto.message_field(2) + """ + The option's value packed in an Any message. If the value is a primitive, + the corresponding wrapper type defined in google/protobuf/wrappers.proto + should be used. If the value is an enum, it should be stored as an int32 + value using the google.protobuf.Int32Value type. + """ + + +@dataclass(eq=False, repr=False) +class Api(betterproto.Message): + """ + Api is a light-weight descriptor for an API Interface. + + Interfaces are also described as "protocol buffer services" in some contexts, + such as by the "service" keyword in a .proto file, but they are different + from API Services, which represent a concrete implementation of an interface + as opposed to simply a description of methods and bindings. They are also + sometimes simply referred to as "APIs" in other contexts, such as the name of + this message itself. See https://cloud.google.com/apis/design/glossary for + detailed terminology. + """ + + name: str = betterproto.string_field(1) + """ + The fully qualified name of this interface, including package name + followed by the interface's simple name. + """ + + methods: List["Method"] = betterproto.message_field(2, repeated=True) + """The methods of this interface, in unspecified order.""" + + options: List["Option"] = betterproto.message_field(3, repeated=True) + """Any metadata attached to the interface.""" + + version: str = betterproto.string_field(4) + """ + A version string for this interface. If specified, must have the form + `major-version.minor-version`, as in `1.10`. If the minor version is + omitted, it defaults to zero. If the entire version field is empty, the + major version is derived from the package name, as outlined below. If the + field is not empty, the version in the package name will be verified to be + consistent with what is provided here. + + The versioning schema uses [semantic + versioning](http://semver.org) where the major version number + indicates a breaking change and the minor version an additive, + non-breaking change. Both version numbers are signals to users + what to expect from different versions, and should be carefully + chosen based on the product plan. + + The major version is also reflected in the package name of the + interface, which must end in `v`, as in + `google.feature.v1`. For major versions 0 and 1, the suffix can + be omitted. Zero major versions must only be used for + experimental, non-GA interfaces. + """ + + source_context: "SourceContext" = betterproto.message_field(5) + """ + Source context for the protocol buffer service represented by this + message. + """ + + mixins: List["Mixin"] = betterproto.message_field(6, repeated=True) + """Included interfaces. See [Mixin][].""" + + syntax: "Syntax" = betterproto.enum_field(7) + """The source syntax of the service.""" + + +@dataclass(eq=False, repr=False) +class Method(betterproto.Message): + """Method represents a method of an API interface.""" + + name: str = betterproto.string_field(1) + """The simple name of this method.""" + + request_type_url: str = betterproto.string_field(2) + """A URL of the input message type.""" + + request_streaming: bool = betterproto.bool_field(3) + """If true, the request is streamed.""" + + response_type_url: str = betterproto.string_field(4) + """The URL of the output message type.""" + + response_streaming: bool = betterproto.bool_field(5) + """If true, the response is streamed.""" + + options: List["Option"] = betterproto.message_field(6, repeated=True) + """Any metadata attached to the method.""" + + syntax: "Syntax" = betterproto.enum_field(7) + """The source syntax of this method.""" + + +@dataclass(eq=False, repr=False) +class Mixin(betterproto.Message): + """ + Declares an API Interface to be included in this interface. The including + interface must redeclare all the methods from the included interface, but + documentation and options are inherited as follows: + + - If after comment and whitespace stripping, the documentation + string of the redeclared method is empty, it will be inherited + from the original method. + + - Each annotation belonging to the service config (http, + visibility) which is not set in the redeclared method will be + inherited. + + - If an http annotation is inherited, the path pattern will be + modified as follows. Any version prefix will be replaced by the + version of the including interface plus the [root][] path if + specified. + + Example of a simple mixin: + + package google.acl.v1; + service AccessControl { + // Get the underlying ACL object. + rpc GetAcl(GetAclRequest) returns (Acl) { + option (google.api.http).get = "/v1/{resource=**}:getAcl"; + } + } + + package google.storage.v2; + service Storage { + rpc GetAcl(GetAclRequest) returns (Acl); + + // Get a data record. + rpc GetData(GetDataRequest) returns (Data) { + option (google.api.http).get = "/v2/{resource=**}"; + } + } + + Example of a mixin configuration: + + apis: + - name: google.storage.v2.Storage + mixins: + - name: google.acl.v1.AccessControl + + The mixin construct implies that all methods in `AccessControl` are + also declared with same name and request/response types in + `Storage`. A documentation generator or annotation processor will + see the effective `Storage.GetAcl` method after inherting + documentation and annotations as follows: + + service Storage { + // Get the underlying ACL object. + rpc GetAcl(GetAclRequest) returns (Acl) { + option (google.api.http).get = "/v2/{resource=**}:getAcl"; + } + ... + } + + Note how the version in the path pattern changed from `v1` to `v2`. + + If the `root` field in the mixin is specified, it should be a + relative path under which inherited HTTP paths are placed. Example: + + apis: + - name: google.storage.v2.Storage + mixins: + - name: google.acl.v1.AccessControl + root: acls + + This implies the following inherited HTTP annotation: + + service Storage { + // Get the underlying ACL object. + rpc GetAcl(GetAclRequest) returns (Acl) { + option (google.api.http).get = "/v2/acls/{resource=**}:getAcl"; + } + ... + } + """ + + name: str = betterproto.string_field(1) + """The fully qualified name of the interface which is included.""" + + root: str = betterproto.string_field(2) + """ + If non-empty specifies a path under which inherited HTTP paths + are rooted. + """ + + +@dataclass(eq=False, repr=False) +class FileDescriptorSet(betterproto.Message): + """ + The protocol compiler can output a FileDescriptorSet containing the .proto + files it parses. + """ + + file: List["FileDescriptorProto"] = betterproto.message_field(1, repeated=True) + """ + + """ + + +@dataclass(eq=False, repr=False) +class FileDescriptorProto(betterproto.Message): + """Describes a complete .proto file.""" + + name: str = betterproto.string_field(1) + """file name, relative to root of source tree""" + + package: str = betterproto.string_field(2) + """e.g. "foo", "foo.bar", etc.""" + + dependency: List[str] = betterproto.string_field(3, repeated=True) + """Names of files imported by this file.""" + + public_dependency: List[int] = betterproto.int32_field(10, repeated=True) + """Indexes of the public imported files in the dependency list above.""" + + weak_dependency: List[int] = betterproto.int32_field(11, repeated=True) + """ + Indexes of the weak imported files in the dependency list. + For Google-internal migration only. Do not use. + """ + + message_type: List["DescriptorProto"] = betterproto.message_field(4, repeated=True) + """All top-level definitions in this file.""" + + enum_type: List["EnumDescriptorProto"] = betterproto.message_field(5, repeated=True) + """ + + """ + + service: List["ServiceDescriptorProto"] = betterproto.message_field( + 6, repeated=True + ) + """ + + """ + + extension: List["FieldDescriptorProto"] = betterproto.message_field( + 7, repeated=True + ) + """ + + """ + + options: "FileOptions" = betterproto.message_field(8) + """ + + """ + + source_code_info: "SourceCodeInfo" = betterproto.message_field(9) + """ + This field contains optional information about the original source code. + You may safely remove this entire field without harming runtime + functionality of the descriptors -- the information is needed only by + development tools. + """ + + syntax: str = betterproto.string_field(12) + """ + The syntax of the proto file. + The supported values are "proto2" and "proto3". + """ + + +@dataclass(eq=False, repr=False) +class DescriptorProto(betterproto.Message): + """Describes a message type.""" + + name: str = betterproto.string_field(1) + """ + + """ + + field: List["FieldDescriptorProto"] = betterproto.message_field(2, repeated=True) + """ + + """ + + extension: List["FieldDescriptorProto"] = betterproto.message_field( + 6, repeated=True + ) + """ + + """ + + nested_type: List["DescriptorProto"] = betterproto.message_field(3, repeated=True) + """ + + """ + + enum_type: List["EnumDescriptorProto"] = betterproto.message_field(4, repeated=True) + """ + + """ + + extension_range: List["DescriptorProtoExtensionRange"] = betterproto.message_field( + 5, repeated=True + ) + """ + + """ + + oneof_decl: List["OneofDescriptorProto"] = betterproto.message_field( + 8, repeated=True + ) + """ + + """ + + options: "MessageOptions" = betterproto.message_field(7) + """ + + """ + + reserved_range: List["DescriptorProtoReservedRange"] = betterproto.message_field( + 9, repeated=True + ) + """ + + """ + + reserved_name: List[str] = betterproto.string_field(10, repeated=True) + """ + Reserved field names, which may not be used by fields in the same message. + A given name may only be reserved once. + """ + + +@dataclass(eq=False, repr=False) +class DescriptorProtoExtensionRange(betterproto.Message): + """ """ + + start: int = betterproto.int32_field(1) + """Inclusive.""" + + end: int = betterproto.int32_field(2) + """Exclusive.""" + + options: "ExtensionRangeOptions" = betterproto.message_field(3) + """ + + """ + + +@dataclass(eq=False, repr=False) +class DescriptorProtoReservedRange(betterproto.Message): + """ + Range of reserved tag numbers. Reserved tag numbers may not be used by + fields or extension ranges in the same message. Reserved ranges may + not overlap. + """ + + start: int = betterproto.int32_field(1) + """Inclusive.""" + + end: int = betterproto.int32_field(2) + """Exclusive.""" + + +@dataclass(eq=False, repr=False) +class ExtensionRangeOptions(betterproto.Message): + """ """ + + uninterpreted_option: List["UninterpretedOption"] = betterproto.message_field( + 999, repeated=True + ) + """The parser stores options it doesn't recognize here. See above.""" + + +@dataclass(eq=False, repr=False) +class FieldDescriptorProto(betterproto.Message): + """Describes a field within a message.""" + + name: str = betterproto.string_field(1) + """ + + """ + + number: int = betterproto.int32_field(3) + """ + + """ + + label: "FieldDescriptorProtoLabel" = betterproto.enum_field(4) + """ + + """ + + type: "FieldDescriptorProtoType" = betterproto.enum_field(5) + """ + If type_name is set, this need not be set. If both this and type_name + are set, this must be one of TYPE_ENUM, TYPE_MESSAGE or TYPE_GROUP. + """ + + type_name: str = betterproto.string_field(6) + """ + For message and enum types, this is the name of the type. If the name + starts with a '.', it is fully-qualified. Otherwise, C++-like scoping + rules are used to find the type (i.e. first the nested types within this + message are searched, then within the parent, on up to the root + namespace). + """ + + extendee: str = betterproto.string_field(2) + """ + For extensions, this is the name of the type being extended. It is + resolved in the same manner as type_name. + """ + + default_value: str = betterproto.string_field(7) + """ + For numeric types, contains the original text representation of the value. + For booleans, "true" or "false". + For strings, contains the default text contents (not escaped in any way). + For bytes, contains the C escaped value. All bytes >= 128 are escaped. + TODO(kenton): Base-64 encode? + """ + + oneof_index: int = betterproto.int32_field(9) + """ + If set, gives the index of a oneof in the containing type's oneof_decl + list. This field is a member of that oneof. + """ + + json_name: str = betterproto.string_field(10) + """ + JSON name of this field. The value is set by protocol compiler. If the + user has set a "json_name" option on this field, that option's value + will be used. Otherwise, it's deduced from the field's name by converting + it to camelCase. + """ + + options: "FieldOptions" = betterproto.message_field(8) + """ + + """ + + proto3_optional: bool = betterproto.bool_field(17) + """ + If true, this is a proto3 "optional". When a proto3 field is optional, it + tracks presence regardless of field type. + + When proto3_optional is true, this field must be belong to a oneof to + signal to old proto3 clients that presence is tracked for this field. This + oneof is known as a "synthetic" oneof, and this field must be its sole + member (each proto3 optional field gets its own synthetic oneof). Synthetic + oneofs exist in the descriptor only, and do not generate any API. Synthetic + oneofs must be ordered after all "real" oneofs. + + For message fields, proto3_optional doesn't create any semantic change, + since non-repeated message fields always track presence. However it still + indicates the semantic detail of whether the user wrote "optional" or not. + This can be useful for round-tripping the .proto file. For consistency we + give message fields a synthetic oneof also, even though it is not required + to track presence. This is especially important because the parser can't + tell if a field is a message or an enum, so it must always create a + synthetic oneof. + + Proto2 optional fields do not set this flag, because they already indicate + optional with `LABEL_OPTIONAL`. + """ + + +@dataclass(eq=False, repr=False) +class OneofDescriptorProto(betterproto.Message): + """Describes a oneof.""" + + name: str = betterproto.string_field(1) + """ + + """ + + options: "OneofOptions" = betterproto.message_field(2) + """ + + """ + + +@dataclass(eq=False, repr=False) +class EnumDescriptorProto(betterproto.Message): + """Describes an enum type.""" + + name: str = betterproto.string_field(1) + """ + + """ + + value: List["EnumValueDescriptorProto"] = betterproto.message_field( + 2, repeated=True + ) + """ + + """ + + options: "EnumOptions" = betterproto.message_field(3) + """ + + """ + + reserved_range: List["EnumDescriptorProtoEnumReservedRange"] = ( + betterproto.message_field(4, repeated=True) + ) + """ + Range of reserved numeric values. Reserved numeric values may not be used + by enum values in the same enum declaration. Reserved ranges may not + overlap. + """ + + reserved_name: List[str] = betterproto.string_field(5, repeated=True) + """ + Reserved enum value names, which may not be reused. A given name may only + be reserved once. + """ + + +@dataclass(eq=False, repr=False) +class EnumDescriptorProtoEnumReservedRange(betterproto.Message): + """ + Range of reserved numeric values. Reserved values may not be used by + entries in the same enum. Reserved ranges may not overlap. + + Note that this is distinct from DescriptorProto.ReservedRange in that it + is inclusive such that it can appropriately represent the entire int32 + domain. + """ + + start: int = betterproto.int32_field(1) + """Inclusive.""" + + end: int = betterproto.int32_field(2) + """Inclusive.""" + + +@dataclass(eq=False, repr=False) +class EnumValueDescriptorProto(betterproto.Message): + """Describes a value within an enum.""" + + name: str = betterproto.string_field(1) + """ + + """ + + number: int = betterproto.int32_field(2) + """ + + """ + + options: "EnumValueOptions" = betterproto.message_field(3) + """ + + """ + + +@dataclass(eq=False, repr=False) +class ServiceDescriptorProto(betterproto.Message): + """Describes a service.""" + + name: str = betterproto.string_field(1) + """ + + """ + + method: List["MethodDescriptorProto"] = betterproto.message_field(2, repeated=True) + """ + + """ + + options: "ServiceOptions" = betterproto.message_field(3) + """ + + """ + + +@dataclass(eq=False, repr=False) +class MethodDescriptorProto(betterproto.Message): + """Describes a method of a service.""" + + name: str = betterproto.string_field(1) + """ + + """ + + input_type: str = betterproto.string_field(2) + """ + Input and output type names. These are resolved in the same way as + FieldDescriptorProto.type_name, but must refer to a message type. + """ + + output_type: str = betterproto.string_field(3) + """ + + """ + + options: "MethodOptions" = betterproto.message_field(4) + """ + + """ + + client_streaming: bool = betterproto.bool_field(5) + """Identifies if client streams multiple client messages""" + + server_streaming: bool = betterproto.bool_field(6) + """Identifies if server streams multiple server messages""" + + +@dataclass(eq=False, repr=False) +class FileOptions(betterproto.Message): + """ + =================================================================== + Options + + Each of the definitions above may have "options" attached. These are + just annotations which may cause code to be generated slightly differently + or may contain hints for code that manipulates protocol messages. + + Clients may define custom options as extensions of the *Options messages. + These extensions may not yet be known at parsing time, so the parser cannot + store the values in them. Instead it stores them in a field in the *Options + message called uninterpreted_option. This field must have the same name + across all *Options messages. We then use this field to populate the + extensions when we build a descriptor, at which point all protos have been + parsed and so all extensions are known. + + Extension numbers for custom options may be chosen as follows: + * For options which will only be used within a single application or + organization, or for experimental options, use field numbers 50000 + through 99999. It is up to you to ensure that you do not use the + same number for multiple options. + * For options which will be published and used publicly by multiple + independent entities, e-mail protobuf-global-extension-registry@google.com + to reserve extension numbers. Simply provide your project name (e.g. + Objective-C plugin) and your project website (if available) -- there's no + need to explain how you intend to use them. Usually you only need one + extension number. You can declare multiple options with only one extension + number by putting them in a sub-message. See the Custom Options section of + the docs for examples: + https://developers.google.com/protocol-buffers/docs/proto#options + If this turns out to be popular, a web service will be set up + to automatically assign option numbers. + """ + + java_package: str = betterproto.string_field(1) + """ + Sets the Java package where classes generated from this .proto will be + placed. By default, the proto package is used, but this is often + inappropriate because proto packages do not normally start with backwards + domain names. + """ + + java_outer_classname: str = betterproto.string_field(8) + """ + If set, all the classes from the .proto file are wrapped in a single + outer class with the given name. This applies to both Proto1 + (equivalent to the old "--one_java_file" option) and Proto2 (where + a .proto always translates to a single class, but you may want to + explicitly choose the class name). + """ + + java_multiple_files: bool = betterproto.bool_field(10) + """ + If set true, then the Java code generator will generate a separate .java + file for each top-level message, enum, and service defined in the .proto + file. Thus, these types will *not* be nested inside the outer class + named by java_outer_classname. However, the outer class will still be + generated to contain the file's getDescriptor() method as well as any + top-level extensions defined in the file. + """ + + java_generate_equals_and_hash: bool = betterproto.bool_field(20) + """This option does nothing.""" + + java_string_check_utf8: bool = betterproto.bool_field(27) + """ + If set true, then the Java2 code generator will generate code that + throws an exception whenever an attempt is made to assign a non-UTF-8 + byte sequence to a string field. + Message reflection will do the same. + However, an extension field still accepts non-UTF-8 byte sequences. + This option has no effect on when used with the lite runtime. + """ + + optimize_for: "FileOptionsOptimizeMode" = betterproto.enum_field(9) + """ + + """ + + go_package: str = betterproto.string_field(11) + """ + Sets the Go package where structs generated from this .proto will be + placed. If omitted, the Go package will be derived from the following: + - The basename of the package import path, if provided. + - Otherwise, the package statement in the .proto file, if present. + - Otherwise, the basename of the .proto file, without extension. + """ + + cc_generic_services: bool = betterproto.bool_field(16) + """ + Should generic services be generated in each language? "Generic" services + are not specific to any particular RPC system. They are generated by the + main code generators in each language (without additional plugins). + Generic services were the only kind of service generation supported by + early versions of google.protobuf. + + Generic services are now considered deprecated in favor of using plugins + that generate code specific to your particular RPC system. Therefore, + these default to false. Old code which depends on generic services should + explicitly set them to true. + """ + + java_generic_services: bool = betterproto.bool_field(17) + """ + + """ + + py_generic_services: bool = betterproto.bool_field(18) + """ + + """ + + php_generic_services: bool = betterproto.bool_field(42) + """ + + """ + + deprecated: bool = betterproto.bool_field(23) + """ + Is this file deprecated? + Depending on the target platform, this can emit Deprecated annotations + for everything in the file, or it will be completely ignored; in the very + least, this is a formalization for deprecating files. + """ + + cc_enable_arenas: bool = betterproto.bool_field(31) + """ + Enables the use of arenas for the proto messages in this file. This applies + only to generated classes for C++. + """ + + objc_class_prefix: str = betterproto.string_field(36) + """ + Sets the objective c class prefix which is prepended to all objective c + generated classes from this .proto. There is no default. + """ + + csharp_namespace: str = betterproto.string_field(37) + """Namespace for generated classes; defaults to the package.""" + + swift_prefix: str = betterproto.string_field(39) + """ + By default Swift generators will take the proto package and CamelCase it + replacing '.' with underscore and use that to prefix the types/symbols + defined. When this options is provided, they will use this value instead + to prefix the types/symbols defined. + """ + + php_class_prefix: str = betterproto.string_field(40) + """ + Sets the php class prefix which is prepended to all php generated classes + from this .proto. Default is empty. + """ + + php_namespace: str = betterproto.string_field(41) + """ + Use this option to change the namespace of php generated classes. Default + is empty. When this option is empty, the package name will be used for + determining the namespace. + """ + + php_metadata_namespace: str = betterproto.string_field(44) + """ + Use this option to change the namespace of php generated metadata classes. + Default is empty. When this option is empty, the proto file name will be + used for determining the namespace. + """ + + ruby_package: str = betterproto.string_field(45) + """ + Use this option to change the package of ruby generated classes. Default + is empty. When this option is not set, the package name will be used for + determining the ruby package. + """ + + uninterpreted_option: List["UninterpretedOption"] = betterproto.message_field( + 999, repeated=True + ) + """ + The parser stores options it doesn't recognize here. + See the documentation for the "Options" section above. + """ + + def __post_init__(self) -> None: + super().__post_init__() + if self.is_set("java_generate_equals_and_hash"): + warnings.warn( + "FileOptions.java_generate_equals_and_hash is deprecated", + DeprecationWarning, + ) + + +@dataclass(eq=False, repr=False) +class MessageOptions(betterproto.Message): + """ """ + + message_set_wire_format: bool = betterproto.bool_field(1) + """ + Set true to use the old proto1 MessageSet wire format for extensions. + This is provided for backwards-compatibility with the MessageSet wire + format. You should not use this for any other reason: It's less + efficient, has fewer features, and is more complicated. + + The message must be defined exactly as follows: + message Foo { + option message_set_wire_format = true; + extensions 4 to max; + } + Note that the message cannot have any defined fields; MessageSets only + have extensions. + + All extensions of your type must be singular messages; e.g. they cannot + be int32s, enums, or repeated messages. + + Because this is an option, the above two restrictions are not enforced by + the protocol compiler. + """ + + no_standard_descriptor_accessor: bool = betterproto.bool_field(2) + """ + Disables the generation of the standard "descriptor()" accessor, which can + conflict with a field of the same name. This is meant to make migration + from proto1 easier; new code should avoid fields named "descriptor". + """ + + deprecated: bool = betterproto.bool_field(3) + """ + Is this message deprecated? + Depending on the target platform, this can emit Deprecated annotations + for the message, or it will be completely ignored; in the very least, + this is a formalization for deprecating messages. + """ + + map_entry: bool = betterproto.bool_field(7) + """ + Whether the message is an automatically generated map entry type for the + maps field. + + For maps fields: + map map_field = 1; + The parsed descriptor looks like: + message MapFieldEntry { + option map_entry = true; + optional KeyType key = 1; + optional ValueType value = 2; + } + repeated MapFieldEntry map_field = 1; + + Implementations may choose not to generate the map_entry=true message, but + use a native map in the target language to hold the keys and values. + The reflection APIs in such implementations still need to work as + if the field is a repeated message field. + + NOTE: Do not set the option in .proto files. Always use the maps syntax + instead. The option should only be implicitly set by the proto compiler + parser. + """ + + uninterpreted_option: List["UninterpretedOption"] = betterproto.message_field( + 999, repeated=True + ) + """The parser stores options it doesn't recognize here. See above.""" + + +@dataclass(eq=False, repr=False) +class FieldOptions(betterproto.Message): + """ """ + + ctype: "FieldOptionsCType" = betterproto.enum_field(1) + """ + The ctype option instructs the C++ code generator to use a different + representation of the field than it normally would. See the specific + options below. This option is not yet implemented in the open source + release -- sorry, we'll try to include it in a future version! + """ + + packed: bool = betterproto.bool_field(2) + """ + The packed option can be enabled for repeated primitive fields to enable + a more efficient representation on the wire. Rather than repeatedly + writing the tag and type for each element, the entire array is encoded as + a single length-delimited blob. In proto3, only explicit setting it to + false will avoid using packed encoding. + """ + + jstype: "FieldOptionsJsType" = betterproto.enum_field(6) + """ + The jstype option determines the JavaScript type used for values of the + field. The option is permitted only for 64 bit integral and fixed types + (int64, uint64, sint64, fixed64, sfixed64). A field with jstype JS_STRING + is represented as JavaScript string, which avoids loss of precision that + can happen when a large value is converted to a floating point JavaScript. + Specifying JS_NUMBER for the jstype causes the generated JavaScript code to + use the JavaScript "number" type. The behavior of the default option + JS_NORMAL is implementation dependent. + + This option is an enum to permit additional types to be added, e.g. + goog.math.Integer. + """ + + lazy: bool = betterproto.bool_field(5) + """ + Should this field be parsed lazily? Lazy applies only to message-type + fields. It means that when the outer message is initially parsed, the + inner message's contents will not be parsed but instead stored in encoded + form. The inner message will actually be parsed when it is first accessed. + + This is only a hint. Implementations are free to choose whether to use + eager or lazy parsing regardless of the value of this option. However, + setting this option true suggests that the protocol author believes that + using lazy parsing on this field is worth the additional bookkeeping + overhead typically needed to implement it. + + This option does not affect the public interface of any generated code; + all method signatures remain the same. Furthermore, thread-safety of the + interface is not affected by this option; const methods remain safe to + call from multiple threads concurrently, while non-const methods continue + to require exclusive access. + + Note that implementations may choose not to check required fields within + a lazy sub-message. That is, calling IsInitialized() on the outer message + may return true even if the inner message has missing required fields. + This is necessary because otherwise the inner message would have to be + parsed in order to perform the check, defeating the purpose of lazy + parsing. An implementation which chooses not to check required fields + must be consistent about it. That is, for any particular sub-message, the + implementation must either *always* check its required fields, or *never* + check its required fields, regardless of whether or not the message has + been parsed. + """ + + deprecated: bool = betterproto.bool_field(3) + """ + Is this field deprecated? + Depending on the target platform, this can emit Deprecated annotations + for accessors, or it will be completely ignored; in the very least, this + is a formalization for deprecating fields. + """ + + weak: bool = betterproto.bool_field(10) + """For Google-internal migration only. Do not use.""" + + uninterpreted_option: List["UninterpretedOption"] = betterproto.message_field( + 999, repeated=True + ) + """The parser stores options it doesn't recognize here. See above.""" + + +@dataclass(eq=False, repr=False) +class OneofOptions(betterproto.Message): + """ """ + + uninterpreted_option: List["UninterpretedOption"] = betterproto.message_field( + 999, repeated=True + ) + """The parser stores options it doesn't recognize here. See above.""" + + +@dataclass(eq=False, repr=False) +class EnumOptions(betterproto.Message): + """ """ + + allow_alias: bool = betterproto.bool_field(2) + """ + Set this option to true to allow mapping different tag names to the same + value. + """ + + deprecated: bool = betterproto.bool_field(3) + """ + Is this enum deprecated? + Depending on the target platform, this can emit Deprecated annotations + for the enum, or it will be completely ignored; in the very least, this + is a formalization for deprecating enums. + """ + + uninterpreted_option: List["UninterpretedOption"] = betterproto.message_field( + 999, repeated=True + ) + """The parser stores options it doesn't recognize here. See above.""" + + +@dataclass(eq=False, repr=False) +class EnumValueOptions(betterproto.Message): + """ """ + + deprecated: bool = betterproto.bool_field(1) + """ + Is this enum value deprecated? + Depending on the target platform, this can emit Deprecated annotations + for the enum value, or it will be completely ignored; in the very least, + this is a formalization for deprecating enum values. + """ + + uninterpreted_option: List["UninterpretedOption"] = betterproto.message_field( + 999, repeated=True + ) + """The parser stores options it doesn't recognize here. See above.""" + + +@dataclass(eq=False, repr=False) +class ServiceOptions(betterproto.Message): + """ """ + + deprecated: bool = betterproto.bool_field(33) + """ + Note: Field numbers 1 through 32 are reserved for Google's internal RPC + framework. We apologize for hoarding these numbers to ourselves, but + we were already using them long before we decided to release Protocol + Buffers. + + Is this service deprecated? + Depending on the target platform, this can emit Deprecated annotations + for the service, or it will be completely ignored; in the very least, + this is a formalization for deprecating services. + """ + + uninterpreted_option: List["UninterpretedOption"] = betterproto.message_field( + 999, repeated=True + ) + """The parser stores options it doesn't recognize here. See above.""" + + +@dataclass(eq=False, repr=False) +class MethodOptions(betterproto.Message): + """ """ + + deprecated: bool = betterproto.bool_field(33) + """ + Note: Field numbers 1 through 32 are reserved for Google's internal RPC + framework. We apologize for hoarding these numbers to ourselves, but + we were already using them long before we decided to release Protocol + Buffers. + + Is this method deprecated? + Depending on the target platform, this can emit Deprecated annotations + for the method, or it will be completely ignored; in the very least, + this is a formalization for deprecating methods. + """ + + idempotency_level: "MethodOptionsIdempotencyLevel" = betterproto.enum_field(34) + """ + + """ + + uninterpreted_option: List["UninterpretedOption"] = betterproto.message_field( + 999, repeated=True + ) + """The parser stores options it doesn't recognize here. See above.""" + + +@dataclass(eq=False, repr=False) +class UninterpretedOption(betterproto.Message): + """ + A message representing a option the parser does not recognize. This only + appears in options protos created by the compiler::Parser class. + DescriptorPool resolves these when building Descriptor objects. Therefore, + options protos in descriptor objects (e.g. returned by Descriptor::options(), + or produced by Descriptor::CopyTo()) will never have UninterpretedOptions + in them. + """ + + name: List["UninterpretedOptionNamePart"] = betterproto.message_field( + 2, repeated=True + ) + """ + + """ + + identifier_value: str = betterproto.string_field(3) + """ + The value of the uninterpreted option, in whatever type the tokenizer + identified it as during parsing. Exactly one of these should be set. + """ + + positive_int_value: int = betterproto.uint64_field(4) + """ + + """ + + negative_int_value: int = betterproto.int64_field(5) + """ + + """ + + double_value: float = betterproto.double_field(6) + """ + + """ + + string_value: bytes = betterproto.bytes_field(7) + """ + + """ + + aggregate_value: str = betterproto.string_field(8) + """ + + """ + + +@dataclass(eq=False, repr=False) +class UninterpretedOptionNamePart(betterproto.Message): + """ + The name of the uninterpreted option. Each string represents a segment in + a dot-separated name. is_extension is true iff a segment represents an + extension (denoted with parentheses in options specs in .proto files). + E.g.,{ ["foo", false], ["bar.baz", true], ["qux", false] } represents + "foo.(bar.baz).qux". + """ + + name_part: str = betterproto.string_field(1) + """ + + """ + + is_extension: bool = betterproto.bool_field(2) + """ + + """ + + +@dataclass(eq=False, repr=False) +class SourceCodeInfo(betterproto.Message): + """ + =================================================================== + Optional source code info + + Encapsulates information about the original source file from which a + FileDescriptorProto was generated. + """ + + location: List["SourceCodeInfoLocation"] = betterproto.message_field( + 1, repeated=True + ) + """ + A Location identifies a piece of source code in a .proto file which + corresponds to a particular definition. This information is intended + to be useful to IDEs, code indexers, documentation generators, and similar + tools. + + For example, say we have a file like: + message Foo { + optional string foo = 1; + } + Let's look at just the field definition: + optional string foo = 1; + ^ ^^ ^^ ^ ^^^ + a bc de f ghi + We have the following locations: + span path represents + [a,i) [ 4, 0, 2, 0 ] The whole field definition. + [a,b) [ 4, 0, 2, 0, 4 ] The label (optional). + [c,d) [ 4, 0, 2, 0, 5 ] The type (string). + [e,f) [ 4, 0, 2, 0, 1 ] The name (foo). + [g,h) [ 4, 0, 2, 0, 3 ] The number (1). + + Notes: + - A location may refer to a repeated field itself (i.e. not to any + particular index within it). This is used whenever a set of elements are + logically enclosed in a single code segment. For example, an entire + extend block (possibly containing multiple extension definitions) will + have an outer location whose path refers to the "extensions" repeated + field without an index. + - Multiple locations may have the same path. This happens when a single + logical declaration is spread out across multiple places. The most + obvious example is the "extend" block again -- there may be multiple + extend blocks in the same scope, each of which will have the same path. + - A location's span is not always a subset of its parent's span. For + example, the "extendee" of an extension declaration appears at the + beginning of the "extend" block and is shared by all extensions within + the block. + - Just because a location's span is a subset of some other location's span + does not mean that it is a descendant. For example, a "group" defines + both a type and a field in a single declaration. Thus, the locations + corresponding to the type and field and their components will overlap. + - Code which tries to interpret locations should probably be designed to + ignore those that it doesn't understand, as more types of locations could + be recorded in the future. + """ + + +@dataclass(eq=False, repr=False) +class SourceCodeInfoLocation(betterproto.Message): + """ """ + + path: List[int] = betterproto.int32_field(1, repeated=True) + """ + Identifies which part of the FileDescriptorProto was defined at this + location. + + Each element is a field number or an index. They form a path from + the root FileDescriptorProto to the place where the definition. For + example, this path: + [ 4, 3, 2, 7, 1 ] + refers to: + file.message_type(3) // 4, 3 + .field(7) // 2, 7 + .name() // 1 + This is because FileDescriptorProto.message_type has field number 4: + repeated DescriptorProto message_type = 4; + and DescriptorProto.field has field number 2: + repeated FieldDescriptorProto field = 2; + and FieldDescriptorProto.name has field number 1: + optional string name = 1; + + Thus, the above path gives the location of a field name. If we removed + the last element: + [ 4, 3, 2, 7 ] + this path refers to the whole field declaration (from the beginning + of the label to the terminating semicolon). + """ + + span: List[int] = betterproto.int32_field(2, repeated=True) + """ + Always has exactly three or four elements: start line, start column, + end line (optional, otherwise assumed same as start line), end column. + These are packed into a single field for efficiency. Note that line + and column numbers are zero-based -- typically you will want to add + 1 to each before displaying to a user. + """ + + leading_comments: str = betterproto.string_field(3) + """ + If this SourceCodeInfo represents a complete declaration, these are any + comments appearing before and after the declaration which appear to be + attached to the declaration. + + A series of line comments appearing on consecutive lines, with no other + tokens appearing on those lines, will be treated as a single comment. + + leading_detached_comments will keep paragraphs of comments that appear + before (but not connected to) the current element. Each paragraph, + separated by empty lines, will be one comment element in the repeated + field. + + Only the comment content is provided; comment markers (e.g. //) are + stripped out. For block comments, leading whitespace and an asterisk + will be stripped from the beginning of each line other than the first. + Newlines are included in the output. + + Examples: + + optional int32 foo = 1; // Comment attached to foo. + // Comment attached to bar. + optional int32 bar = 2; + + optional string baz = 3; + // Comment attached to baz. + // Another line attached to baz. + + // Comment attached to qux. + // + // Another line attached to qux. + optional double qux = 4; + + // Detached comment for corge. This is not leading or trailing comments + // to qux or corge because there are blank lines separating it from + // both. + + // Detached comment for corge paragraph 2. + + optional string corge = 5; + /* Block comment attached + * to corge. Leading asterisks + * will be removed. */ + /* Block comment attached to + * grault. */ + optional int32 grault = 6; + + // ignored detached comments. + """ + + trailing_comments: str = betterproto.string_field(4) + """ + + """ + + leading_detached_comments: List[str] = betterproto.string_field(6, repeated=True) + """ + + """ + + +@dataclass(eq=False, repr=False) +class GeneratedCodeInfo(betterproto.Message): + """ + Describes the relationship between generated code and its original source + file. A GeneratedCodeInfo message is associated with only one generated + source file, but may contain references to different source .proto files. + """ + + annotation: List["GeneratedCodeInfoAnnotation"] = betterproto.message_field( + 1, repeated=True + ) + """ + An Annotation connects some span of text in generated code to an element + of its generating .proto file. + """ + + +@dataclass(eq=False, repr=False) +class GeneratedCodeInfoAnnotation(betterproto.Message): + """ """ + + path: List[int] = betterproto.int32_field(1, repeated=True) + """ + Identifies the element in the original source .proto file. This field + is formatted the same as SourceCodeInfo.Location.path. + """ + + source_file: str = betterproto.string_field(2) + """Identifies the filesystem path to the original source .proto.""" + + begin: int = betterproto.int32_field(3) + """ + Identifies the starting offset in bytes in the generated code + that relates to the identified object. + """ + + end: int = betterproto.int32_field(4) + """ + Identifies the ending offset in bytes in the generated code that + relates to the identified offset. The end offset should be one past + the last relevant byte (so the length of the text = end - begin). + """ + + +@dataclass(eq=False, repr=False) +class Duration(betterproto.Message): + """ + A Duration represents a signed, fixed-length span of time represented + as a count of seconds and fractions of seconds at nanosecond + resolution. It is independent of any calendar and concepts like "day" + or "month". It is related to Timestamp in that the difference between + two Timestamp values is a Duration and it can be added or subtracted + from a Timestamp. Range is approximately +-10,000 years. + + # Examples + + Example 1: Compute Duration from two Timestamps in pseudo code. + + Timestamp start = ...; + Timestamp end = ...; + Duration duration = ...; + + duration.seconds = end.seconds - start.seconds; + duration.nanos = end.nanos - start.nanos; + + if (duration.seconds < 0 && duration.nanos > 0) { + duration.seconds += 1; + duration.nanos -= 1000000000; + } else if (duration.seconds > 0 && duration.nanos < 0) { + duration.seconds -= 1; + duration.nanos += 1000000000; + } + + Example 2: Compute Timestamp from Timestamp + Duration in pseudo code. + + Timestamp start = ...; + Duration duration = ...; + Timestamp end = ...; + + end.seconds = start.seconds + duration.seconds; + end.nanos = start.nanos + duration.nanos; + + if (end.nanos < 0) { + end.seconds -= 1; + end.nanos += 1000000000; + } else if (end.nanos >= 1000000000) { + end.seconds += 1; + end.nanos -= 1000000000; + } + + Example 3: Compute Duration from datetime.timedelta in Python. + + td = datetime.timedelta(days=3, minutes=10) + duration = Duration() + duration.FromTimedelta(td) + + # JSON Mapping + + In JSON format, the Duration type is encoded as a string rather than an + object, where the string ends in the suffix "s" (indicating seconds) and + is preceded by the number of seconds, with nanoseconds expressed as + fractional seconds. For example, 3 seconds with 0 nanoseconds should be + encoded in JSON format as "3s", while 3 seconds and 1 nanosecond should + be expressed in JSON format as "3.000000001s", and 3 seconds and 1 + microsecond should be expressed in JSON format as "3.000001s". + """ + + seconds: int = betterproto.int64_field(1) + """ + Signed seconds of the span of time. Must be from -315,576,000,000 + to +315,576,000,000 inclusive. Note: these bounds are computed from: + 60 sec/min * 60 min/hr * 24 hr/day * 365.25 days/year * 10000 years + """ + + nanos: int = betterproto.int32_field(2) + """ + Signed fractions of a second at nanosecond resolution of the span + of time. Durations less than one second are represented with a 0 + `seconds` field and a positive or negative `nanos` field. For durations + of one second or more, a non-zero value for the `nanos` field must be + of the same sign as the `seconds` field. Must be from -999,999,999 + to +999,999,999 inclusive. + """ + + +@dataclass(eq=False, repr=False) +class Empty(betterproto.Message): + """ + A generic empty message that you can re-use to avoid defining duplicated + empty messages in your APIs. A typical example is to use it as the request + or the response type of an API method. For instance: + + service Foo { + rpc Bar(google.protobuf.Empty) returns (google.protobuf.Empty); + } + + The JSON representation for `Empty` is empty JSON object `{}`. + """ + + pass + + +@dataclass(eq=False, repr=False) +class FieldMask(betterproto.Message): + """ + `FieldMask` represents a set of symbolic field paths, for example: + + paths: "f.a" + paths: "f.b.d" + + Here `f` represents a field in some root message, `a` and `b` + fields in the message found in `f`, and `d` a field found in the + message in `f.b`. + + Field masks are used to specify a subset of fields that should be + returned by a get operation or modified by an update operation. + Field masks also have a custom JSON encoding (see below). + + # Field Masks in Projections + + When used in the context of a projection, a response message or + sub-message is filtered by the API to only contain those fields as + specified in the mask. For example, if the mask in the previous + example is applied to a response message as follows: + + f { + a : 22 + b { + d : 1 + x : 2 + } + y : 13 + } + z: 8 + + The result will not contain specific values for fields x,y and z + (their value will be set to the default, and omitted in proto text + output): + + f { + a : 22 + b { + d : 1 + } + } + + A repeated field is not allowed except at the last position of a + paths string. + + If a FieldMask object is not present in a get operation, the + operation applies to all fields (as if a FieldMask of all fields + had been specified). + + Note that a field mask does not necessarily apply to the + top-level response message. In case of a REST get operation, the + field mask applies directly to the response, but in case of a REST + list operation, the mask instead applies to each individual message + in the returned resource list. In case of a REST custom method, + other definitions may be used. Where the mask applies will be + clearly documented together with its declaration in the API. In + any case, the effect on the returned resource/resources is required + behavior for APIs. + + # Field Masks in Update Operations + + A field mask in update operations specifies which fields of the + targeted resource are going to be updated. The API is required + to only change the values of the fields as specified in the mask + and leave the others untouched. If a resource is passed in to + describe the updated values, the API ignores the values of all + fields not covered by the mask. + + If a repeated field is specified for an update operation, new values will + be appended to the existing repeated field in the target resource. Note that + a repeated field is only allowed in the last position of a `paths` string. + + If a sub-message is specified in the last position of the field mask for an + update operation, then new value will be merged into the existing sub-message + in the target resource. + + For example, given the target message: + + f { + b { + d: 1 + x: 2 + } + c: [1] + } + + And an update message: + + f { + b { + d: 10 + } + c: [2] + } + + then if the field mask is: + + paths: ["f.b", "f.c"] + + then the result will be: + + f { + b { + d: 10 + x: 2 + } + c: [1, 2] + } + + An implementation may provide options to override this default behavior for + repeated and message fields. + + In order to reset a field's value to the default, the field must + be in the mask and set to the default value in the provided resource. + Hence, in order to reset all fields of a resource, provide a default + instance of the resource and set all fields in the mask, or do + not provide a mask as described below. + + If a field mask is not present on update, the operation applies to + all fields (as if a field mask of all fields has been specified). + Note that in the presence of schema evolution, this may mean that + fields the client does not know and has therefore not filled into + the request will be reset to their default. If this is unwanted + behavior, a specific service may require a client to always specify + a field mask, producing an error if not. + + As with get operations, the location of the resource which + describes the updated values in the request message depends on the + operation kind. In any case, the effect of the field mask is + required to be honored by the API. + + ## Considerations for HTTP REST + + The HTTP kind of an update operation which uses a field mask must + be set to PATCH instead of PUT in order to satisfy HTTP semantics + (PUT must only be used for full updates). + + # JSON Encoding of Field Masks + + In JSON, a field mask is encoded as a single string where paths are + separated by a comma. Fields name in each path are converted + to/from lower-camel naming conventions. + + As an example, consider the following message declarations: + + message Profile { + User user = 1; + Photo photo = 2; + } + message User { + string display_name = 1; + string address = 2; + } + + In proto a field mask for `Profile` may look as such: + + mask { + paths: "user.display_name" + paths: "photo" + } + + In JSON, the same mask is represented as below: + + { + mask: "user.displayName,photo" + } + + # Field Masks and Oneof Fields + + Field masks treat fields in oneofs just as regular fields. Consider the + following message: + + message SampleMessage { + oneof test_oneof { + string name = 4; + SubMessage sub_message = 9; + } + } + + The field mask can be: + + mask { + paths: "name" + } + + Or: + + mask { + paths: "sub_message" + } + + Note that oneof type names ("test_oneof" in this case) cannot be used in + paths. + + ## Field Mask Verification + + The implementation of any API method which has a FieldMask type field in the + request should verify the included field paths, and return an + `INVALID_ARGUMENT` error if any path is unmappable. + """ + + paths: List[str] = betterproto.string_field(1, repeated=True) + """The set of field mask paths.""" + + +@dataclass(eq=False, repr=False) +class Struct(betterproto.Message): + """ + `Struct` represents a structured data value, consisting of fields + which map to dynamically typed values. In some languages, `Struct` + might be supported by a native representation. For example, in + scripting languages like JS a struct is represented as an + object. The details of that representation are described together + with the proto support for the language. + + The JSON representation for `Struct` is JSON object. + """ + + fields: Dict[str, "Value"] = betterproto.map_field( + 1, betterproto.TYPE_STRING, betterproto.TYPE_MESSAGE + ) + """Unordered map of dynamically typed values.""" + + +@dataclass(eq=False, repr=False) +class Value(betterproto.Message): + """ + `Value` represents a dynamically typed value which can be either + null, a number, a string, a boolean, a recursive struct value, or a + list of values. A producer of value is expected to set one of that + variants, absence of any variant indicates an error. + + The JSON representation for `Value` is JSON value. + """ + + null_value: "NullValue" = betterproto.enum_field(1, group="kind") + """Represents a null value.""" + + number_value: float = betterproto.double_field(2, group="kind") + """Represents a double value.""" + + string_value: str = betterproto.string_field(3, group="kind") + """Represents a string value.""" + + bool_value: bool = betterproto.bool_field(4, group="kind") + """Represents a boolean value.""" + + struct_value: "Struct" = betterproto.message_field(5, group="kind") + """Represents a structured value.""" + + list_value: "ListValue" = betterproto.message_field(6, group="kind") + """Represents a repeated `Value`.""" + + +@dataclass(eq=False, repr=False) +class ListValue(betterproto.Message): + """ + `ListValue` is a wrapper around a repeated field of values. + + The JSON representation for `ListValue` is JSON array. + """ + + values: List["Value"] = betterproto.message_field(1, repeated=True) + """Repeated field of dynamically typed values.""" + + +@dataclass(eq=False, repr=False) +class Timestamp(betterproto.Message): + """ + A Timestamp represents a point in time independent of any time zone or local + calendar, encoded as a count of seconds and fractions of seconds at + nanosecond resolution. The count is relative to an epoch at UTC midnight on + January 1, 1970, in the proleptic Gregorian calendar which extends the + Gregorian calendar backwards to year one. + + All minutes are 60 seconds long. Leap seconds are "smeared" so that no leap + second table is needed for interpretation, using a [24-hour linear + smear](https://developers.google.com/time/smear). + + The range is from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z. By + restricting to that range, we ensure that we can convert to and from [RFC + 3339](https://www.ietf.org/rfc/rfc3339.txt) date strings. + + # Examples + + Example 1: Compute Timestamp from POSIX `time()`. + + Timestamp timestamp; + timestamp.set_seconds(time(NULL)); + timestamp.set_nanos(0); + + Example 2: Compute Timestamp from POSIX `gettimeofday()`. + + struct timeval tv; + gettimeofday(&tv, NULL); + + Timestamp timestamp; + timestamp.set_seconds(tv.tv_sec); + timestamp.set_nanos(tv.tv_usec * 1000); + + Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`. + + FILETIME ft; + GetSystemTimeAsFileTime(&ft); + UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime; + + // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z + // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z. + Timestamp timestamp; + timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL)); + timestamp.set_nanos((INT32) ((ticks % 10000000) * 100)); + + Example 4: Compute Timestamp from Java `System.currentTimeMillis()`. + + long millis = System.currentTimeMillis(); + + Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000) + .setNanos((int) ((millis % 1000) * 1000000)).build(); + + Example 5: Compute Timestamp from current time in Python. + + timestamp = Timestamp() + timestamp.GetCurrentTime() + + # JSON Mapping + + In JSON format, the Timestamp type is encoded as a string in the + [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format. That is, the + format is "{year}-{month}-{day}T{hour}:{min}:{sec}[.{frac_sec}]Z" + where {year} is always expressed using four digits while {month}, {day}, + {hour}, {min}, and {sec} are zero-padded to two digits each. The fractional + seconds, which can go up to 9 digits (i.e. up to 1 nanosecond resolution), + are optional. The "Z" suffix indicates the timezone ("UTC"); the timezone + is required. A proto3 JSON serializer should always use UTC (as indicated by + "Z") when printing the Timestamp type and a proto3 JSON parser should be + able to accept both UTC and other timezones (as indicated by an offset). + + For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past + 01:30 UTC on January 15, 2017. + + In JavaScript, one can convert a Date object to this format using the + standard + [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString) + method. In Python, a standard `datetime.datetime` object can be converted + to this format using + [`strftime`](https://docs.python.org/2/library/time.html#time.strftime) with + the time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one can use + the Joda Time's [`ISODateTimeFormat.dateTime()`]( + http://www.joda.org/joda-time/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime%2D%2D + ) to obtain a formatter capable of generating timestamps in this format. + """ + + seconds: int = betterproto.int64_field(1) + """ + Represents seconds of UTC time since Unix epoch + 1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to + 9999-12-31T23:59:59Z inclusive. + """ + + nanos: int = betterproto.int32_field(2) + """ + Non-negative fractions of a second at nanosecond resolution. Negative + second values with fractions must still have non-negative nanos values + that count forward in time. Must be from 0 to 999,999,999 + inclusive. + """ + + +@dataclass(eq=False, repr=False) +class DoubleValue(betterproto.Message): + """ + Wrapper message for `double`. + + The JSON representation for `DoubleValue` is JSON number. + """ + + value: float = betterproto.double_field(1) + """The double value.""" + + +@dataclass(eq=False, repr=False) +class FloatValue(betterproto.Message): + """ + Wrapper message for `float`. + + The JSON representation for `FloatValue` is JSON number. + """ + + value: float = betterproto.float_field(1) + """The float value.""" + + +@dataclass(eq=False, repr=False) +class Int64Value(betterproto.Message): + """ + Wrapper message for `int64`. + + The JSON representation for `Int64Value` is JSON string. + """ + + value: int = betterproto.int64_field(1) + """The int64 value.""" + + +@dataclass(eq=False, repr=False) +class UInt64Value(betterproto.Message): + """ + Wrapper message for `uint64`. + + The JSON representation for `UInt64Value` is JSON string. + """ + + value: int = betterproto.uint64_field(1) + """The uint64 value.""" + + +@dataclass(eq=False, repr=False) +class Int32Value(betterproto.Message): + """ + Wrapper message for `int32`. + + The JSON representation for `Int32Value` is JSON number. + """ + + value: int = betterproto.int32_field(1) + """The int32 value.""" + + +@dataclass(eq=False, repr=False) +class UInt32Value(betterproto.Message): + """ + Wrapper message for `uint32`. + + The JSON representation for `UInt32Value` is JSON number. + """ + + value: int = betterproto.uint32_field(1) + """The uint32 value.""" + + +@dataclass(eq=False, repr=False) +class BoolValue(betterproto.Message): + """ + Wrapper message for `bool`. + + The JSON representation for `BoolValue` is JSON `true` and `false`. + """ + + value: bool = betterproto.bool_field(1) + """The bool value.""" + + +@dataclass(eq=False, repr=False) +class StringValue(betterproto.Message): + """ + Wrapper message for `string`. + + The JSON representation for `StringValue` is JSON string. + """ + + value: str = betterproto.string_field(1) + """The string value.""" + + +@dataclass(eq=False, repr=False) +class BytesValue(betterproto.Message): + """ + Wrapper message for `bytes`. + + The JSON representation for `BytesValue` is JSON string. + """ + + value: bytes = betterproto.bytes_field(1) + """The bytes value.""" diff --git a/src/betterproto/plugin/models.py b/src/betterproto/plugin/models.py index e330e6884..3e249aae3 100644 --- a/src/betterproto/plugin/models.py +++ b/src/betterproto/plugin/models.py @@ -449,6 +449,8 @@ def betterproto_field_args(self) -> List[str]: args.append(f"wraps={self.field_wraps}") if self.optional: args.append(f"optional=True") + if self.repeated: + args.append(f"repeated=True") return args @property From c44b4ac78b2ad1c1979cbc1a456793023fbc18cc Mon Sep 17 00:00:00 2001 From: Adrien Vannson Date: Mon, 11 Nov 2024 14:05:55 +0100 Subject: [PATCH 02/37] Regenerate files --- .../lib/google/protobuf/__init__.py | 2519 +--------------- .../lib/std/google/protobuf/__init__.py | 2578 +++++++++-------- 2 files changed, 1301 insertions(+), 3796 deletions(-) diff --git a/src/betterproto/lib/google/protobuf/__init__.py b/src/betterproto/lib/google/protobuf/__init__.py index d3885ae54..dfc9d5586 100644 --- a/src/betterproto/lib/google/protobuf/__init__.py +++ b/src/betterproto/lib/google/protobuf/__init__.py @@ -1,2518 +1 @@ -# Generated by the protocol buffer compiler. DO NOT EDIT! -# sources: google/protobuf/any.proto, google/protobuf/api.proto, google/protobuf/descriptor.proto, google/protobuf/duration.proto, google/protobuf/empty.proto, google/protobuf/field_mask.proto, google/protobuf/source_context.proto, google/protobuf/struct.proto, google/protobuf/timestamp.proto, google/protobuf/type.proto, google/protobuf/wrappers.proto -# plugin: python-betterproto -# This file has been @generated - -__all__ = ( - "Syntax", - "FieldKind", - "FieldCardinality", - "FieldDescriptorProtoType", - "FieldDescriptorProtoLabel", - "FileOptionsOptimizeMode", - "FieldOptionsCType", - "FieldOptionsJsType", - "MethodOptionsIdempotencyLevel", - "NullValue", - "Any", - "SourceContext", - "Type", - "Field", - "Enum", - "EnumValue", - "Option", - "Api", - "Method", - "Mixin", - "FileDescriptorSet", - "FileDescriptorProto", - "DescriptorProto", - "DescriptorProtoExtensionRange", - "DescriptorProtoReservedRange", - "ExtensionRangeOptions", - "FieldDescriptorProto", - "OneofDescriptorProto", - "EnumDescriptorProto", - "EnumDescriptorProtoEnumReservedRange", - "EnumValueDescriptorProto", - "ServiceDescriptorProto", - "MethodDescriptorProto", - "FileOptions", - "MessageOptions", - "FieldOptions", - "OneofOptions", - "EnumOptions", - "EnumValueOptions", - "ServiceOptions", - "MethodOptions", - "UninterpretedOption", - "UninterpretedOptionNamePart", - "SourceCodeInfo", - "SourceCodeInfoLocation", - "GeneratedCodeInfo", - "GeneratedCodeInfoAnnotation", - "Duration", - "Empty", - "FieldMask", - "Struct", - "Value", - "ListValue", - "Timestamp", - "DoubleValue", - "FloatValue", - "Int64Value", - "UInt64Value", - "Int32Value", - "UInt32Value", - "BoolValue", - "StringValue", - "BytesValue", -) - -import warnings -from dataclasses import dataclass -from typing import ( - Dict, - List, -) - -import betterproto - - -class Syntax(betterproto.Enum): - """The syntax in which a protocol buffer element is defined.""" - - PROTO2 = 0 - """Syntax `proto2`.""" - - PROTO3 = 1 - """Syntax `proto3`.""" - - -class FieldKind(betterproto.Enum): - """Basic field types.""" - - TYPE_UNKNOWN = 0 - """Field type unknown.""" - - TYPE_DOUBLE = 1 - """Field type double.""" - - TYPE_FLOAT = 2 - """Field type float.""" - - TYPE_INT64 = 3 - """Field type int64.""" - - TYPE_UINT64 = 4 - """Field type uint64.""" - - TYPE_INT32 = 5 - """Field type int32.""" - - TYPE_FIXED64 = 6 - """Field type fixed64.""" - - TYPE_FIXED32 = 7 - """Field type fixed32.""" - - TYPE_BOOL = 8 - """Field type bool.""" - - TYPE_STRING = 9 - """Field type string.""" - - TYPE_GROUP = 10 - """Field type group. Proto2 syntax only, and deprecated.""" - - TYPE_MESSAGE = 11 - """Field type message.""" - - TYPE_BYTES = 12 - """Field type bytes.""" - - TYPE_UINT32 = 13 - """Field type uint32.""" - - TYPE_ENUM = 14 - """Field type enum.""" - - TYPE_SFIXED32 = 15 - """Field type sfixed32.""" - - TYPE_SFIXED64 = 16 - """Field type sfixed64.""" - - TYPE_SINT32 = 17 - """Field type sint32.""" - - TYPE_SINT64 = 18 - """Field type sint64.""" - - -class FieldCardinality(betterproto.Enum): - """Whether a field is optional, required, or repeated.""" - - CARDINALITY_UNKNOWN = 0 - """For fields with unknown cardinality.""" - - CARDINALITY_OPTIONAL = 1 - """For optional fields.""" - - CARDINALITY_REQUIRED = 2 - """For required fields. Proto2 syntax only.""" - - CARDINALITY_REPEATED = 3 - """For repeated fields.""" - - -class FieldDescriptorProtoType(betterproto.Enum): - """ """ - - TYPE_DOUBLE = 1 - """ - 0 is reserved for errors. - Order is weird for historical reasons. - """ - - TYPE_FLOAT = 2 - """ - - """ - - TYPE_INT64 = 3 - """ - Not ZigZag encoded. Negative numbers take 10 bytes. Use TYPE_SINT64 if - negative values are likely. - """ - - TYPE_UINT64 = 4 - """ - - """ - - TYPE_INT32 = 5 - """ - Not ZigZag encoded. Negative numbers take 10 bytes. Use TYPE_SINT32 if - negative values are likely. - """ - - TYPE_FIXED64 = 6 - """ - - """ - - TYPE_FIXED32 = 7 - """ - - """ - - TYPE_BOOL = 8 - """ - - """ - - TYPE_STRING = 9 - """ - - """ - - TYPE_GROUP = 10 - """ - Tag-delimited aggregate. - Group type is deprecated and not supported in proto3. However, Proto3 - implementations should still be able to parse the group wire format and - treat group fields as unknown fields. - """ - - TYPE_MESSAGE = 11 - """Length-delimited aggregate.""" - - TYPE_BYTES = 12 - """New in version 2.""" - - TYPE_UINT32 = 13 - """ - - """ - - TYPE_ENUM = 14 - """ - - """ - - TYPE_SFIXED32 = 15 - """ - - """ - - TYPE_SFIXED64 = 16 - """ - - """ - - TYPE_SINT32 = 17 - """Uses ZigZag encoding.""" - - TYPE_SINT64 = 18 - """Uses ZigZag encoding.""" - - -class FieldDescriptorProtoLabel(betterproto.Enum): - """ """ - - LABEL_OPTIONAL = 1 - """0 is reserved for errors""" - - LABEL_REQUIRED = 2 - """ - - """ - - LABEL_REPEATED = 3 - """ - - """ - - -class FileOptionsOptimizeMode(betterproto.Enum): - """Generated classes can be optimized for speed or code size.""" - - SPEED = 1 - """Generate complete code for parsing, serialization,""" - - CODE_SIZE = 2 - """ - etc. - - Use ReflectionOps to implement these methods. - """ - - LITE_RUNTIME = 3 - """Generate code using MessageLite and the lite runtime.""" - - -class FieldOptionsCType(betterproto.Enum): - """ """ - - STRING = 0 - """Default mode.""" - - CORD = 1 - """ - - """ - - STRING_PIECE = 2 - """ - - """ - - -class FieldOptionsJsType(betterproto.Enum): - """ """ - - JS_NORMAL = 0 - """Use the default type.""" - - JS_STRING = 1 - """Use JavaScript strings.""" - - JS_NUMBER = 2 - """Use JavaScript numbers.""" - - -class MethodOptionsIdempotencyLevel(betterproto.Enum): - """ - Is this method side-effect-free (or safe in HTTP parlance), or idempotent, - or neither? HTTP based RPC implementation may choose GET verb for safe - methods, and PUT verb for idempotent methods instead of the default POST. - """ - - IDEMPOTENCY_UNKNOWN = 0 - """ - - """ - - NO_SIDE_EFFECTS = 1 - """implies idempotent""" - - IDEMPOTENT = 2 - """idempotent, but may have side effects""" - - -class NullValue(betterproto.Enum): - """ - `NullValue` is a singleton enumeration to represent the null value for the - `Value` type union. - - The JSON representation for `NullValue` is JSON `null`. - """ - - _ = 0 - """Null value.""" - - -@dataclass(eq=False, repr=False) -class Any(betterproto.Message): - """ - `Any` contains an arbitrary serialized protocol buffer message along with a - URL that describes the type of the serialized message. - - Protobuf library provides support to pack/unpack Any values in the form - of utility functions or additional generated methods of the Any type. - - Example 1: Pack and unpack a message in C++. - - Foo foo = ...; - Any any; - any.PackFrom(foo); - ... - if (any.UnpackTo(&foo)) { - ... - } - - Example 2: Pack and unpack a message in Java. - - Foo foo = ...; - Any any = Any.pack(foo); - ... - if (any.is(Foo.class)) { - foo = any.unpack(Foo.class); - } - - Example 3: Pack and unpack a message in Python. - - foo = Foo(...) - any = Any() - any.Pack(foo) - ... - if any.Is(Foo.DESCRIPTOR): - any.Unpack(foo) - ... - - Example 4: Pack and unpack a message in Go - - foo := &pb.Foo{...} - any, err := ptypes.MarshalAny(foo) - ... - foo := &pb.Foo{} - if err := ptypes.UnmarshalAny(any, foo); err != nil { - ... - } - - The pack methods provided by protobuf library will by default use - 'type.googleapis.com/full.type.name' as the type URL and the unpack - methods only use the fully qualified type name after the last '/' - in the type URL, for example "foo.bar.com/x/y.z" will yield type - name "y.z". - - JSON - ==== - The JSON representation of an `Any` value uses the regular - representation of the deserialized, embedded message, with an - additional field `@type` which contains the type URL. Example: - - package google.profile; - message Person { - string first_name = 1; - string last_name = 2; - } - - { - "@type": "type.googleapis.com/google.profile.Person", - "firstName": , - "lastName": - } - - If the embedded message type is well-known and has a custom JSON - representation, that representation will be embedded adding a field - `value` which holds the custom JSON in addition to the `@type` - field. Example (for message [google.protobuf.Duration][]): - - { - "@type": "type.googleapis.com/google.protobuf.Duration", - "value": "1.212s" - } - """ - - type_url: str = betterproto.string_field(1) - """ - A URL/resource name that uniquely identifies the type of the serialized - protocol buffer message. This string must contain at least - one "/" character. The last segment of the URL's path must represent - the fully qualified name of the type (as in - `path/google.protobuf.Duration`). The name should be in a canonical form - (e.g., leading "." is not accepted). - - In practice, teams usually precompile into the binary all types that they - expect it to use in the context of Any. However, for URLs which use the - scheme `http`, `https`, or no scheme, one can optionally set up a type - server that maps type URLs to message definitions as follows: - - * If no scheme is provided, `https` is assumed. - * An HTTP GET on the URL must yield a [google.protobuf.Type][] - value in binary format, or produce an error. - * Applications are allowed to cache lookup results based on the - URL, or have them precompiled into a binary to avoid any - lookup. Therefore, binary compatibility needs to be preserved - on changes to types. (Use versioned type names to manage - breaking changes.) - - Note: this functionality is not currently available in the official - protobuf release, and it is not used for type URLs beginning with - type.googleapis.com. - - Schemes other than `http`, `https` (or the empty scheme) might be - used with implementation specific semantics. - """ - - value: bytes = betterproto.bytes_field(2) - """ - Must be a valid serialized protocol buffer of the above specified type. - """ - - -@dataclass(eq=False, repr=False) -class SourceContext(betterproto.Message): - """ - `SourceContext` represents information about the source of a - protobuf element, like the file in which it is defined. - """ - - file_name: str = betterproto.string_field(1) - """ - The path-qualified name of the .proto file that contained the associated - protobuf element. For example: `"google/protobuf/source_context.proto"`. - """ - - -@dataclass(eq=False, repr=False) -class Type(betterproto.Message): - """A protocol buffer message type.""" - - name: str = betterproto.string_field(1) - """The fully qualified message name.""" - - fields: List["Field"] = betterproto.message_field(2, repeated=True) - """The list of fields.""" - - oneofs: List[str] = betterproto.string_field(3, repeated=True) - """The list of types appearing in `oneof` definitions in this type.""" - - options: List["Option"] = betterproto.message_field(4, repeated=True) - """The protocol buffer options.""" - - source_context: "SourceContext" = betterproto.message_field(5) - """The source context.""" - - syntax: "Syntax" = betterproto.enum_field(6) - """The source syntax.""" - - -@dataclass(eq=False, repr=False) -class Field(betterproto.Message): - """A single field of a message type.""" - - kind: "FieldKind" = betterproto.enum_field(1) - """The field type.""" - - cardinality: "FieldCardinality" = betterproto.enum_field(2) - """The field cardinality.""" - - number: int = betterproto.int32_field(3) - """The field number.""" - - name: str = betterproto.string_field(4) - """The field name.""" - - type_url: str = betterproto.string_field(6) - """ - The field type URL, without the scheme, for message or enumeration - types. Example: `"type.googleapis.com/google.protobuf.Timestamp"`. - """ - - oneof_index: int = betterproto.int32_field(7) - """ - The index of the field type in `Type.oneofs`, for message or enumeration - types. The first type has index 1; zero means the type is not in the list. - """ - - packed: bool = betterproto.bool_field(8) - """Whether to use alternative packed wire representation.""" - - options: List["Option"] = betterproto.message_field(9, repeated=True) - """The protocol buffer options.""" - - json_name: str = betterproto.string_field(10) - """The field JSON name.""" - - default_value: str = betterproto.string_field(11) - """ - The string value of the default value of this field. Proto2 syntax only. - """ - - -@dataclass(eq=False, repr=False) -class Enum(betterproto.Message): - """Enum type definition.""" - - name: str = betterproto.string_field(1) - """Enum type name.""" - - enumvalue: List["EnumValue"] = betterproto.message_field( - 2, wraps=betterproto.TYPE_ENUM, repeated=True - ) - """Enum value definitions.""" - - options: List["Option"] = betterproto.message_field(3, repeated=True) - """Protocol buffer options.""" - - source_context: "SourceContext" = betterproto.message_field(4) - """The source context.""" - - syntax: "Syntax" = betterproto.enum_field(5) - """The source syntax.""" - - -@dataclass(eq=False, repr=False) -class EnumValue(betterproto.Message): - """Enum value definition.""" - - name: str = betterproto.string_field(1) - """Enum value name.""" - - number: int = betterproto.int32_field(2) - """Enum value number.""" - - options: List["Option"] = betterproto.message_field(3, repeated=True) - """Protocol buffer options.""" - - -@dataclass(eq=False, repr=False) -class Option(betterproto.Message): - """ - A protocol buffer option, which can be attached to a message, field, - enumeration, etc. - """ - - name: str = betterproto.string_field(1) - """ - The option's name. For protobuf built-in options (options defined in - descriptor.proto), this is the short name. For example, `"map_entry"`. - For custom options, it should be the fully-qualified name. For example, - `"google.api.http"`. - """ - - value: "Any" = betterproto.message_field(2) - """ - The option's value packed in an Any message. If the value is a primitive, - the corresponding wrapper type defined in google/protobuf/wrappers.proto - should be used. If the value is an enum, it should be stored as an int32 - value using the google.protobuf.Int32Value type. - """ - - -@dataclass(eq=False, repr=False) -class Api(betterproto.Message): - """ - Api is a light-weight descriptor for an API Interface. - - Interfaces are also described as "protocol buffer services" in some contexts, - such as by the "service" keyword in a .proto file, but they are different - from API Services, which represent a concrete implementation of an interface - as opposed to simply a description of methods and bindings. They are also - sometimes simply referred to as "APIs" in other contexts, such as the name of - this message itself. See https://cloud.google.com/apis/design/glossary for - detailed terminology. - """ - - name: str = betterproto.string_field(1) - """ - The fully qualified name of this interface, including package name - followed by the interface's simple name. - """ - - methods: List["Method"] = betterproto.message_field(2, repeated=True) - """The methods of this interface, in unspecified order.""" - - options: List["Option"] = betterproto.message_field(3, repeated=True) - """Any metadata attached to the interface.""" - - version: str = betterproto.string_field(4) - """ - A version string for this interface. If specified, must have the form - `major-version.minor-version`, as in `1.10`. If the minor version is - omitted, it defaults to zero. If the entire version field is empty, the - major version is derived from the package name, as outlined below. If the - field is not empty, the version in the package name will be verified to be - consistent with what is provided here. - - The versioning schema uses [semantic - versioning](http://semver.org) where the major version number - indicates a breaking change and the minor version an additive, - non-breaking change. Both version numbers are signals to users - what to expect from different versions, and should be carefully - chosen based on the product plan. - - The major version is also reflected in the package name of the - interface, which must end in `v`, as in - `google.feature.v1`. For major versions 0 and 1, the suffix can - be omitted. Zero major versions must only be used for - experimental, non-GA interfaces. - """ - - source_context: "SourceContext" = betterproto.message_field(5) - """ - Source context for the protocol buffer service represented by this - message. - """ - - mixins: List["Mixin"] = betterproto.message_field(6, repeated=True) - """Included interfaces. See [Mixin][].""" - - syntax: "Syntax" = betterproto.enum_field(7) - """The source syntax of the service.""" - - -@dataclass(eq=False, repr=False) -class Method(betterproto.Message): - """Method represents a method of an API interface.""" - - name: str = betterproto.string_field(1) - """The simple name of this method.""" - - request_type_url: str = betterproto.string_field(2) - """A URL of the input message type.""" - - request_streaming: bool = betterproto.bool_field(3) - """If true, the request is streamed.""" - - response_type_url: str = betterproto.string_field(4) - """The URL of the output message type.""" - - response_streaming: bool = betterproto.bool_field(5) - """If true, the response is streamed.""" - - options: List["Option"] = betterproto.message_field(6, repeated=True) - """Any metadata attached to the method.""" - - syntax: "Syntax" = betterproto.enum_field(7) - """The source syntax of this method.""" - - -@dataclass(eq=False, repr=False) -class Mixin(betterproto.Message): - """ - Declares an API Interface to be included in this interface. The including - interface must redeclare all the methods from the included interface, but - documentation and options are inherited as follows: - - - If after comment and whitespace stripping, the documentation - string of the redeclared method is empty, it will be inherited - from the original method. - - - Each annotation belonging to the service config (http, - visibility) which is not set in the redeclared method will be - inherited. - - - If an http annotation is inherited, the path pattern will be - modified as follows. Any version prefix will be replaced by the - version of the including interface plus the [root][] path if - specified. - - Example of a simple mixin: - - package google.acl.v1; - service AccessControl { - // Get the underlying ACL object. - rpc GetAcl(GetAclRequest) returns (Acl) { - option (google.api.http).get = "/v1/{resource=**}:getAcl"; - } - } - - package google.storage.v2; - service Storage { - rpc GetAcl(GetAclRequest) returns (Acl); - - // Get a data record. - rpc GetData(GetDataRequest) returns (Data) { - option (google.api.http).get = "/v2/{resource=**}"; - } - } - - Example of a mixin configuration: - - apis: - - name: google.storage.v2.Storage - mixins: - - name: google.acl.v1.AccessControl - - The mixin construct implies that all methods in `AccessControl` are - also declared with same name and request/response types in - `Storage`. A documentation generator or annotation processor will - see the effective `Storage.GetAcl` method after inherting - documentation and annotations as follows: - - service Storage { - // Get the underlying ACL object. - rpc GetAcl(GetAclRequest) returns (Acl) { - option (google.api.http).get = "/v2/{resource=**}:getAcl"; - } - ... - } - - Note how the version in the path pattern changed from `v1` to `v2`. - - If the `root` field in the mixin is specified, it should be a - relative path under which inherited HTTP paths are placed. Example: - - apis: - - name: google.storage.v2.Storage - mixins: - - name: google.acl.v1.AccessControl - root: acls - - This implies the following inherited HTTP annotation: - - service Storage { - // Get the underlying ACL object. - rpc GetAcl(GetAclRequest) returns (Acl) { - option (google.api.http).get = "/v2/acls/{resource=**}:getAcl"; - } - ... - } - """ - - name: str = betterproto.string_field(1) - """The fully qualified name of the interface which is included.""" - - root: str = betterproto.string_field(2) - """ - If non-empty specifies a path under which inherited HTTP paths - are rooted. - """ - - -@dataclass(eq=False, repr=False) -class FileDescriptorSet(betterproto.Message): - """ - The protocol compiler can output a FileDescriptorSet containing the .proto - files it parses. - """ - - file: List["FileDescriptorProto"] = betterproto.message_field(1, repeated=True) - """ - - """ - - -@dataclass(eq=False, repr=False) -class FileDescriptorProto(betterproto.Message): - """Describes a complete .proto file.""" - - name: str = betterproto.string_field(1) - """file name, relative to root of source tree""" - - package: str = betterproto.string_field(2) - """e.g. "foo", "foo.bar", etc.""" - - dependency: List[str] = betterproto.string_field(3, repeated=True) - """Names of files imported by this file.""" - - public_dependency: List[int] = betterproto.int32_field(10, repeated=True) - """Indexes of the public imported files in the dependency list above.""" - - weak_dependency: List[int] = betterproto.int32_field(11, repeated=True) - """ - Indexes of the weak imported files in the dependency list. - For Google-internal migration only. Do not use. - """ - - message_type: List["DescriptorProto"] = betterproto.message_field(4, repeated=True) - """All top-level definitions in this file.""" - - enum_type: List["EnumDescriptorProto"] = betterproto.message_field(5, repeated=True) - """ - - """ - - service: List["ServiceDescriptorProto"] = betterproto.message_field( - 6, repeated=True - ) - """ - - """ - - extension: List["FieldDescriptorProto"] = betterproto.message_field( - 7, repeated=True - ) - """ - - """ - - options: "FileOptions" = betterproto.message_field(8) - """ - - """ - - source_code_info: "SourceCodeInfo" = betterproto.message_field(9) - """ - This field contains optional information about the original source code. - You may safely remove this entire field without harming runtime - functionality of the descriptors -- the information is needed only by - development tools. - """ - - syntax: str = betterproto.string_field(12) - """ - The syntax of the proto file. - The supported values are "proto2" and "proto3". - """ - - -@dataclass(eq=False, repr=False) -class DescriptorProto(betterproto.Message): - """Describes a message type.""" - - name: str = betterproto.string_field(1) - """ - - """ - - field: List["FieldDescriptorProto"] = betterproto.message_field(2, repeated=True) - """ - - """ - - extension: List["FieldDescriptorProto"] = betterproto.message_field( - 6, repeated=True - ) - """ - - """ - - nested_type: List["DescriptorProto"] = betterproto.message_field(3, repeated=True) - """ - - """ - - enum_type: List["EnumDescriptorProto"] = betterproto.message_field(4, repeated=True) - """ - - """ - - extension_range: List["DescriptorProtoExtensionRange"] = betterproto.message_field( - 5, repeated=True - ) - """ - - """ - - oneof_decl: List["OneofDescriptorProto"] = betterproto.message_field( - 8, repeated=True - ) - """ - - """ - - options: "MessageOptions" = betterproto.message_field(7) - """ - - """ - - reserved_range: List["DescriptorProtoReservedRange"] = betterproto.message_field( - 9, repeated=True - ) - """ - - """ - - reserved_name: List[str] = betterproto.string_field(10, repeated=True) - """ - Reserved field names, which may not be used by fields in the same message. - A given name may only be reserved once. - """ - - -@dataclass(eq=False, repr=False) -class DescriptorProtoExtensionRange(betterproto.Message): - """ """ - - start: int = betterproto.int32_field(1) - """Inclusive.""" - - end: int = betterproto.int32_field(2) - """Exclusive.""" - - options: "ExtensionRangeOptions" = betterproto.message_field(3) - """ - - """ - - -@dataclass(eq=False, repr=False) -class DescriptorProtoReservedRange(betterproto.Message): - """ - Range of reserved tag numbers. Reserved tag numbers may not be used by - fields or extension ranges in the same message. Reserved ranges may - not overlap. - """ - - start: int = betterproto.int32_field(1) - """Inclusive.""" - - end: int = betterproto.int32_field(2) - """Exclusive.""" - - -@dataclass(eq=False, repr=False) -class ExtensionRangeOptions(betterproto.Message): - """ """ - - uninterpreted_option: List["UninterpretedOption"] = betterproto.message_field( - 999, repeated=True - ) - """The parser stores options it doesn't recognize here. See above.""" - - -@dataclass(eq=False, repr=False) -class FieldDescriptorProto(betterproto.Message): - """Describes a field within a message.""" - - name: str = betterproto.string_field(1) - """ - - """ - - number: int = betterproto.int32_field(3) - """ - - """ - - label: "FieldDescriptorProtoLabel" = betterproto.enum_field(4) - """ - - """ - - type: "FieldDescriptorProtoType" = betterproto.enum_field(5) - """ - If type_name is set, this need not be set. If both this and type_name - are set, this must be one of TYPE_ENUM, TYPE_MESSAGE or TYPE_GROUP. - """ - - type_name: str = betterproto.string_field(6) - """ - For message and enum types, this is the name of the type. If the name - starts with a '.', it is fully-qualified. Otherwise, C++-like scoping - rules are used to find the type (i.e. first the nested types within this - message are searched, then within the parent, on up to the root - namespace). - """ - - extendee: str = betterproto.string_field(2) - """ - For extensions, this is the name of the type being extended. It is - resolved in the same manner as type_name. - """ - - default_value: str = betterproto.string_field(7) - """ - For numeric types, contains the original text representation of the value. - For booleans, "true" or "false". - For strings, contains the default text contents (not escaped in any way). - For bytes, contains the C escaped value. All bytes >= 128 are escaped. - TODO(kenton): Base-64 encode? - """ - - oneof_index: int = betterproto.int32_field(9) - """ - If set, gives the index of a oneof in the containing type's oneof_decl - list. This field is a member of that oneof. - """ - - json_name: str = betterproto.string_field(10) - """ - JSON name of this field. The value is set by protocol compiler. If the - user has set a "json_name" option on this field, that option's value - will be used. Otherwise, it's deduced from the field's name by converting - it to camelCase. - """ - - options: "FieldOptions" = betterproto.message_field(8) - """ - - """ - - proto3_optional: bool = betterproto.bool_field(17) - """ - If true, this is a proto3 "optional". When a proto3 field is optional, it - tracks presence regardless of field type. - - When proto3_optional is true, this field must be belong to a oneof to - signal to old proto3 clients that presence is tracked for this field. This - oneof is known as a "synthetic" oneof, and this field must be its sole - member (each proto3 optional field gets its own synthetic oneof). Synthetic - oneofs exist in the descriptor only, and do not generate any API. Synthetic - oneofs must be ordered after all "real" oneofs. - - For message fields, proto3_optional doesn't create any semantic change, - since non-repeated message fields always track presence. However it still - indicates the semantic detail of whether the user wrote "optional" or not. - This can be useful for round-tripping the .proto file. For consistency we - give message fields a synthetic oneof also, even though it is not required - to track presence. This is especially important because the parser can't - tell if a field is a message or an enum, so it must always create a - synthetic oneof. - - Proto2 optional fields do not set this flag, because they already indicate - optional with `LABEL_OPTIONAL`. - """ - - -@dataclass(eq=False, repr=False) -class OneofDescriptorProto(betterproto.Message): - """Describes a oneof.""" - - name: str = betterproto.string_field(1) - """ - - """ - - options: "OneofOptions" = betterproto.message_field(2) - """ - - """ - - -@dataclass(eq=False, repr=False) -class EnumDescriptorProto(betterproto.Message): - """Describes an enum type.""" - - name: str = betterproto.string_field(1) - """ - - """ - - value: List["EnumValueDescriptorProto"] = betterproto.message_field( - 2, repeated=True - ) - """ - - """ - - options: "EnumOptions" = betterproto.message_field(3) - """ - - """ - - reserved_range: List["EnumDescriptorProtoEnumReservedRange"] = ( - betterproto.message_field(4, repeated=True) - ) - """ - Range of reserved numeric values. Reserved numeric values may not be used - by enum values in the same enum declaration. Reserved ranges may not - overlap. - """ - - reserved_name: List[str] = betterproto.string_field(5, repeated=True) - """ - Reserved enum value names, which may not be reused. A given name may only - be reserved once. - """ - - -@dataclass(eq=False, repr=False) -class EnumDescriptorProtoEnumReservedRange(betterproto.Message): - """ - Range of reserved numeric values. Reserved values may not be used by - entries in the same enum. Reserved ranges may not overlap. - - Note that this is distinct from DescriptorProto.ReservedRange in that it - is inclusive such that it can appropriately represent the entire int32 - domain. - """ - - start: int = betterproto.int32_field(1) - """Inclusive.""" - - end: int = betterproto.int32_field(2) - """Inclusive.""" - - -@dataclass(eq=False, repr=False) -class EnumValueDescriptorProto(betterproto.Message): - """Describes a value within an enum.""" - - name: str = betterproto.string_field(1) - """ - - """ - - number: int = betterproto.int32_field(2) - """ - - """ - - options: "EnumValueOptions" = betterproto.message_field(3) - """ - - """ - - -@dataclass(eq=False, repr=False) -class ServiceDescriptorProto(betterproto.Message): - """Describes a service.""" - - name: str = betterproto.string_field(1) - """ - - """ - - method: List["MethodDescriptorProto"] = betterproto.message_field(2, repeated=True) - """ - - """ - - options: "ServiceOptions" = betterproto.message_field(3) - """ - - """ - - -@dataclass(eq=False, repr=False) -class MethodDescriptorProto(betterproto.Message): - """Describes a method of a service.""" - - name: str = betterproto.string_field(1) - """ - - """ - - input_type: str = betterproto.string_field(2) - """ - Input and output type names. These are resolved in the same way as - FieldDescriptorProto.type_name, but must refer to a message type. - """ - - output_type: str = betterproto.string_field(3) - """ - - """ - - options: "MethodOptions" = betterproto.message_field(4) - """ - - """ - - client_streaming: bool = betterproto.bool_field(5) - """Identifies if client streams multiple client messages""" - - server_streaming: bool = betterproto.bool_field(6) - """Identifies if server streams multiple server messages""" - - -@dataclass(eq=False, repr=False) -class FileOptions(betterproto.Message): - """ - =================================================================== - Options - - Each of the definitions above may have "options" attached. These are - just annotations which may cause code to be generated slightly differently - or may contain hints for code that manipulates protocol messages. - - Clients may define custom options as extensions of the *Options messages. - These extensions may not yet be known at parsing time, so the parser cannot - store the values in them. Instead it stores them in a field in the *Options - message called uninterpreted_option. This field must have the same name - across all *Options messages. We then use this field to populate the - extensions when we build a descriptor, at which point all protos have been - parsed and so all extensions are known. - - Extension numbers for custom options may be chosen as follows: - * For options which will only be used within a single application or - organization, or for experimental options, use field numbers 50000 - through 99999. It is up to you to ensure that you do not use the - same number for multiple options. - * For options which will be published and used publicly by multiple - independent entities, e-mail protobuf-global-extension-registry@google.com - to reserve extension numbers. Simply provide your project name (e.g. - Objective-C plugin) and your project website (if available) -- there's no - need to explain how you intend to use them. Usually you only need one - extension number. You can declare multiple options with only one extension - number by putting them in a sub-message. See the Custom Options section of - the docs for examples: - https://developers.google.com/protocol-buffers/docs/proto#options - If this turns out to be popular, a web service will be set up - to automatically assign option numbers. - """ - - java_package: str = betterproto.string_field(1) - """ - Sets the Java package where classes generated from this .proto will be - placed. By default, the proto package is used, but this is often - inappropriate because proto packages do not normally start with backwards - domain names. - """ - - java_outer_classname: str = betterproto.string_field(8) - """ - If set, all the classes from the .proto file are wrapped in a single - outer class with the given name. This applies to both Proto1 - (equivalent to the old "--one_java_file" option) and Proto2 (where - a .proto always translates to a single class, but you may want to - explicitly choose the class name). - """ - - java_multiple_files: bool = betterproto.bool_field(10) - """ - If set true, then the Java code generator will generate a separate .java - file for each top-level message, enum, and service defined in the .proto - file. Thus, these types will *not* be nested inside the outer class - named by java_outer_classname. However, the outer class will still be - generated to contain the file's getDescriptor() method as well as any - top-level extensions defined in the file. - """ - - java_generate_equals_and_hash: bool = betterproto.bool_field(20) - """This option does nothing.""" - - java_string_check_utf8: bool = betterproto.bool_field(27) - """ - If set true, then the Java2 code generator will generate code that - throws an exception whenever an attempt is made to assign a non-UTF-8 - byte sequence to a string field. - Message reflection will do the same. - However, an extension field still accepts non-UTF-8 byte sequences. - This option has no effect on when used with the lite runtime. - """ - - optimize_for: "FileOptionsOptimizeMode" = betterproto.enum_field(9) - """ - - """ - - go_package: str = betterproto.string_field(11) - """ - Sets the Go package where structs generated from this .proto will be - placed. If omitted, the Go package will be derived from the following: - - The basename of the package import path, if provided. - - Otherwise, the package statement in the .proto file, if present. - - Otherwise, the basename of the .proto file, without extension. - """ - - cc_generic_services: bool = betterproto.bool_field(16) - """ - Should generic services be generated in each language? "Generic" services - are not specific to any particular RPC system. They are generated by the - main code generators in each language (without additional plugins). - Generic services were the only kind of service generation supported by - early versions of google.protobuf. - - Generic services are now considered deprecated in favor of using plugins - that generate code specific to your particular RPC system. Therefore, - these default to false. Old code which depends on generic services should - explicitly set them to true. - """ - - java_generic_services: bool = betterproto.bool_field(17) - """ - - """ - - py_generic_services: bool = betterproto.bool_field(18) - """ - - """ - - php_generic_services: bool = betterproto.bool_field(42) - """ - - """ - - deprecated: bool = betterproto.bool_field(23) - """ - Is this file deprecated? - Depending on the target platform, this can emit Deprecated annotations - for everything in the file, or it will be completely ignored; in the very - least, this is a formalization for deprecating files. - """ - - cc_enable_arenas: bool = betterproto.bool_field(31) - """ - Enables the use of arenas for the proto messages in this file. This applies - only to generated classes for C++. - """ - - objc_class_prefix: str = betterproto.string_field(36) - """ - Sets the objective c class prefix which is prepended to all objective c - generated classes from this .proto. There is no default. - """ - - csharp_namespace: str = betterproto.string_field(37) - """Namespace for generated classes; defaults to the package.""" - - swift_prefix: str = betterproto.string_field(39) - """ - By default Swift generators will take the proto package and CamelCase it - replacing '.' with underscore and use that to prefix the types/symbols - defined. When this options is provided, they will use this value instead - to prefix the types/symbols defined. - """ - - php_class_prefix: str = betterproto.string_field(40) - """ - Sets the php class prefix which is prepended to all php generated classes - from this .proto. Default is empty. - """ - - php_namespace: str = betterproto.string_field(41) - """ - Use this option to change the namespace of php generated classes. Default - is empty. When this option is empty, the package name will be used for - determining the namespace. - """ - - php_metadata_namespace: str = betterproto.string_field(44) - """ - Use this option to change the namespace of php generated metadata classes. - Default is empty. When this option is empty, the proto file name will be - used for determining the namespace. - """ - - ruby_package: str = betterproto.string_field(45) - """ - Use this option to change the package of ruby generated classes. Default - is empty. When this option is not set, the package name will be used for - determining the ruby package. - """ - - uninterpreted_option: List["UninterpretedOption"] = betterproto.message_field( - 999, repeated=True - ) - """ - The parser stores options it doesn't recognize here. - See the documentation for the "Options" section above. - """ - - def __post_init__(self) -> None: - super().__post_init__() - if self.is_set("java_generate_equals_and_hash"): - warnings.warn( - "FileOptions.java_generate_equals_and_hash is deprecated", - DeprecationWarning, - ) - - -@dataclass(eq=False, repr=False) -class MessageOptions(betterproto.Message): - """ """ - - message_set_wire_format: bool = betterproto.bool_field(1) - """ - Set true to use the old proto1 MessageSet wire format for extensions. - This is provided for backwards-compatibility with the MessageSet wire - format. You should not use this for any other reason: It's less - efficient, has fewer features, and is more complicated. - - The message must be defined exactly as follows: - message Foo { - option message_set_wire_format = true; - extensions 4 to max; - } - Note that the message cannot have any defined fields; MessageSets only - have extensions. - - All extensions of your type must be singular messages; e.g. they cannot - be int32s, enums, or repeated messages. - - Because this is an option, the above two restrictions are not enforced by - the protocol compiler. - """ - - no_standard_descriptor_accessor: bool = betterproto.bool_field(2) - """ - Disables the generation of the standard "descriptor()" accessor, which can - conflict with a field of the same name. This is meant to make migration - from proto1 easier; new code should avoid fields named "descriptor". - """ - - deprecated: bool = betterproto.bool_field(3) - """ - Is this message deprecated? - Depending on the target platform, this can emit Deprecated annotations - for the message, or it will be completely ignored; in the very least, - this is a formalization for deprecating messages. - """ - - map_entry: bool = betterproto.bool_field(7) - """ - Whether the message is an automatically generated map entry type for the - maps field. - - For maps fields: - map map_field = 1; - The parsed descriptor looks like: - message MapFieldEntry { - option map_entry = true; - optional KeyType key = 1; - optional ValueType value = 2; - } - repeated MapFieldEntry map_field = 1; - - Implementations may choose not to generate the map_entry=true message, but - use a native map in the target language to hold the keys and values. - The reflection APIs in such implementations still need to work as - if the field is a repeated message field. - - NOTE: Do not set the option in .proto files. Always use the maps syntax - instead. The option should only be implicitly set by the proto compiler - parser. - """ - - uninterpreted_option: List["UninterpretedOption"] = betterproto.message_field( - 999, repeated=True - ) - """The parser stores options it doesn't recognize here. See above.""" - - -@dataclass(eq=False, repr=False) -class FieldOptions(betterproto.Message): - """ """ - - ctype: "FieldOptionsCType" = betterproto.enum_field(1) - """ - The ctype option instructs the C++ code generator to use a different - representation of the field than it normally would. See the specific - options below. This option is not yet implemented in the open source - release -- sorry, we'll try to include it in a future version! - """ - - packed: bool = betterproto.bool_field(2) - """ - The packed option can be enabled for repeated primitive fields to enable - a more efficient representation on the wire. Rather than repeatedly - writing the tag and type for each element, the entire array is encoded as - a single length-delimited blob. In proto3, only explicit setting it to - false will avoid using packed encoding. - """ - - jstype: "FieldOptionsJsType" = betterproto.enum_field(6) - """ - The jstype option determines the JavaScript type used for values of the - field. The option is permitted only for 64 bit integral and fixed types - (int64, uint64, sint64, fixed64, sfixed64). A field with jstype JS_STRING - is represented as JavaScript string, which avoids loss of precision that - can happen when a large value is converted to a floating point JavaScript. - Specifying JS_NUMBER for the jstype causes the generated JavaScript code to - use the JavaScript "number" type. The behavior of the default option - JS_NORMAL is implementation dependent. - - This option is an enum to permit additional types to be added, e.g. - goog.math.Integer. - """ - - lazy: bool = betterproto.bool_field(5) - """ - Should this field be parsed lazily? Lazy applies only to message-type - fields. It means that when the outer message is initially parsed, the - inner message's contents will not be parsed but instead stored in encoded - form. The inner message will actually be parsed when it is first accessed. - - This is only a hint. Implementations are free to choose whether to use - eager or lazy parsing regardless of the value of this option. However, - setting this option true suggests that the protocol author believes that - using lazy parsing on this field is worth the additional bookkeeping - overhead typically needed to implement it. - - This option does not affect the public interface of any generated code; - all method signatures remain the same. Furthermore, thread-safety of the - interface is not affected by this option; const methods remain safe to - call from multiple threads concurrently, while non-const methods continue - to require exclusive access. - - Note that implementations may choose not to check required fields within - a lazy sub-message. That is, calling IsInitialized() on the outer message - may return true even if the inner message has missing required fields. - This is necessary because otherwise the inner message would have to be - parsed in order to perform the check, defeating the purpose of lazy - parsing. An implementation which chooses not to check required fields - must be consistent about it. That is, for any particular sub-message, the - implementation must either *always* check its required fields, or *never* - check its required fields, regardless of whether or not the message has - been parsed. - """ - - deprecated: bool = betterproto.bool_field(3) - """ - Is this field deprecated? - Depending on the target platform, this can emit Deprecated annotations - for accessors, or it will be completely ignored; in the very least, this - is a formalization for deprecating fields. - """ - - weak: bool = betterproto.bool_field(10) - """For Google-internal migration only. Do not use.""" - - uninterpreted_option: List["UninterpretedOption"] = betterproto.message_field( - 999, repeated=True - ) - """The parser stores options it doesn't recognize here. See above.""" - - -@dataclass(eq=False, repr=False) -class OneofOptions(betterproto.Message): - """ """ - - uninterpreted_option: List["UninterpretedOption"] = betterproto.message_field( - 999, repeated=True - ) - """The parser stores options it doesn't recognize here. See above.""" - - -@dataclass(eq=False, repr=False) -class EnumOptions(betterproto.Message): - """ """ - - allow_alias: bool = betterproto.bool_field(2) - """ - Set this option to true to allow mapping different tag names to the same - value. - """ - - deprecated: bool = betterproto.bool_field(3) - """ - Is this enum deprecated? - Depending on the target platform, this can emit Deprecated annotations - for the enum, or it will be completely ignored; in the very least, this - is a formalization for deprecating enums. - """ - - uninterpreted_option: List["UninterpretedOption"] = betterproto.message_field( - 999, repeated=True - ) - """The parser stores options it doesn't recognize here. See above.""" - - -@dataclass(eq=False, repr=False) -class EnumValueOptions(betterproto.Message): - """ """ - - deprecated: bool = betterproto.bool_field(1) - """ - Is this enum value deprecated? - Depending on the target platform, this can emit Deprecated annotations - for the enum value, or it will be completely ignored; in the very least, - this is a formalization for deprecating enum values. - """ - - uninterpreted_option: List["UninterpretedOption"] = betterproto.message_field( - 999, repeated=True - ) - """The parser stores options it doesn't recognize here. See above.""" - - -@dataclass(eq=False, repr=False) -class ServiceOptions(betterproto.Message): - """ """ - - deprecated: bool = betterproto.bool_field(33) - """ - Note: Field numbers 1 through 32 are reserved for Google's internal RPC - framework. We apologize for hoarding these numbers to ourselves, but - we were already using them long before we decided to release Protocol - Buffers. - - Is this service deprecated? - Depending on the target platform, this can emit Deprecated annotations - for the service, or it will be completely ignored; in the very least, - this is a formalization for deprecating services. - """ - - uninterpreted_option: List["UninterpretedOption"] = betterproto.message_field( - 999, repeated=True - ) - """The parser stores options it doesn't recognize here. See above.""" - - -@dataclass(eq=False, repr=False) -class MethodOptions(betterproto.Message): - """ """ - - deprecated: bool = betterproto.bool_field(33) - """ - Note: Field numbers 1 through 32 are reserved for Google's internal RPC - framework. We apologize for hoarding these numbers to ourselves, but - we were already using them long before we decided to release Protocol - Buffers. - - Is this method deprecated? - Depending on the target platform, this can emit Deprecated annotations - for the method, or it will be completely ignored; in the very least, - this is a formalization for deprecating methods. - """ - - idempotency_level: "MethodOptionsIdempotencyLevel" = betterproto.enum_field(34) - """ - - """ - - uninterpreted_option: List["UninterpretedOption"] = betterproto.message_field( - 999, repeated=True - ) - """The parser stores options it doesn't recognize here. See above.""" - - -@dataclass(eq=False, repr=False) -class UninterpretedOption(betterproto.Message): - """ - A message representing a option the parser does not recognize. This only - appears in options protos created by the compiler::Parser class. - DescriptorPool resolves these when building Descriptor objects. Therefore, - options protos in descriptor objects (e.g. returned by Descriptor::options(), - or produced by Descriptor::CopyTo()) will never have UninterpretedOptions - in them. - """ - - name: List["UninterpretedOptionNamePart"] = betterproto.message_field( - 2, repeated=True - ) - """ - - """ - - identifier_value: str = betterproto.string_field(3) - """ - The value of the uninterpreted option, in whatever type the tokenizer - identified it as during parsing. Exactly one of these should be set. - """ - - positive_int_value: int = betterproto.uint64_field(4) - """ - - """ - - negative_int_value: int = betterproto.int64_field(5) - """ - - """ - - double_value: float = betterproto.double_field(6) - """ - - """ - - string_value: bytes = betterproto.bytes_field(7) - """ - - """ - - aggregate_value: str = betterproto.string_field(8) - """ - - """ - - -@dataclass(eq=False, repr=False) -class UninterpretedOptionNamePart(betterproto.Message): - """ - The name of the uninterpreted option. Each string represents a segment in - a dot-separated name. is_extension is true iff a segment represents an - extension (denoted with parentheses in options specs in .proto files). - E.g.,{ ["foo", false], ["bar.baz", true], ["qux", false] } represents - "foo.(bar.baz).qux". - """ - - name_part: str = betterproto.string_field(1) - """ - - """ - - is_extension: bool = betterproto.bool_field(2) - """ - - """ - - -@dataclass(eq=False, repr=False) -class SourceCodeInfo(betterproto.Message): - """ - =================================================================== - Optional source code info - - Encapsulates information about the original source file from which a - FileDescriptorProto was generated. - """ - - location: List["SourceCodeInfoLocation"] = betterproto.message_field( - 1, repeated=True - ) - """ - A Location identifies a piece of source code in a .proto file which - corresponds to a particular definition. This information is intended - to be useful to IDEs, code indexers, documentation generators, and similar - tools. - - For example, say we have a file like: - message Foo { - optional string foo = 1; - } - Let's look at just the field definition: - optional string foo = 1; - ^ ^^ ^^ ^ ^^^ - a bc de f ghi - We have the following locations: - span path represents - [a,i) [ 4, 0, 2, 0 ] The whole field definition. - [a,b) [ 4, 0, 2, 0, 4 ] The label (optional). - [c,d) [ 4, 0, 2, 0, 5 ] The type (string). - [e,f) [ 4, 0, 2, 0, 1 ] The name (foo). - [g,h) [ 4, 0, 2, 0, 3 ] The number (1). - - Notes: - - A location may refer to a repeated field itself (i.e. not to any - particular index within it). This is used whenever a set of elements are - logically enclosed in a single code segment. For example, an entire - extend block (possibly containing multiple extension definitions) will - have an outer location whose path refers to the "extensions" repeated - field without an index. - - Multiple locations may have the same path. This happens when a single - logical declaration is spread out across multiple places. The most - obvious example is the "extend" block again -- there may be multiple - extend blocks in the same scope, each of which will have the same path. - - A location's span is not always a subset of its parent's span. For - example, the "extendee" of an extension declaration appears at the - beginning of the "extend" block and is shared by all extensions within - the block. - - Just because a location's span is a subset of some other location's span - does not mean that it is a descendant. For example, a "group" defines - both a type and a field in a single declaration. Thus, the locations - corresponding to the type and field and their components will overlap. - - Code which tries to interpret locations should probably be designed to - ignore those that it doesn't understand, as more types of locations could - be recorded in the future. - """ - - -@dataclass(eq=False, repr=False) -class SourceCodeInfoLocation(betterproto.Message): - """ """ - - path: List[int] = betterproto.int32_field(1, repeated=True) - """ - Identifies which part of the FileDescriptorProto was defined at this - location. - - Each element is a field number or an index. They form a path from - the root FileDescriptorProto to the place where the definition. For - example, this path: - [ 4, 3, 2, 7, 1 ] - refers to: - file.message_type(3) // 4, 3 - .field(7) // 2, 7 - .name() // 1 - This is because FileDescriptorProto.message_type has field number 4: - repeated DescriptorProto message_type = 4; - and DescriptorProto.field has field number 2: - repeated FieldDescriptorProto field = 2; - and FieldDescriptorProto.name has field number 1: - optional string name = 1; - - Thus, the above path gives the location of a field name. If we removed - the last element: - [ 4, 3, 2, 7 ] - this path refers to the whole field declaration (from the beginning - of the label to the terminating semicolon). - """ - - span: List[int] = betterproto.int32_field(2, repeated=True) - """ - Always has exactly three or four elements: start line, start column, - end line (optional, otherwise assumed same as start line), end column. - These are packed into a single field for efficiency. Note that line - and column numbers are zero-based -- typically you will want to add - 1 to each before displaying to a user. - """ - - leading_comments: str = betterproto.string_field(3) - """ - If this SourceCodeInfo represents a complete declaration, these are any - comments appearing before and after the declaration which appear to be - attached to the declaration. - - A series of line comments appearing on consecutive lines, with no other - tokens appearing on those lines, will be treated as a single comment. - - leading_detached_comments will keep paragraphs of comments that appear - before (but not connected to) the current element. Each paragraph, - separated by empty lines, will be one comment element in the repeated - field. - - Only the comment content is provided; comment markers (e.g. //) are - stripped out. For block comments, leading whitespace and an asterisk - will be stripped from the beginning of each line other than the first. - Newlines are included in the output. - - Examples: - - optional int32 foo = 1; // Comment attached to foo. - // Comment attached to bar. - optional int32 bar = 2; - - optional string baz = 3; - // Comment attached to baz. - // Another line attached to baz. - - // Comment attached to qux. - // - // Another line attached to qux. - optional double qux = 4; - - // Detached comment for corge. This is not leading or trailing comments - // to qux or corge because there are blank lines separating it from - // both. - - // Detached comment for corge paragraph 2. - - optional string corge = 5; - /* Block comment attached - * to corge. Leading asterisks - * will be removed. */ - /* Block comment attached to - * grault. */ - optional int32 grault = 6; - - // ignored detached comments. - """ - - trailing_comments: str = betterproto.string_field(4) - """ - - """ - - leading_detached_comments: List[str] = betterproto.string_field(6, repeated=True) - """ - - """ - - -@dataclass(eq=False, repr=False) -class GeneratedCodeInfo(betterproto.Message): - """ - Describes the relationship between generated code and its original source - file. A GeneratedCodeInfo message is associated with only one generated - source file, but may contain references to different source .proto files. - """ - - annotation: List["GeneratedCodeInfoAnnotation"] = betterproto.message_field( - 1, repeated=True - ) - """ - An Annotation connects some span of text in generated code to an element - of its generating .proto file. - """ - - -@dataclass(eq=False, repr=False) -class GeneratedCodeInfoAnnotation(betterproto.Message): - """ """ - - path: List[int] = betterproto.int32_field(1, repeated=True) - """ - Identifies the element in the original source .proto file. This field - is formatted the same as SourceCodeInfo.Location.path. - """ - - source_file: str = betterproto.string_field(2) - """Identifies the filesystem path to the original source .proto.""" - - begin: int = betterproto.int32_field(3) - """ - Identifies the starting offset in bytes in the generated code - that relates to the identified object. - """ - - end: int = betterproto.int32_field(4) - """ - Identifies the ending offset in bytes in the generated code that - relates to the identified offset. The end offset should be one past - the last relevant byte (so the length of the text = end - begin). - """ - - -@dataclass(eq=False, repr=False) -class Duration(betterproto.Message): - """ - A Duration represents a signed, fixed-length span of time represented - as a count of seconds and fractions of seconds at nanosecond - resolution. It is independent of any calendar and concepts like "day" - or "month". It is related to Timestamp in that the difference between - two Timestamp values is a Duration and it can be added or subtracted - from a Timestamp. Range is approximately +-10,000 years. - - # Examples - - Example 1: Compute Duration from two Timestamps in pseudo code. - - Timestamp start = ...; - Timestamp end = ...; - Duration duration = ...; - - duration.seconds = end.seconds - start.seconds; - duration.nanos = end.nanos - start.nanos; - - if (duration.seconds < 0 && duration.nanos > 0) { - duration.seconds += 1; - duration.nanos -= 1000000000; - } else if (duration.seconds > 0 && duration.nanos < 0) { - duration.seconds -= 1; - duration.nanos += 1000000000; - } - - Example 2: Compute Timestamp from Timestamp + Duration in pseudo code. - - Timestamp start = ...; - Duration duration = ...; - Timestamp end = ...; - - end.seconds = start.seconds + duration.seconds; - end.nanos = start.nanos + duration.nanos; - - if (end.nanos < 0) { - end.seconds -= 1; - end.nanos += 1000000000; - } else if (end.nanos >= 1000000000) { - end.seconds += 1; - end.nanos -= 1000000000; - } - - Example 3: Compute Duration from datetime.timedelta in Python. - - td = datetime.timedelta(days=3, minutes=10) - duration = Duration() - duration.FromTimedelta(td) - - # JSON Mapping - - In JSON format, the Duration type is encoded as a string rather than an - object, where the string ends in the suffix "s" (indicating seconds) and - is preceded by the number of seconds, with nanoseconds expressed as - fractional seconds. For example, 3 seconds with 0 nanoseconds should be - encoded in JSON format as "3s", while 3 seconds and 1 nanosecond should - be expressed in JSON format as "3.000000001s", and 3 seconds and 1 - microsecond should be expressed in JSON format as "3.000001s". - """ - - seconds: int = betterproto.int64_field(1) - """ - Signed seconds of the span of time. Must be from -315,576,000,000 - to +315,576,000,000 inclusive. Note: these bounds are computed from: - 60 sec/min * 60 min/hr * 24 hr/day * 365.25 days/year * 10000 years - """ - - nanos: int = betterproto.int32_field(2) - """ - Signed fractions of a second at nanosecond resolution of the span - of time. Durations less than one second are represented with a 0 - `seconds` field and a positive or negative `nanos` field. For durations - of one second or more, a non-zero value for the `nanos` field must be - of the same sign as the `seconds` field. Must be from -999,999,999 - to +999,999,999 inclusive. - """ - - -@dataclass(eq=False, repr=False) -class Empty(betterproto.Message): - """ - A generic empty message that you can re-use to avoid defining duplicated - empty messages in your APIs. A typical example is to use it as the request - or the response type of an API method. For instance: - - service Foo { - rpc Bar(google.protobuf.Empty) returns (google.protobuf.Empty); - } - - The JSON representation for `Empty` is empty JSON object `{}`. - """ - - pass - - -@dataclass(eq=False, repr=False) -class FieldMask(betterproto.Message): - """ - `FieldMask` represents a set of symbolic field paths, for example: - - paths: "f.a" - paths: "f.b.d" - - Here `f` represents a field in some root message, `a` and `b` - fields in the message found in `f`, and `d` a field found in the - message in `f.b`. - - Field masks are used to specify a subset of fields that should be - returned by a get operation or modified by an update operation. - Field masks also have a custom JSON encoding (see below). - - # Field Masks in Projections - - When used in the context of a projection, a response message or - sub-message is filtered by the API to only contain those fields as - specified in the mask. For example, if the mask in the previous - example is applied to a response message as follows: - - f { - a : 22 - b { - d : 1 - x : 2 - } - y : 13 - } - z: 8 - - The result will not contain specific values for fields x,y and z - (their value will be set to the default, and omitted in proto text - output): - - f { - a : 22 - b { - d : 1 - } - } - - A repeated field is not allowed except at the last position of a - paths string. - - If a FieldMask object is not present in a get operation, the - operation applies to all fields (as if a FieldMask of all fields - had been specified). - - Note that a field mask does not necessarily apply to the - top-level response message. In case of a REST get operation, the - field mask applies directly to the response, but in case of a REST - list operation, the mask instead applies to each individual message - in the returned resource list. In case of a REST custom method, - other definitions may be used. Where the mask applies will be - clearly documented together with its declaration in the API. In - any case, the effect on the returned resource/resources is required - behavior for APIs. - - # Field Masks in Update Operations - - A field mask in update operations specifies which fields of the - targeted resource are going to be updated. The API is required - to only change the values of the fields as specified in the mask - and leave the others untouched. If a resource is passed in to - describe the updated values, the API ignores the values of all - fields not covered by the mask. - - If a repeated field is specified for an update operation, new values will - be appended to the existing repeated field in the target resource. Note that - a repeated field is only allowed in the last position of a `paths` string. - - If a sub-message is specified in the last position of the field mask for an - update operation, then new value will be merged into the existing sub-message - in the target resource. - - For example, given the target message: - - f { - b { - d: 1 - x: 2 - } - c: [1] - } - - And an update message: - - f { - b { - d: 10 - } - c: [2] - } - - then if the field mask is: - - paths: ["f.b", "f.c"] - - then the result will be: - - f { - b { - d: 10 - x: 2 - } - c: [1, 2] - } - - An implementation may provide options to override this default behavior for - repeated and message fields. - - In order to reset a field's value to the default, the field must - be in the mask and set to the default value in the provided resource. - Hence, in order to reset all fields of a resource, provide a default - instance of the resource and set all fields in the mask, or do - not provide a mask as described below. - - If a field mask is not present on update, the operation applies to - all fields (as if a field mask of all fields has been specified). - Note that in the presence of schema evolution, this may mean that - fields the client does not know and has therefore not filled into - the request will be reset to their default. If this is unwanted - behavior, a specific service may require a client to always specify - a field mask, producing an error if not. - - As with get operations, the location of the resource which - describes the updated values in the request message depends on the - operation kind. In any case, the effect of the field mask is - required to be honored by the API. - - ## Considerations for HTTP REST - - The HTTP kind of an update operation which uses a field mask must - be set to PATCH instead of PUT in order to satisfy HTTP semantics - (PUT must only be used for full updates). - - # JSON Encoding of Field Masks - - In JSON, a field mask is encoded as a single string where paths are - separated by a comma. Fields name in each path are converted - to/from lower-camel naming conventions. - - As an example, consider the following message declarations: - - message Profile { - User user = 1; - Photo photo = 2; - } - message User { - string display_name = 1; - string address = 2; - } - - In proto a field mask for `Profile` may look as such: - - mask { - paths: "user.display_name" - paths: "photo" - } - - In JSON, the same mask is represented as below: - - { - mask: "user.displayName,photo" - } - - # Field Masks and Oneof Fields - - Field masks treat fields in oneofs just as regular fields. Consider the - following message: - - message SampleMessage { - oneof test_oneof { - string name = 4; - SubMessage sub_message = 9; - } - } - - The field mask can be: - - mask { - paths: "name" - } - - Or: - - mask { - paths: "sub_message" - } - - Note that oneof type names ("test_oneof" in this case) cannot be used in - paths. - - ## Field Mask Verification - - The implementation of any API method which has a FieldMask type field in the - request should verify the included field paths, and return an - `INVALID_ARGUMENT` error if any path is unmappable. - """ - - paths: List[str] = betterproto.string_field(1, repeated=True) - """The set of field mask paths.""" - - -@dataclass(eq=False, repr=False) -class Struct(betterproto.Message): - """ - `Struct` represents a structured data value, consisting of fields - which map to dynamically typed values. In some languages, `Struct` - might be supported by a native representation. For example, in - scripting languages like JS a struct is represented as an - object. The details of that representation are described together - with the proto support for the language. - - The JSON representation for `Struct` is JSON object. - """ - - fields: Dict[str, "Value"] = betterproto.map_field( - 1, betterproto.TYPE_STRING, betterproto.TYPE_MESSAGE - ) - """Unordered map of dynamically typed values.""" - - -@dataclass(eq=False, repr=False) -class Value(betterproto.Message): - """ - `Value` represents a dynamically typed value which can be either - null, a number, a string, a boolean, a recursive struct value, or a - list of values. A producer of value is expected to set one of that - variants, absence of any variant indicates an error. - - The JSON representation for `Value` is JSON value. - """ - - null_value: "NullValue" = betterproto.enum_field(1, group="kind") - """Represents a null value.""" - - number_value: float = betterproto.double_field(2, group="kind") - """Represents a double value.""" - - string_value: str = betterproto.string_field(3, group="kind") - """Represents a string value.""" - - bool_value: bool = betterproto.bool_field(4, group="kind") - """Represents a boolean value.""" - - struct_value: "Struct" = betterproto.message_field(5, group="kind") - """Represents a structured value.""" - - list_value: "ListValue" = betterproto.message_field(6, group="kind") - """Represents a repeated `Value`.""" - - -@dataclass(eq=False, repr=False) -class ListValue(betterproto.Message): - """ - `ListValue` is a wrapper around a repeated field of values. - - The JSON representation for `ListValue` is JSON array. - """ - - values: List["Value"] = betterproto.message_field(1, repeated=True) - """Repeated field of dynamically typed values.""" - - -@dataclass(eq=False, repr=False) -class Timestamp(betterproto.Message): - """ - A Timestamp represents a point in time independent of any time zone or local - calendar, encoded as a count of seconds and fractions of seconds at - nanosecond resolution. The count is relative to an epoch at UTC midnight on - January 1, 1970, in the proleptic Gregorian calendar which extends the - Gregorian calendar backwards to year one. - - All minutes are 60 seconds long. Leap seconds are "smeared" so that no leap - second table is needed for interpretation, using a [24-hour linear - smear](https://developers.google.com/time/smear). - - The range is from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z. By - restricting to that range, we ensure that we can convert to and from [RFC - 3339](https://www.ietf.org/rfc/rfc3339.txt) date strings. - - # Examples - - Example 1: Compute Timestamp from POSIX `time()`. - - Timestamp timestamp; - timestamp.set_seconds(time(NULL)); - timestamp.set_nanos(0); - - Example 2: Compute Timestamp from POSIX `gettimeofday()`. - - struct timeval tv; - gettimeofday(&tv, NULL); - - Timestamp timestamp; - timestamp.set_seconds(tv.tv_sec); - timestamp.set_nanos(tv.tv_usec * 1000); - - Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`. - - FILETIME ft; - GetSystemTimeAsFileTime(&ft); - UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime; - - // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z - // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z. - Timestamp timestamp; - timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL)); - timestamp.set_nanos((INT32) ((ticks % 10000000) * 100)); - - Example 4: Compute Timestamp from Java `System.currentTimeMillis()`. - - long millis = System.currentTimeMillis(); - - Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000) - .setNanos((int) ((millis % 1000) * 1000000)).build(); - - Example 5: Compute Timestamp from current time in Python. - - timestamp = Timestamp() - timestamp.GetCurrentTime() - - # JSON Mapping - - In JSON format, the Timestamp type is encoded as a string in the - [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format. That is, the - format is "{year}-{month}-{day}T{hour}:{min}:{sec}[.{frac_sec}]Z" - where {year} is always expressed using four digits while {month}, {day}, - {hour}, {min}, and {sec} are zero-padded to two digits each. The fractional - seconds, which can go up to 9 digits (i.e. up to 1 nanosecond resolution), - are optional. The "Z" suffix indicates the timezone ("UTC"); the timezone - is required. A proto3 JSON serializer should always use UTC (as indicated by - "Z") when printing the Timestamp type and a proto3 JSON parser should be - able to accept both UTC and other timezones (as indicated by an offset). - - For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past - 01:30 UTC on January 15, 2017. - - In JavaScript, one can convert a Date object to this format using the - standard - [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString) - method. In Python, a standard `datetime.datetime` object can be converted - to this format using - [`strftime`](https://docs.python.org/2/library/time.html#time.strftime) with - the time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one can use - the Joda Time's [`ISODateTimeFormat.dateTime()`]( - http://www.joda.org/joda-time/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime%2D%2D - ) to obtain a formatter capable of generating timestamps in this format. - """ - - seconds: int = betterproto.int64_field(1) - """ - Represents seconds of UTC time since Unix epoch - 1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to - 9999-12-31T23:59:59Z inclusive. - """ - - nanos: int = betterproto.int32_field(2) - """ - Non-negative fractions of a second at nanosecond resolution. Negative - second values with fractions must still have non-negative nanos values - that count forward in time. Must be from 0 to 999,999,999 - inclusive. - """ - - -@dataclass(eq=False, repr=False) -class DoubleValue(betterproto.Message): - """ - Wrapper message for `double`. - - The JSON representation for `DoubleValue` is JSON number. - """ - - value: float = betterproto.double_field(1) - """The double value.""" - - -@dataclass(eq=False, repr=False) -class FloatValue(betterproto.Message): - """ - Wrapper message for `float`. - - The JSON representation for `FloatValue` is JSON number. - """ - - value: float = betterproto.float_field(1) - """The float value.""" - - -@dataclass(eq=False, repr=False) -class Int64Value(betterproto.Message): - """ - Wrapper message for `int64`. - - The JSON representation for `Int64Value` is JSON string. - """ - - value: int = betterproto.int64_field(1) - """The int64 value.""" - - -@dataclass(eq=False, repr=False) -class UInt64Value(betterproto.Message): - """ - Wrapper message for `uint64`. - - The JSON representation for `UInt64Value` is JSON string. - """ - - value: int = betterproto.uint64_field(1) - """The uint64 value.""" - - -@dataclass(eq=False, repr=False) -class Int32Value(betterproto.Message): - """ - Wrapper message for `int32`. - - The JSON representation for `Int32Value` is JSON number. - """ - - value: int = betterproto.int32_field(1) - """The int32 value.""" - - -@dataclass(eq=False, repr=False) -class UInt32Value(betterproto.Message): - """ - Wrapper message for `uint32`. - - The JSON representation for `UInt32Value` is JSON number. - """ - - value: int = betterproto.uint32_field(1) - """The uint32 value.""" - - -@dataclass(eq=False, repr=False) -class BoolValue(betterproto.Message): - """ - Wrapper message for `bool`. - - The JSON representation for `BoolValue` is JSON `true` and `false`. - """ - - value: bool = betterproto.bool_field(1) - """The bool value.""" - - -@dataclass(eq=False, repr=False) -class StringValue(betterproto.Message): - """ - Wrapper message for `string`. - - The JSON representation for `StringValue` is JSON string. - """ - - value: str = betterproto.string_field(1) - """The string value.""" - - -@dataclass(eq=False, repr=False) -class BytesValue(betterproto.Message): - """ - Wrapper message for `bytes`. - - The JSON representation for `BytesValue` is JSON string. - """ - - value: bytes = betterproto.bytes_field(1) - """The bytes value.""" +from betterproto.lib.std.google.protobuf import * diff --git a/src/betterproto/lib/std/google/protobuf/__init__.py b/src/betterproto/lib/std/google/protobuf/__init__.py index 1c40ac906..bb34c611b 100644 --- a/src/betterproto/lib/std/google/protobuf/__init__.py +++ b/src/betterproto/lib/std/google/protobuf/__init__.py @@ -1,13 +1,80 @@ # Generated by the protocol buffer compiler. DO NOT EDIT! # sources: google/protobuf/any.proto, google/protobuf/api.proto, google/protobuf/descriptor.proto, google/protobuf/duration.proto, google/protobuf/empty.proto, google/protobuf/field_mask.proto, google/protobuf/source_context.proto, google/protobuf/struct.proto, google/protobuf/timestamp.proto, google/protobuf/type.proto, google/protobuf/wrappers.proto # plugin: python-betterproto +# This file has been @generated + +__all__ = ( + "Syntax", + "FieldKind", + "FieldCardinality", + "FieldDescriptorProtoType", + "FieldDescriptorProtoLabel", + "FileOptionsOptimizeMode", + "FieldOptionsCType", + "FieldOptionsJsType", + "MethodOptionsIdempotencyLevel", + "NullValue", + "Any", + "SourceContext", + "Type", + "Field", + "Enum", + "EnumValue", + "Option", + "Api", + "Method", + "Mixin", + "FileDescriptorSet", + "FileDescriptorProto", + "DescriptorProto", + "DescriptorProtoExtensionRange", + "DescriptorProtoReservedRange", + "ExtensionRangeOptions", + "FieldDescriptorProto", + "OneofDescriptorProto", + "EnumDescriptorProto", + "EnumDescriptorProtoEnumReservedRange", + "EnumValueDescriptorProto", + "ServiceDescriptorProto", + "MethodDescriptorProto", + "FileOptions", + "MessageOptions", + "FieldOptions", + "OneofOptions", + "EnumOptions", + "EnumValueOptions", + "ServiceOptions", + "MethodOptions", + "UninterpretedOption", + "UninterpretedOptionNamePart", + "SourceCodeInfo", + "SourceCodeInfoLocation", + "GeneratedCodeInfo", + "GeneratedCodeInfoAnnotation", + "Duration", + "Empty", + "FieldMask", + "Struct", + "Value", + "ListValue", + "Timestamp", + "DoubleValue", + "FloatValue", + "Int64Value", + "UInt64Value", + "Int32Value", + "UInt32Value", + "BoolValue", + "StringValue", + "BytesValue", +) import warnings from dataclasses import dataclass from typing import ( Dict, List, - Mapping, + Mapping ) from typing_extensions import Self @@ -25,9 +92,6 @@ class Syntax(betterproto.Enum): PROTO3 = 1 """Syntax `proto3`.""" - EDITIONS = 2 - """Syntax `editions`.""" - class FieldKind(betterproto.Enum): """Basic field types.""" @@ -106,112 +170,112 @@ class FieldCardinality(betterproto.Enum): """For repeated fields.""" -class Edition(betterproto.Enum): - """The full set of known editions.""" - - UNKNOWN = 0 - """A placeholder for an unknown edition value.""" +class FieldDescriptorProtoType(betterproto.Enum): + """ """ - PROTO2 = 998 + TYPE_DOUBLE = 1 """ - Legacy syntax "editions". These pre-date editions, but behave much like - distinct editions. These can't be used to specify the edition of proto - files, but feature definitions must supply proto2/proto3 defaults for - backwards compatibility. + 0 is reserved for errors. + Order is weird for historical reasons. """ - PROTO3 = 999 - _2023 = 1000 + TYPE_FLOAT = 2 """ - Editions that have been released. The specific values are arbitrary and - should not be depended on, but they will always be time-ordered for easy - comparison. + """ - _2024 = 1001 - _1_TEST_ONLY = 1 + TYPE_INT64 = 3 """ - Placeholder editions for testing feature resolution. These should not be - used or relyed on outside of tests. + Not ZigZag encoded. Negative numbers take 10 bytes. Use TYPE_SINT64 if + negative values are likely. """ - _2_TEST_ONLY = 2 - _99997_TEST_ONLY = 99997 - _99998_TEST_ONLY = 99998 - _99999_TEST_ONLY = 99999 - MAX = 2147483647 + TYPE_UINT64 = 4 """ - Placeholder for specifying unbounded edition support. This should only - ever be used by plugins that can expect to never require any changes to - support a new edition. + """ - -class ExtensionRangeOptionsVerificationState(betterproto.Enum): - """The verification state of the extension range.""" - - DECLARATION = 0 - """All the extensions of the range must be declared.""" - - UNVERIFIED = 1 - - -class FieldDescriptorProtoType(betterproto.Enum): - TYPE_DOUBLE = 1 + TYPE_INT32 = 5 """ - 0 is reserved for errors. - Order is weird for historical reasons. + Not ZigZag encoded. Negative numbers take 10 bytes. Use TYPE_SINT32 if + negative values are likely. """ - TYPE_FLOAT = 2 - TYPE_INT64 = 3 + TYPE_FIXED64 = 6 """ - Not ZigZag encoded. Negative numbers take 10 bytes. Use TYPE_SINT64 if - negative values are likely. + """ - TYPE_UINT64 = 4 - TYPE_INT32 = 5 + TYPE_FIXED32 = 7 """ - Not ZigZag encoded. Negative numbers take 10 bytes. Use TYPE_SINT32 if - negative values are likely. + """ - TYPE_FIXED64 = 6 - TYPE_FIXED32 = 7 TYPE_BOOL = 8 + """ + + """ + TYPE_STRING = 9 + """ + + """ + TYPE_GROUP = 10 """ Tag-delimited aggregate. - Group type is deprecated and not supported after google.protobuf. However, Proto3 - implementations should still be able to parse the group wire format and - treat group fields as unknown fields. In Editions, the group wire format - can be enabled via the `message_encoding` feature. + Group type is deprecated and not supported in proto3. However, Proto3 + implementations should still be able to parse the group wire format and + treat group fields as unknown fields. """ TYPE_MESSAGE = 11 + """Length-delimited aggregate.""" + TYPE_BYTES = 12 """New in version 2.""" TYPE_UINT32 = 13 + """ + + """ + TYPE_ENUM = 14 + """ + + """ + TYPE_SFIXED32 = 15 + """ + + """ + TYPE_SFIXED64 = 16 + """ + + """ + TYPE_SINT32 = 17 + """Uses ZigZag encoding.""" + TYPE_SINT64 = 18 + """Uses ZigZag encoding.""" class FieldDescriptorProtoLabel(betterproto.Enum): + """ """ + LABEL_OPTIONAL = 1 """0 is reserved for errors""" - LABEL_REPEATED = 3 LABEL_REQUIRED = 2 """ - The required label is only allowed in google.protobuf. In proto3 and Editions - it's explicitly prohibited. In Editions, the `field_presence` feature - can be used to get this behavior. + + """ + + LABEL_REPEATED = 3 + """ + """ @@ -219,30 +283,39 @@ class FileOptionsOptimizeMode(betterproto.Enum): """Generated classes can be optimized for speed or code size.""" SPEED = 1 + """Generate complete code for parsing, serialization,""" + CODE_SIZE = 2 - """etc.""" + """ + etc. + + Use ReflectionOps to implement these methods. + """ LITE_RUNTIME = 3 + """Generate code using MessageLite and the lite runtime.""" class FieldOptionsCType(betterproto.Enum): + """ """ + STRING = 0 """Default mode.""" CORD = 1 """ - The option [ctype=CORD] may be applied to a non-repeated field of type - "bytes". It indicates that in C++, the data should be stored in a Cord - instead of a string. For very large strings, this may reduce memory - fragmentation. It may also allow better performance when parsing from a - Cord, or when parsing with aliasing enabled, as the parsed Cord may then - alias the original buffer. + """ STRING_PIECE = 2 + """ + + """ class FieldOptionsJsType(betterproto.Enum): + """ """ + JS_NORMAL = 0 """Use the default type.""" @@ -253,107 +326,29 @@ class FieldOptionsJsType(betterproto.Enum): """Use JavaScript numbers.""" -class FieldOptionsOptionRetention(betterproto.Enum): - """ - If set to RETENTION_SOURCE, the option will be omitted from the binary. - Note: as of January 2023, support for this is in progress and does not yet - have an effect (b/264593489). - """ - - RETENTION_UNKNOWN = 0 - RETENTION_RUNTIME = 1 - RETENTION_SOURCE = 2 - - -class FieldOptionsOptionTargetType(betterproto.Enum): - """ - This indicates the types of entities that the field may apply to when used - as an option. If it is unset, then the field may be freely used as an - option on any kind of entity. Note: as of January 2023, support for this is - in progress and does not yet have an effect (b/264593489). - """ - - TARGET_TYPE_UNKNOWN = 0 - TARGET_TYPE_FILE = 1 - TARGET_TYPE_EXTENSION_RANGE = 2 - TARGET_TYPE_MESSAGE = 3 - TARGET_TYPE_FIELD = 4 - TARGET_TYPE_ONEOF = 5 - TARGET_TYPE_ENUM = 6 - TARGET_TYPE_ENUM_ENTRY = 7 - TARGET_TYPE_SERVICE = 8 - TARGET_TYPE_METHOD = 9 - - class MethodOptionsIdempotencyLevel(betterproto.Enum): """ Is this method side-effect-free (or safe in HTTP parlance), or idempotent, - or neither? HTTP based RPC implementation may choose GET verb for safe - methods, and PUT verb for idempotent methods instead of the default POST. + or neither? HTTP based RPC implementation may choose GET verb for safe + methods, and PUT verb for idempotent methods instead of the default POST. """ IDEMPOTENCY_UNKNOWN = 0 - NO_SIDE_EFFECTS = 1 - IDEMPOTENT = 2 - - -class FeatureSetFieldPresence(betterproto.Enum): - FIELD_PRESENCE_UNKNOWN = 0 - EXPLICIT = 1 - IMPLICIT = 2 - LEGACY_REQUIRED = 3 - - -class FeatureSetEnumType(betterproto.Enum): - ENUM_TYPE_UNKNOWN = 0 - OPEN = 1 - CLOSED = 2 - - -class FeatureSetRepeatedFieldEncoding(betterproto.Enum): - REPEATED_FIELD_ENCODING_UNKNOWN = 0 - PACKED = 1 - EXPANDED = 2 - - -class FeatureSetUtf8Validation(betterproto.Enum): - UTF8_VALIDATION_UNKNOWN = 0 - VERIFY = 2 - NONE = 3 - - -class FeatureSetMessageEncoding(betterproto.Enum): - MESSAGE_ENCODING_UNKNOWN = 0 - LENGTH_PREFIXED = 1 - DELIMITED = 2 - - -class FeatureSetJsonFormat(betterproto.Enum): - JSON_FORMAT_UNKNOWN = 0 - ALLOW = 1 - LEGACY_BEST_EFFORT = 2 - - -class GeneratedCodeInfoAnnotationSemantic(betterproto.Enum): """ - Represents the identified object's effect on the element in the original - .proto file. + """ - NONE = 0 - """There is no effect or the effect is indescribable.""" - - SET = 1 - """The element is set or otherwise mutated.""" + NO_SIDE_EFFECTS = 1 + """implies idempotent""" - ALIAS = 2 - """An alias to the element is returned.""" + IDEMPOTENT = 2 + """idempotent, but may have side effects""" class NullValue(betterproto.Enum): """ `NullValue` is a singleton enumeration to represent the null value for the - `Value` type union. + `Value` type union. The JSON representation for `NullValue` is JSON `null`. """ @@ -366,122 +361,114 @@ class NullValue(betterproto.Enum): class Any(betterproto.Message): """ `Any` contains an arbitrary serialized protocol buffer message along with a - URL that describes the type of the serialized message. + URL that describes the type of the serialized message. - Protobuf library provides support to pack/unpack Any values in the form - of utility functions or additional generated methods of the Any type. + Protobuf library provides support to pack/unpack Any values in the form + of utility functions or additional generated methods of the Any type. - Example 1: Pack and unpack a message in C++. + Example 1: Pack and unpack a message in C++. - Foo foo = ...; - Any any; - any.PackFrom(foo); - ... - if (any.UnpackTo(&foo)) { - ... - } + Foo foo = ...; + Any any; + any.PackFrom(foo); + ... + if (any.UnpackTo(&foo)) { + ... + } - Example 2: Pack and unpack a message in Java. + Example 2: Pack and unpack a message in Java. - Foo foo = ...; - Any any = Any.pack(foo); - ... - if (any.is(Foo.class)) { - foo = any.unpack(Foo.class); - } - // or ... - if (any.isSameTypeAs(Foo.getDefaultInstance())) { - foo = any.unpack(Foo.getDefaultInstance()); - } + Foo foo = ...; + Any any = Any.pack(foo); + ... + if (any.is(Foo.class)) { + foo = any.unpack(Foo.class); + } - Example 3: Pack and unpack a message in Python. + Example 3: Pack and unpack a message in Python. - foo = Foo(...) - any = Any() - any.Pack(foo) - ... - if any.Is(Foo.DESCRIPTOR): - any.Unpack(foo) - ... - - Example 4: Pack and unpack a message in Go - - foo := &pb.Foo{...} - any, err := anypb.New(foo) - if err != nil { - ... - } + foo = Foo(...) + any = Any() + any.Pack(foo) + ... + if any.Is(Foo.DESCRIPTOR): + any.Unpack(foo) ... - foo := &pb.Foo{} - if err := any.UnmarshalTo(foo); err != nil { - ... - } - The pack methods provided by protobuf library will by default use - 'type.googleapis.com/full.type.name' as the type URL and the unpack - methods only use the fully qualified type name after the last '/' - in the type URL, for example "foo.bar.com/x/y.z" will yield type - name "y.z". - - JSON - ==== - The JSON representation of an `Any` value uses the regular - representation of the deserialized, embedded message, with an - additional field `@type` which contains the type URL. Example: - - package google.profile; - message Person { - string first_name = 1; - string last_name = 2; - } + Example 4: Pack and unpack a message in Go - { - "@type": "type.googleapis.com/google.profile.Person", - "firstName": , - "lastName": + foo := &pb.Foo{...} + any, err := ptypes.MarshalAny(foo) + ... + foo := &pb.Foo{} + if err := ptypes.UnmarshalAny(any, foo); err != nil { + ... } - If the embedded message type is well-known and has a custom JSON - representation, that representation will be embedded adding a field - `value` which holds the custom JSON in addition to the `@type` - field. Example (for message [google.protobuf.Duration][]): - - { - "@type": "type.googleapis.com/google.protobuf.Duration", - "value": "1.212s" - } + The pack methods provided by protobuf library will by default use + 'type.googleapis.com/full.type.name' as the type URL and the unpack + methods only use the fully qualified type name after the last '/' + in the type URL, for example "foo.bar.com/x/y.z" will yield type + name "y.z". + + JSON + ==== + The JSON representation of an `Any` value uses the regular + representation of the deserialized, embedded message, with an + additional field `@type` which contains the type URL. Example: + + package google.profile; + message Person { + string first_name = 1; + string last_name = 2; + } + + { + "@type": "type.googleapis.com/google.profile.Person", + "firstName": , + "lastName": + } + + If the embedded message type is well-known and has a custom JSON + representation, that representation will be embedded adding a field + `value` which holds the custom JSON in addition to the `@type` + field. Example (for message [google.protobuf.Duration][]): + + { + "@type": "type.googleapis.com/google.protobuf.Duration", + "value": "1.212s" + } """ type_url: str = betterproto.string_field(1) """ A URL/resource name that uniquely identifies the type of the serialized - protocol buffer message. This string must contain at least - one "/" character. The last segment of the URL's path must represent - the fully qualified name of the type (as in - `path/google.protobuf.Duration`). The name should be in a canonical form - (e.g., leading "." is not accepted). - - In practice, teams usually precompile into the binary all types that they - expect it to use in the context of Any. However, for URLs which use the - scheme `http`, `https`, or no scheme, one can optionally set up a type - server that maps type URLs to message definitions as follows: - - * If no scheme is provided, `https` is assumed. - * An HTTP GET on the URL must yield a [google.protobuf.Type][] - value in binary format, or produce an error. - * Applications are allowed to cache lookup results based on the - URL, or have them precompiled into a binary to avoid any - lookup. Therefore, binary compatibility needs to be preserved - on changes to types. (Use versioned type names to manage - breaking changes.) - - Note: this functionality is not currently available in the official - protobuf release, and it is not used for type URLs beginning with - type.googleapis.com. As of May 2023, there are no widely used type server - implementations and no plans to implement one. - - Schemes other than `http`, `https` (or the empty scheme) might be - used with implementation specific semantics. + protocol buffer message. This string must contain at least + one "/" character. The last segment of the URL's path must represent + the fully qualified name of the type (as in + `path/google.protobuf.Duration`). The name should be in a canonical form + (e.g., leading "." is not accepted). + + In practice, teams usually precompile into the binary all types that they + expect it to use in the context of Any. However, for URLs which use the + scheme `http`, `https`, or no scheme, one can optionally set up a type + server that maps type URLs to message definitions as follows: + + * If no scheme is provided, `https` is assumed. + * An HTTP GET on the URL must yield a [google.protobuf.Type][] + value in binary format, or produce an error. + * Applications are allowed to cache lookup results based on the + URL, or have them precompiled into a binary to avoid any + lookup. Therefore, binary compatibility needs to be preserved + on changes to types. (Use versioned type names to manage + breaking changes.) + + Note: this functionality is not currently available in the official + protobuf release, and it is not used for type URLs beginning with + type.googleapis.com. + + Schemes other than `http`, `https` (or the empty scheme) might be + used with implementation specific semantics. """ value: bytes = betterproto.bytes_field(2) @@ -494,13 +481,13 @@ class Any(betterproto.Message): class SourceContext(betterproto.Message): """ `SourceContext` represents information about the source of a - protobuf element, like the file in which it is defined. + protobuf element, like the file in which it is defined. """ file_name: str = betterproto.string_field(1) """ The path-qualified name of the .proto file that contained the associated - protobuf element. For example: `"google/protobuf/source_context.proto"`. + protobuf element. For example: `"google/protobuf/source_context.proto"`. """ @@ -511,13 +498,13 @@ class Type(betterproto.Message): name: str = betterproto.string_field(1) """The fully qualified message name.""" - fields: List["Field"] = betterproto.message_field(2) + fields: List["Field"] = betterproto.message_field(2, repeated=True) """The list of fields.""" - oneofs: List[str] = betterproto.string_field(3) + oneofs: List[str] = betterproto.string_field(3, repeated=True) """The list of types appearing in `oneof` definitions in this type.""" - options: List["Option"] = betterproto.message_field(4) + options: List["Option"] = betterproto.message_field(4, repeated=True) """The protocol buffer options.""" source_context: "SourceContext" = betterproto.message_field(5) @@ -526,11 +513,6 @@ class Type(betterproto.Message): syntax: "Syntax" = betterproto.enum_field(6) """The source syntax.""" - edition: str = betterproto.string_field(7) - """ - The source edition string, only valid when syntax is SYNTAX_EDITIONS. - """ - @dataclass(eq=False, repr=False) class Field(betterproto.Message): @@ -551,19 +533,19 @@ class Field(betterproto.Message): type_url: str = betterproto.string_field(6) """ The field type URL, without the scheme, for message or enumeration - types. Example: `"type.googleapis.com/google.protobuf.Timestamp"`. + types. Example: `"type.googleapis.com/google.protobuf.Timestamp"`. """ oneof_index: int = betterproto.int32_field(7) """ The index of the field type in `Type.oneofs`, for message or enumeration - types. The first type has index 1; zero means the type is not in the list. + types. The first type has index 1; zero means the type is not in the list. """ packed: bool = betterproto.bool_field(8) """Whether to use alternative packed wire representation.""" - options: List["Option"] = betterproto.message_field(9) + options: List["Option"] = betterproto.message_field(9, repeated=True) """The protocol buffer options.""" json_name: str = betterproto.string_field(10) @@ -583,11 +565,11 @@ class Enum(betterproto.Message): """Enum type name.""" enumvalue: List["EnumValue"] = betterproto.message_field( - 2, wraps=betterproto.TYPE_ENUM + 2, wraps=betterproto.TYPE_ENUM, repeated=True ) """Enum value definitions.""" - options: List["Option"] = betterproto.message_field(3) + options: List["Option"] = betterproto.message_field(3, repeated=True) """Protocol buffer options.""" source_context: "SourceContext" = betterproto.message_field(4) @@ -596,11 +578,6 @@ class Enum(betterproto.Message): syntax: "Syntax" = betterproto.enum_field(5) """The source syntax.""" - edition: str = betterproto.string_field(6) - """ - The source edition string, only valid when syntax is SYNTAX_EDITIONS. - """ - @dataclass(eq=False, repr=False) class EnumValue(betterproto.Message): @@ -612,7 +589,7 @@ class EnumValue(betterproto.Message): number: int = betterproto.int32_field(2) """Enum value number.""" - options: List["Option"] = betterproto.message_field(3) + options: List["Option"] = betterproto.message_field(3, repeated=True) """Protocol buffer options.""" @@ -620,23 +597,23 @@ class EnumValue(betterproto.Message): class Option(betterproto.Message): """ A protocol buffer option, which can be attached to a message, field, - enumeration, etc. + enumeration, etc. """ name: str = betterproto.string_field(1) """ The option's name. For protobuf built-in options (options defined in - descriptor.proto), this is the short name. For example, `"map_entry"`. - For custom options, it should be the fully-qualified name. For example, - `"google.api.http"`. + descriptor.proto), this is the short name. For example, `"map_entry"`. + For custom options, it should be the fully-qualified name. For example, + `"google.api.http"`. """ value: "Any" = betterproto.message_field(2) """ The option's value packed in an Any message. If the value is a primitive, - the corresponding wrapper type defined in google/protobuf/wrappers.proto - should be used. If the value is an enum, it should be stored as an int32 - value using the google.protobuf.Int32Value type. + the corresponding wrapper type defined in google/protobuf/wrappers.proto + should be used. If the value is an enum, it should be stored as an int32 + value using the google.protobuf.Int32Value type. """ @@ -645,57 +622,57 @@ class Api(betterproto.Message): """ Api is a light-weight descriptor for an API Interface. - Interfaces are also described as "protocol buffer services" in some contexts, - such as by the "service" keyword in a .proto file, but they are different - from API Services, which represent a concrete implementation of an interface - as opposed to simply a description of methods and bindings. They are also - sometimes simply referred to as "APIs" in other contexts, such as the name of - this message itself. See https://cloud.google.com/apis/design/glossary for - detailed terminology. + Interfaces are also described as "protocol buffer services" in some contexts, + such as by the "service" keyword in a .proto file, but they are different + from API Services, which represent a concrete implementation of an interface + as opposed to simply a description of methods and bindings. They are also + sometimes simply referred to as "APIs" in other contexts, such as the name of + this message itself. See https://cloud.google.com/apis/design/glossary for + detailed terminology. """ name: str = betterproto.string_field(1) """ The fully qualified name of this interface, including package name - followed by the interface's simple name. + followed by the interface's simple name. """ - methods: List["Method"] = betterproto.message_field(2) + methods: List["Method"] = betterproto.message_field(2, repeated=True) """The methods of this interface, in unspecified order.""" - options: List["Option"] = betterproto.message_field(3) + options: List["Option"] = betterproto.message_field(3, repeated=True) """Any metadata attached to the interface.""" version: str = betterproto.string_field(4) """ A version string for this interface. If specified, must have the form - `major-version.minor-version`, as in `1.10`. If the minor version is - omitted, it defaults to zero. If the entire version field is empty, the - major version is derived from the package name, as outlined below. If the - field is not empty, the version in the package name will be verified to be - consistent with what is provided here. - - The versioning schema uses [semantic - versioning](http://semver.org) where the major version number - indicates a breaking change and the minor version an additive, - non-breaking change. Both version numbers are signals to users - what to expect from different versions, and should be carefully - chosen based on the product plan. - - The major version is also reflected in the package name of the - interface, which must end in `v`, as in - `google.feature.v1`. For major versions 0 and 1, the suffix can - be omitted. Zero major versions must only be used for - experimental, non-GA interfaces. + `major-version.minor-version`, as in `1.10`. If the minor version is + omitted, it defaults to zero. If the entire version field is empty, the + major version is derived from the package name, as outlined below. If the + field is not empty, the version in the package name will be verified to be + consistent with what is provided here. + + The versioning schema uses [semantic + versioning](http://semver.org) where the major version number + indicates a breaking change and the minor version an additive, + non-breaking change. Both version numbers are signals to users + what to expect from different versions, and should be carefully + chosen based on the product plan. + + The major version is also reflected in the package name of the + interface, which must end in `v`, as in + `google.feature.v1`. For major versions 0 and 1, the suffix can + be omitted. Zero major versions must only be used for + experimental, non-GA interfaces. """ source_context: "SourceContext" = betterproto.message_field(5) """ Source context for the protocol buffer service represented by this - message. + message. """ - mixins: List["Mixin"] = betterproto.message_field(6) + mixins: List["Mixin"] = betterproto.message_field(6, repeated=True) """Included interfaces. See [Mixin][].""" syntax: "Syntax" = betterproto.enum_field(7) @@ -721,7 +698,7 @@ class Method(betterproto.Message): response_streaming: bool = betterproto.bool_field(5) """If true, the response is streamed.""" - options: List["Option"] = betterproto.message_field(6) + options: List["Option"] = betterproto.message_field(6, repeated=True) """Any metadata attached to the method.""" syntax: "Syntax" = betterproto.enum_field(7) @@ -732,83 +709,83 @@ class Method(betterproto.Message): class Mixin(betterproto.Message): """ Declares an API Interface to be included in this interface. The including - interface must redeclare all the methods from the included interface, but - documentation and options are inherited as follows: - - - If after comment and whitespace stripping, the documentation - string of the redeclared method is empty, it will be inherited - from the original method. - - - Each annotation belonging to the service config (http, - visibility) which is not set in the redeclared method will be - inherited. - - - If an http annotation is inherited, the path pattern will be - modified as follows. Any version prefix will be replaced by the - version of the including interface plus the [root][] path if - specified. - - Example of a simple mixin: - - package google.acl.v1; - service AccessControl { - // Get the underlying ACL object. - rpc GetAcl(GetAclRequest) returns (Acl) { - option (google.api.http).get = "/v1/{resource=**}:getAcl"; - } - } + interface must redeclare all the methods from the included interface, but + documentation and options are inherited as follows: - package google.storage.v2; - service Storage { - rpc GetAcl(GetAclRequest) returns (Acl); + - If after comment and whitespace stripping, the documentation + string of the redeclared method is empty, it will be inherited + from the original method. - // Get a data record. - rpc GetData(GetDataRequest) returns (Data) { - option (google.api.http).get = "/v2/{resource=**}"; - } - } + - Each annotation belonging to the service config (http, + visibility) which is not set in the redeclared method will be + inherited. - Example of a mixin configuration: + - If an http annotation is inherited, the path pattern will be + modified as follows. Any version prefix will be replaced by the + version of the including interface plus the [root][] path if + specified. - apis: - - name: google.storage.v2.Storage - mixins: - - name: google.acl.v1.AccessControl + Example of a simple mixin: - The mixin construct implies that all methods in `AccessControl` are - also declared with same name and request/response types in - `Storage`. A documentation generator or annotation processor will - see the effective `Storage.GetAcl` method after inherting - documentation and annotations as follows: + package google.acl.v1; + service AccessControl { + // Get the underlying ACL object. + rpc GetAcl(GetAclRequest) returns (Acl) { + option (google.api.http).get = "/v1/{resource=**}:getAcl"; + } + } - service Storage { - // Get the underlying ACL object. - rpc GetAcl(GetAclRequest) returns (Acl) { - option (google.api.http).get = "/v2/{resource=**}:getAcl"; - } - ... - } + package google.storage.v2; + service Storage { + rpc GetAcl(GetAclRequest) returns (Acl); - Note how the version in the path pattern changed from `v1` to `v2`. + // Get a data record. + rpc GetData(GetDataRequest) returns (Data) { + option (google.api.http).get = "/v2/{resource=**}"; + } + } - If the `root` field in the mixin is specified, it should be a - relative path under which inherited HTTP paths are placed. Example: + Example of a mixin configuration: - apis: - - name: google.storage.v2.Storage - mixins: - - name: google.acl.v1.AccessControl - root: acls + apis: + - name: google.storage.v2.Storage + mixins: + - name: google.acl.v1.AccessControl - This implies the following inherited HTTP annotation: + The mixin construct implies that all methods in `AccessControl` are + also declared with same name and request/response types in + `Storage`. A documentation generator or annotation processor will + see the effective `Storage.GetAcl` method after inherting + documentation and annotations as follows: - service Storage { - // Get the underlying ACL object. - rpc GetAcl(GetAclRequest) returns (Acl) { - option (google.api.http).get = "/v2/acls/{resource=**}:getAcl"; - } - ... - } + service Storage { + // Get the underlying ACL object. + rpc GetAcl(GetAclRequest) returns (Acl) { + option (google.api.http).get = "/v2/{resource=**}:getAcl"; + } + ... + } + + Note how the version in the path pattern changed from `v1` to `v2`. + + If the `root` field in the mixin is specified, it should be a + relative path under which inherited HTTP paths are placed. Example: + + apis: + - name: google.storage.v2.Storage + mixins: + - name: google.acl.v1.AccessControl + root: acls + + This implies the following inherited HTTP annotation: + + service Storage { + // Get the underlying ACL object. + rpc GetAcl(GetAclRequest) returns (Acl) { + option (google.api.http).get = "/v2/acls/{resource=**}:getAcl"; + } + ... + } """ name: str = betterproto.string_field(1) @@ -817,7 +794,7 @@ class Mixin(betterproto.Message): root: str = betterproto.string_field(2) """ If non-empty specifies a path under which inherited HTTP paths - are rooted. + are rooted. """ @@ -825,10 +802,13 @@ class Mixin(betterproto.Message): class FileDescriptorSet(betterproto.Message): """ The protocol compiler can output a FileDescriptorSet containing the .proto - files it parses. + files it parses. """ - file: List["FileDescriptorProto"] = betterproto.message_field(1) + file: List["FileDescriptorProto"] = betterproto.message_field(1, repeated=True) + """ + + """ @dataclass(eq=False, repr=False) @@ -836,216 +816,261 @@ class FileDescriptorProto(betterproto.Message): """Describes a complete .proto file.""" name: str = betterproto.string_field(1) + """file name, relative to root of source tree""" + package: str = betterproto.string_field(2) - dependency: List[str] = betterproto.string_field(3) + """e.g. "foo", "foo.bar", etc.""" + + dependency: List[str] = betterproto.string_field(3, repeated=True) """Names of files imported by this file.""" - public_dependency: List[int] = betterproto.int32_field(10) + public_dependency: List[int] = betterproto.int32_field(10, repeated=True) """Indexes of the public imported files in the dependency list above.""" - weak_dependency: List[int] = betterproto.int32_field(11) + weak_dependency: List[int] = betterproto.int32_field(11, repeated=True) """ Indexes of the weak imported files in the dependency list. - For Google-internal migration only. Do not use. + For Google-internal migration only. Do not use. """ - message_type: List["DescriptorProto"] = betterproto.message_field(4) + message_type: List["DescriptorProto"] = betterproto.message_field(4, repeated=True) """All top-level definitions in this file.""" - enum_type: List["EnumDescriptorProto"] = betterproto.message_field(5) - service: List["ServiceDescriptorProto"] = betterproto.message_field(6) - extension: List["FieldDescriptorProto"] = betterproto.message_field(7) + enum_type: List["EnumDescriptorProto"] = betterproto.message_field(5, repeated=True) + """ + + """ + + service: List["ServiceDescriptorProto"] = betterproto.message_field( + 6, repeated=True + ) + """ + + """ + + extension: List["FieldDescriptorProto"] = betterproto.message_field( + 7, repeated=True + ) + """ + + """ + options: "FileOptions" = betterproto.message_field(8) + """ + + """ + source_code_info: "SourceCodeInfo" = betterproto.message_field(9) """ This field contains optional information about the original source code. - You may safely remove this entire field without harming runtime - functionality of the descriptors -- the information is needed only by - development tools. + You may safely remove this entire field without harming runtime + functionality of the descriptors -- the information is needed only by + development tools. """ syntax: str = betterproto.string_field(12) """ The syntax of the proto file. - The supported values are "proto2", "proto3", and "editions". - - If `edition` is present, this value must be "editions". + The supported values are "proto2" and "proto3". """ - edition: "Edition" = betterproto.enum_field(14) - """The edition of the proto file.""" - @dataclass(eq=False, repr=False) class DescriptorProto(betterproto.Message): """Describes a message type.""" name: str = betterproto.string_field(1) - field: List["FieldDescriptorProto"] = betterproto.message_field(2) - extension: List["FieldDescriptorProto"] = betterproto.message_field(6) - nested_type: List["DescriptorProto"] = betterproto.message_field(3) - enum_type: List["EnumDescriptorProto"] = betterproto.message_field(4) + """ + + """ + + field: List["FieldDescriptorProto"] = betterproto.message_field(2, repeated=True) + """ + + """ + + extension: List["FieldDescriptorProto"] = betterproto.message_field( + 6, repeated=True + ) + """ + + """ + + nested_type: List["DescriptorProto"] = betterproto.message_field(3, repeated=True) + """ + + """ + + enum_type: List["EnumDescriptorProto"] = betterproto.message_field(4, repeated=True) + """ + + """ + extension_range: List["DescriptorProtoExtensionRange"] = betterproto.message_field( - 5 + 5, repeated=True ) - oneof_decl: List["OneofDescriptorProto"] = betterproto.message_field(8) + """ + + """ + + oneof_decl: List["OneofDescriptorProto"] = betterproto.message_field( + 8, repeated=True + ) + """ + + """ + options: "MessageOptions" = betterproto.message_field(7) - reserved_range: List["DescriptorProtoReservedRange"] = betterproto.message_field(9) - reserved_name: List[str] = betterproto.string_field(10) + """ + + """ + + reserved_range: List["DescriptorProtoReservedRange"] = betterproto.message_field( + 9, repeated=True + ) + """ + + """ + + reserved_name: List[str] = betterproto.string_field(10, repeated=True) """ Reserved field names, which may not be used by fields in the same message. - A given name may only be reserved once. + A given name may only be reserved once. """ @dataclass(eq=False, repr=False) class DescriptorProtoExtensionRange(betterproto.Message): + """ """ + start: int = betterproto.int32_field(1) + """Inclusive.""" + end: int = betterproto.int32_field(2) + """Exclusive.""" + options: "ExtensionRangeOptions" = betterproto.message_field(3) + """ + + """ @dataclass(eq=False, repr=False) class DescriptorProtoReservedRange(betterproto.Message): """ Range of reserved tag numbers. Reserved tag numbers may not be used by - fields or extension ranges in the same message. Reserved ranges may - not overlap. + fields or extension ranges in the same message. Reserved ranges may + not overlap. """ start: int = betterproto.int32_field(1) + """Inclusive.""" + end: int = betterproto.int32_field(2) + """Exclusive.""" @dataclass(eq=False, repr=False) class ExtensionRangeOptions(betterproto.Message): - uninterpreted_option: List["UninterpretedOption"] = betterproto.message_field(999) - """The parser stores options it doesn't recognize here. See above.""" + """ """ - declaration: List["ExtensionRangeOptionsDeclaration"] = betterproto.message_field(2) - """ - For external users: DO NOT USE. We are in the process of open sourcing - extension declaration and executing internal cleanups before it can be - used externally. - """ - - features: "FeatureSet" = betterproto.message_field(50) - """Any features defined in the specific edition.""" - - verification: "ExtensionRangeOptionsVerificationState" = betterproto.enum_field(3) - """ - The verification state of the range. - TODO: flip the default to DECLARATION once all empty ranges - are marked as UNVERIFIED. - """ + uninterpreted_option: List["UninterpretedOption"] = betterproto.message_field( + 999, repeated=True + ) + """The parser stores options it doesn't recognize here. See above.""" @dataclass(eq=False, repr=False) -class ExtensionRangeOptionsDeclaration(betterproto.Message): - number: int = betterproto.int32_field(1) - """The extension number declared within the extension range.""" - - full_name: str = betterproto.string_field(2) - """ - The fully-qualified name of the extension field. There must be a leading - dot in front of the full name. - """ +class FieldDescriptorProto(betterproto.Message): + """Describes a field within a message.""" - type: str = betterproto.string_field(3) + name: str = betterproto.string_field(1) """ - The fully-qualified type name of the extension field. Unlike - Metadata.type, Declaration.type must have a leading dot for messages - and enums. + """ - reserved: bool = betterproto.bool_field(5) + number: int = betterproto.int32_field(3) """ - If true, indicates that the number is reserved in the extension range, - and any extension field with the number will fail to compile. Set this - when a declared extension field is deleted. + """ - repeated: bool = betterproto.bool_field(6) + label: "FieldDescriptorProtoLabel" = betterproto.enum_field(4) """ - If true, indicates that the extension must be defined as repeated. - Otherwise the extension must be defined as optional. + """ - -@dataclass(eq=False, repr=False) -class FieldDescriptorProto(betterproto.Message): - """Describes a field within a message.""" - - name: str = betterproto.string_field(1) - number: int = betterproto.int32_field(3) - label: "FieldDescriptorProtoLabel" = betterproto.enum_field(4) type: "FieldDescriptorProtoType" = betterproto.enum_field(5) """ If type_name is set, this need not be set. If both this and type_name - are set, this must be one of TYPE_ENUM, TYPE_MESSAGE or TYPE_GROUP. + are set, this must be one of TYPE_ENUM, TYPE_MESSAGE or TYPE_GROUP. """ type_name: str = betterproto.string_field(6) """ For message and enum types, this is the name of the type. If the name - starts with a '.', it is fully-qualified. Otherwise, C++-like scoping - rules are used to find the type (i.e. first the nested types within this - message are searched, then within the parent, on up to the root - namespace). + starts with a '.', it is fully-qualified. Otherwise, C++-like scoping + rules are used to find the type (i.e. first the nested types within this + message are searched, then within the parent, on up to the root + namespace). """ extendee: str = betterproto.string_field(2) """ For extensions, this is the name of the type being extended. It is - resolved in the same manner as type_name. + resolved in the same manner as type_name. """ default_value: str = betterproto.string_field(7) """ For numeric types, contains the original text representation of the value. - For booleans, "true" or "false". - For strings, contains the default text contents (not escaped in any way). - For bytes, contains the C escaped value. All bytes >= 128 are escaped. + For booleans, "true" or "false". + For strings, contains the default text contents (not escaped in any way). + For bytes, contains the C escaped value. All bytes >= 128 are escaped. + TODO(kenton): Base-64 encode? """ oneof_index: int = betterproto.int32_field(9) """ If set, gives the index of a oneof in the containing type's oneof_decl - list. This field is a member of that oneof. + list. This field is a member of that oneof. """ json_name: str = betterproto.string_field(10) """ JSON name of this field. The value is set by protocol compiler. If the - user has set a "json_name" option on this field, that option's value - will be used. Otherwise, it's deduced from the field's name by converting - it to camelCase. + user has set a "json_name" option on this field, that option's value + will be used. Otherwise, it's deduced from the field's name by converting + it to camelCase. """ options: "FieldOptions" = betterproto.message_field(8) + """ + + """ + proto3_optional: bool = betterproto.bool_field(17) """ If true, this is a proto3 "optional". When a proto3 field is optional, it - tracks presence regardless of field type. + tracks presence regardless of field type. - When proto3_optional is true, this field must belong to a oneof to signal - to old proto3 clients that presence is tracked for this field. This oneof - is known as a "synthetic" oneof, and this field must be its sole member - (each proto3 optional field gets its own synthetic oneof). Synthetic oneofs - exist in the descriptor only, and do not generate any API. Synthetic oneofs - must be ordered after all "real" oneofs. + When proto3_optional is true, this field must be belong to a oneof to + signal to old proto3 clients that presence is tracked for this field. This + oneof is known as a "synthetic" oneof, and this field must be its sole + member (each proto3 optional field gets its own synthetic oneof). Synthetic + oneofs exist in the descriptor only, and do not generate any API. Synthetic + oneofs must be ordered after all "real" oneofs. - For message fields, proto3_optional doesn't create any semantic change, - since non-repeated message fields always track presence. However it still - indicates the semantic detail of whether the user wrote "optional" or not. - This can be useful for round-tripping the .proto file. For consistency we - give message fields a synthetic oneof also, even though it is not required - to track presence. This is especially important because the parser can't - tell if a field is a message or an enum, so it must always create a - synthetic oneof. + For message fields, proto3_optional doesn't create any semantic change, + since non-repeated message fields always track presence. However it still + indicates the semantic detail of whether the user wrote "optional" or not. + This can be useful for round-tripping the .proto file. For consistency we + give message fields a synthetic oneof also, even though it is not required + to track presence. This is especially important because the parser can't + tell if a field is a message or an enum, so it must always create a + synthetic oneof. - Proto2 optional fields do not set this flag, because they already indicate - optional with `LABEL_OPTIONAL`. + Proto2 optional fields do not set this flag, because they already indicate + optional with `LABEL_OPTIONAL`. """ @@ -1054,7 +1079,14 @@ class OneofDescriptorProto(betterproto.Message): """Describes a oneof.""" name: str = betterproto.string_field(1) + """ + + """ + options: "OneofOptions" = betterproto.message_field(2) + """ + + """ @dataclass(eq=False, repr=False) @@ -1062,21 +1094,35 @@ class EnumDescriptorProto(betterproto.Message): """Describes an enum type.""" name: str = betterproto.string_field(1) - value: List["EnumValueDescriptorProto"] = betterproto.message_field(2) + """ + + """ + + value: List["EnumValueDescriptorProto"] = betterproto.message_field( + 2, repeated=True + ) + """ + + """ + options: "EnumOptions" = betterproto.message_field(3) - reserved_range: List[ - "EnumDescriptorProtoEnumReservedRange" - ] = betterproto.message_field(4) + """ + + """ + + reserved_range: List["EnumDescriptorProtoEnumReservedRange"] = ( + betterproto.message_field(4, repeated=True) + ) """ Range of reserved numeric values. Reserved numeric values may not be used - by enum values in the same enum declaration. Reserved ranges may not - overlap. + by enum values in the same enum declaration. Reserved ranges may not + overlap. """ - reserved_name: List[str] = betterproto.string_field(5) + reserved_name: List[str] = betterproto.string_field(5, repeated=True) """ Reserved enum value names, which may not be reused. A given name may only - be reserved once. + be reserved once. """ @@ -1084,15 +1130,18 @@ class EnumDescriptorProto(betterproto.Message): class EnumDescriptorProtoEnumReservedRange(betterproto.Message): """ Range of reserved numeric values. Reserved values may not be used by - entries in the same enum. Reserved ranges may not overlap. + entries in the same enum. Reserved ranges may not overlap. - Note that this is distinct from DescriptorProto.ReservedRange in that it - is inclusive such that it can appropriately represent the entire int32 - domain. + Note that this is distinct from DescriptorProto.ReservedRange in that it + is inclusive such that it can appropriately represent the entire int32 + domain. """ start: int = betterproto.int32_field(1) + """Inclusive.""" + end: int = betterproto.int32_field(2) + """Inclusive.""" @dataclass(eq=False, repr=False) @@ -1100,8 +1149,19 @@ class EnumValueDescriptorProto(betterproto.Message): """Describes a value within an enum.""" name: str = betterproto.string_field(1) + """ + + """ + number: int = betterproto.int32_field(2) + """ + + """ + options: "EnumValueOptions" = betterproto.message_field(3) + """ + + """ @dataclass(eq=False, repr=False) @@ -1109,8 +1169,19 @@ class ServiceDescriptorProto(betterproto.Message): """Describes a service.""" name: str = betterproto.string_field(1) - method: List["MethodDescriptorProto"] = betterproto.message_field(2) + """ + + """ + + method: List["MethodDescriptorProto"] = betterproto.message_field(2, repeated=True) + """ + + """ + options: "ServiceOptions" = betterproto.message_field(3) + """ + + """ @dataclass(eq=False, repr=False) @@ -1118,14 +1189,26 @@ class MethodDescriptorProto(betterproto.Message): """Describes a method of a service.""" name: str = betterproto.string_field(1) + """ + + """ + input_type: str = betterproto.string_field(2) """ Input and output type names. These are resolved in the same way as - FieldDescriptorProto.type_name, but must refer to a message type. + FieldDescriptorProto.type_name, but must refer to a message type. """ output_type: str = betterproto.string_field(3) + """ + + """ + options: "MethodOptions" = betterproto.message_field(4) + """ + + """ + client_streaming: bool = betterproto.bool_field(5) """Identifies if client streams multiple client messages""" @@ -1135,31 +1218,65 @@ class MethodDescriptorProto(betterproto.Message): @dataclass(eq=False, repr=False) class FileOptions(betterproto.Message): + """ + =================================================================== + Options + + Each of the definitions above may have "options" attached. These are + just annotations which may cause code to be generated slightly differently + or may contain hints for code that manipulates protocol messages. + + Clients may define custom options as extensions of the *Options messages. + These extensions may not yet be known at parsing time, so the parser cannot + store the values in them. Instead it stores them in a field in the *Options + message called uninterpreted_option. This field must have the same name + across all *Options messages. We then use this field to populate the + extensions when we build a descriptor, at which point all protos have been + parsed and so all extensions are known. + + Extension numbers for custom options may be chosen as follows: + * For options which will only be used within a single application or + organization, or for experimental options, use field numbers 50000 + through 99999. It is up to you to ensure that you do not use the + same number for multiple options. + * For options which will be published and used publicly by multiple + independent entities, e-mail protobuf-global-extension-registry@google.com + to reserve extension numbers. Simply provide your project name (e.g. + Objective-C plugin) and your project website (if available) -- there's no + need to explain how you intend to use them. Usually you only need one + extension number. You can declare multiple options with only one extension + number by putting them in a sub-message. See the Custom Options section of + the docs for examples: + https://developers.google.com/protocol-buffers/docs/proto#options + If this turns out to be popular, a web service will be set up + to automatically assign option numbers. + """ + java_package: str = betterproto.string_field(1) """ Sets the Java package where classes generated from this .proto will be - placed. By default, the proto package is used, but this is often - inappropriate because proto packages do not normally start with backwards - domain names. + placed. By default, the proto package is used, but this is often + inappropriate because proto packages do not normally start with backwards + domain names. """ java_outer_classname: str = betterproto.string_field(8) """ - Controls the name of the wrapper Java class generated for the .proto file. - That class will always contain the .proto file's getDescriptor() method as - well as any top-level extensions defined in the .proto file. - If java_multiple_files is disabled, then all the other classes from the - .proto file will be nested inside the single wrapper outer class. + If set, all the classes from the .proto file are wrapped in a single + outer class with the given name. This applies to both Proto1 + (equivalent to the old "--one_java_file" option) and Proto2 (where + a .proto always translates to a single class, but you may want to + explicitly choose the class name). """ java_multiple_files: bool = betterproto.bool_field(10) """ - If enabled, then the Java code generator will generate a separate .java - file for each top-level message, enum, and service defined in the .proto - file. Thus, these types will *not* be nested inside the wrapper class - named by java_outer_classname. However, the wrapper class will still be - generated to contain the file's getDescriptor() method as well as any - top-level extensions defined in the file. + If set true, then the Java code generator will generate a separate .java + file for each top-level message, enum, and service defined in the .proto + file. Thus, these types will *not* be nested inside the outer class + named by java_outer_classname. However, the outer class will still be + generated to contain the file's getDescriptor() method as well as any + top-level extensions defined in the file. """ java_generate_equals_and_hash: bool = betterproto.bool_field(20) @@ -1167,62 +1284,75 @@ class FileOptions(betterproto.Message): java_string_check_utf8: bool = betterproto.bool_field(27) """ - A proto2 file can set this to true to opt in to UTF-8 checking for Java, - which will throw an exception if invalid UTF-8 is parsed from the wire or - assigned to a string field. - - TODO: clarify exactly what kinds of field types this option - applies to, and update these docs accordingly. - - Proto3 files already perform these checks. Setting the option explicitly to - false has no effect: it cannot be used to opt proto3 files out of UTF-8 - checks. + If set true, then the Java2 code generator will generate code that + throws an exception whenever an attempt is made to assign a non-UTF-8 + byte sequence to a string field. + Message reflection will do the same. + However, an extension field still accepts non-UTF-8 byte sequences. + This option has no effect on when used with the lite runtime. """ optimize_for: "FileOptionsOptimizeMode" = betterproto.enum_field(9) + """ + + """ + go_package: str = betterproto.string_field(11) """ Sets the Go package where structs generated from this .proto will be - placed. If omitted, the Go package will be derived from the following: - - The basename of the package import path, if provided. - - Otherwise, the package statement in the .proto file, if present. - - Otherwise, the basename of the .proto file, without extension. + placed. If omitted, the Go package will be derived from the following: + - The basename of the package import path, if provided. + - Otherwise, the package statement in the .proto file, if present. + - Otherwise, the basename of the .proto file, without extension. """ cc_generic_services: bool = betterproto.bool_field(16) """ Should generic services be generated in each language? "Generic" services - are not specific to any particular RPC system. They are generated by the - main code generators in each language (without additional plugins). - Generic services were the only kind of service generation supported by - early versions of google.protobuf. + are not specific to any particular RPC system. They are generated by the + main code generators in each language (without additional plugins). + Generic services were the only kind of service generation supported by + early versions of google.protobuf. - Generic services are now considered deprecated in favor of using plugins - that generate code specific to your particular RPC system. Therefore, - these default to false. Old code which depends on generic services should - explicitly set them to true. + Generic services are now considered deprecated in favor of using plugins + that generate code specific to your particular RPC system. Therefore, + these default to false. Old code which depends on generic services should + explicitly set them to true. """ java_generic_services: bool = betterproto.bool_field(17) + """ + + """ + py_generic_services: bool = betterproto.bool_field(18) + """ + + """ + + php_generic_services: bool = betterproto.bool_field(42) + """ + + """ + deprecated: bool = betterproto.bool_field(23) """ Is this file deprecated? - Depending on the target platform, this can emit Deprecated annotations - for everything in the file, or it will be completely ignored; in the very - least, this is a formalization for deprecating files. + Depending on the target platform, this can emit Deprecated annotations + for everything in the file, or it will be completely ignored; in the very + least, this is a formalization for deprecating files. """ cc_enable_arenas: bool = betterproto.bool_field(31) """ Enables the use of arenas for the proto messages in this file. This applies - only to generated classes for C++. + only to generated classes for C++. """ objc_class_prefix: str = betterproto.string_field(36) """ Sets the objective c class prefix which is prepended to all objective c - generated classes from this .proto. There is no default. + generated classes from this .proto. There is no default. """ csharp_namespace: str = betterproto.string_field(37) @@ -1231,45 +1361,44 @@ class FileOptions(betterproto.Message): swift_prefix: str = betterproto.string_field(39) """ By default Swift generators will take the proto package and CamelCase it - replacing '.' with underscore and use that to prefix the types/symbols - defined. When this options is provided, they will use this value instead - to prefix the types/symbols defined. + replacing '.' with underscore and use that to prefix the types/symbols + defined. When this options is provided, they will use this value instead + to prefix the types/symbols defined. """ php_class_prefix: str = betterproto.string_field(40) """ Sets the php class prefix which is prepended to all php generated classes - from this .proto. Default is empty. + from this .proto. Default is empty. """ php_namespace: str = betterproto.string_field(41) """ Use this option to change the namespace of php generated classes. Default - is empty. When this option is empty, the package name will be used for - determining the namespace. + is empty. When this option is empty, the package name will be used for + determining the namespace. """ php_metadata_namespace: str = betterproto.string_field(44) """ Use this option to change the namespace of php generated metadata classes. - Default is empty. When this option is empty, the proto file name will be - used for determining the namespace. + Default is empty. When this option is empty, the proto file name will be + used for determining the namespace. """ ruby_package: str = betterproto.string_field(45) """ Use this option to change the package of ruby generated classes. Default - is empty. When this option is not set, the package name will be used for - determining the ruby package. + is empty. When this option is not set, the package name will be used for + determining the ruby package. """ - features: "FeatureSet" = betterproto.message_field(50) - """Any features defined in the specific edition.""" - - uninterpreted_option: List["UninterpretedOption"] = betterproto.message_field(999) + uninterpreted_option: List["UninterpretedOption"] = betterproto.message_field( + 999, repeated=True + ) """ The parser stores options it doesn't recognize here. - See the documentation for the "Options" section above. + See the documentation for the "Options" section above. """ def __post_init__(self) -> None: @@ -1283,339 +1412,260 @@ def __post_init__(self) -> None: @dataclass(eq=False, repr=False) class MessageOptions(betterproto.Message): + """ """ + message_set_wire_format: bool = betterproto.bool_field(1) """ Set true to use the old proto1 MessageSet wire format for extensions. - This is provided for backwards-compatibility with the MessageSet wire - format. You should not use this for any other reason: It's less - efficient, has fewer features, and is more complicated. + This is provided for backwards-compatibility with the MessageSet wire + format. You should not use this for any other reason: It's less + efficient, has fewer features, and is more complicated. - The message must be defined exactly as follows: - message Foo { - option message_set_wire_format = true; - extensions 4 to max; - } - Note that the message cannot have any defined fields; MessageSets only - have extensions. + The message must be defined exactly as follows: + message Foo { + option message_set_wire_format = true; + extensions 4 to max; + } + Note that the message cannot have any defined fields; MessageSets only + have extensions. - All extensions of your type must be singular messages; e.g. they cannot - be int32s, enums, or repeated messages. + All extensions of your type must be singular messages; e.g. they cannot + be int32s, enums, or repeated messages. - Because this is an option, the above two restrictions are not enforced by - the protocol compiler. + Because this is an option, the above two restrictions are not enforced by + the protocol compiler. """ no_standard_descriptor_accessor: bool = betterproto.bool_field(2) """ Disables the generation of the standard "descriptor()" accessor, which can - conflict with a field of the same name. This is meant to make migration - from proto1 easier; new code should avoid fields named "descriptor". + conflict with a field of the same name. This is meant to make migration + from proto1 easier; new code should avoid fields named "descriptor". """ deprecated: bool = betterproto.bool_field(3) """ Is this message deprecated? - Depending on the target platform, this can emit Deprecated annotations - for the message, or it will be completely ignored; in the very least, - this is a formalization for deprecating messages. + Depending on the target platform, this can emit Deprecated annotations + for the message, or it will be completely ignored; in the very least, + this is a formalization for deprecating messages. """ map_entry: bool = betterproto.bool_field(7) """ Whether the message is an automatically generated map entry type for the - maps field. - - For maps fields: - map map_field = 1; - The parsed descriptor looks like: - message MapFieldEntry { - option map_entry = true; - optional KeyType key = 1; - optional ValueType value = 2; - } - repeated MapFieldEntry map_field = 1; - - Implementations may choose not to generate the map_entry=true message, but - use a native map in the target language to hold the keys and values. - The reflection APIs in such implementations still need to work as - if the field is a repeated message field. + maps field. - NOTE: Do not set the option in .proto files. Always use the maps syntax - instead. The option should only be implicitly set by the proto compiler - parser. - """ - - deprecated_legacy_json_field_conflicts: bool = betterproto.bool_field(11) - """ - Enable the legacy handling of JSON field name conflicts. This lowercases - and strips underscored from the fields before comparison in proto3 only. - The new behavior takes `json_name` into account and applies to proto2 as - well. + For maps fields: + map map_field = 1; + The parsed descriptor looks like: + message MapFieldEntry { + option map_entry = true; + optional KeyType key = 1; + optional ValueType value = 2; + } + repeated MapFieldEntry map_field = 1; - This should only be used as a temporary measure against broken builds due - to the change in behavior for JSON field name conflicts. + Implementations may choose not to generate the map_entry=true message, but + use a native map in the target language to hold the keys and values. + The reflection APIs in such implementations still need to work as + if the field is a repeated message field. - TODO This is legacy behavior we plan to remove once downstream - teams have had time to migrate. + NOTE: Do not set the option in .proto files. Always use the maps syntax + instead. The option should only be implicitly set by the proto compiler + parser. """ - features: "FeatureSet" = betterproto.message_field(12) - """Any features defined in the specific edition.""" - - uninterpreted_option: List["UninterpretedOption"] = betterproto.message_field(999) + uninterpreted_option: List["UninterpretedOption"] = betterproto.message_field( + 999, repeated=True + ) """The parser stores options it doesn't recognize here. See above.""" - def __post_init__(self) -> None: - super().__post_init__() - if self.is_set("deprecated_legacy_json_field_conflicts"): - warnings.warn( - "MessageOptions.deprecated_legacy_json_field_conflicts is deprecated", - DeprecationWarning, - ) - @dataclass(eq=False, repr=False) class FieldOptions(betterproto.Message): + """ """ + ctype: "FieldOptionsCType" = betterproto.enum_field(1) """ The ctype option instructs the C++ code generator to use a different - representation of the field than it normally would. See the specific - options below. This option is only implemented to support use of - [ctype=CORD] and [ctype=STRING] (the default) on non-repeated fields of - type "bytes" in the open source release -- sorry, we'll try to include - other types in a future version! + representation of the field than it normally would. See the specific + options below. This option is not yet implemented in the open source + release -- sorry, we'll try to include it in a future version! """ packed: bool = betterproto.bool_field(2) """ The packed option can be enabled for repeated primitive fields to enable - a more efficient representation on the wire. Rather than repeatedly - writing the tag and type for each element, the entire array is encoded as - a single length-delimited blob. In proto3, only explicit setting it to - false will avoid using packed encoding. This option is prohibited in - Editions, but the `repeated_field_encoding` feature can be used to control - the behavior. + a more efficient representation on the wire. Rather than repeatedly + writing the tag and type for each element, the entire array is encoded as + a single length-delimited blob. In proto3, only explicit setting it to + false will avoid using packed encoding. """ jstype: "FieldOptionsJsType" = betterproto.enum_field(6) """ The jstype option determines the JavaScript type used for values of the - field. The option is permitted only for 64 bit integral and fixed types - (int64, uint64, sint64, fixed64, sfixed64). A field with jstype JS_STRING - is represented as JavaScript string, which avoids loss of precision that - can happen when a large value is converted to a floating point JavaScript. - Specifying JS_NUMBER for the jstype causes the generated JavaScript code to - use the JavaScript "number" type. The behavior of the default option - JS_NORMAL is implementation dependent. + field. The option is permitted only for 64 bit integral and fixed types + (int64, uint64, sint64, fixed64, sfixed64). A field with jstype JS_STRING + is represented as JavaScript string, which avoids loss of precision that + can happen when a large value is converted to a floating point JavaScript. + Specifying JS_NUMBER for the jstype causes the generated JavaScript code to + use the JavaScript "number" type. The behavior of the default option + JS_NORMAL is implementation dependent. - This option is an enum to permit additional types to be added, e.g. - goog.math.Integer. + This option is an enum to permit additional types to be added, e.g. + goog.math.Integer. """ lazy: bool = betterproto.bool_field(5) """ Should this field be parsed lazily? Lazy applies only to message-type - fields. It means that when the outer message is initially parsed, the - inner message's contents will not be parsed but instead stored in encoded - form. The inner message will actually be parsed when it is first accessed. + fields. It means that when the outer message is initially parsed, the + inner message's contents will not be parsed but instead stored in encoded + form. The inner message will actually be parsed when it is first accessed. - This is only a hint. Implementations are free to choose whether to use - eager or lazy parsing regardless of the value of this option. However, - setting this option true suggests that the protocol author believes that - using lazy parsing on this field is worth the additional bookkeeping - overhead typically needed to implement it. + This is only a hint. Implementations are free to choose whether to use + eager or lazy parsing regardless of the value of this option. However, + setting this option true suggests that the protocol author believes that + using lazy parsing on this field is worth the additional bookkeeping + overhead typically needed to implement it. - This option does not affect the public interface of any generated code; - all method signatures remain the same. Furthermore, thread-safety of the - interface is not affected by this option; const methods remain safe to - call from multiple threads concurrently, while non-const methods continue - to require exclusive access. + This option does not affect the public interface of any generated code; + all method signatures remain the same. Furthermore, thread-safety of the + interface is not affected by this option; const methods remain safe to + call from multiple threads concurrently, while non-const methods continue + to require exclusive access. - Note that lazy message fields are still eagerly verified to check - ill-formed wireformat or missing required fields. Calling IsInitialized() - on the outer message would fail if the inner message has missing required - fields. Failed verification would result in parsing failure (except when - uninitialized messages are acceptable). - """ - - unverified_lazy: bool = betterproto.bool_field(15) - """ - unverified_lazy does no correctness checks on the byte stream. This should - only be used where lazy with verification is prohibitive for performance - reasons. + Note that implementations may choose not to check required fields within + a lazy sub-message. That is, calling IsInitialized() on the outer message + may return true even if the inner message has missing required fields. + This is necessary because otherwise the inner message would have to be + parsed in order to perform the check, defeating the purpose of lazy + parsing. An implementation which chooses not to check required fields + must be consistent about it. That is, for any particular sub-message, the + implementation must either *always* check its required fields, or *never* + check its required fields, regardless of whether or not the message has + been parsed. """ deprecated: bool = betterproto.bool_field(3) """ Is this field deprecated? - Depending on the target platform, this can emit Deprecated annotations - for accessors, or it will be completely ignored; in the very least, this - is a formalization for deprecating fields. + Depending on the target platform, this can emit Deprecated annotations + for accessors, or it will be completely ignored; in the very least, this + is a formalization for deprecating fields. """ weak: bool = betterproto.bool_field(10) """For Google-internal migration only. Do not use.""" - debug_redact: bool = betterproto.bool_field(16) - """ - Indicate that the field value should not be printed out when using debug - formats, e.g. when the field contains sensitive credentials. - """ - - retention: "FieldOptionsOptionRetention" = betterproto.enum_field(17) - targets: List["FieldOptionsOptionTargetType"] = betterproto.enum_field(19) - edition_defaults: List["FieldOptionsEditionDefault"] = betterproto.message_field(20) - features: "FeatureSet" = betterproto.message_field(21) - """Any features defined in the specific edition.""" - - feature_support: "FieldOptionsFeatureSupport" = betterproto.message_field(22) - uninterpreted_option: List["UninterpretedOption"] = betterproto.message_field(999) + uninterpreted_option: List["UninterpretedOption"] = betterproto.message_field( + 999, repeated=True + ) """The parser stores options it doesn't recognize here. See above.""" -@dataclass(eq=False, repr=False) -class FieldOptionsEditionDefault(betterproto.Message): - edition: "Edition" = betterproto.enum_field(3) - value: str = betterproto.string_field(2) - - -@dataclass(eq=False, repr=False) -class FieldOptionsFeatureSupport(betterproto.Message): - """Information about the support window of a feature.""" - - edition_introduced: "Edition" = betterproto.enum_field(1) - """ - The edition that this feature was first available in. In editions - earlier than this one, the default assigned to EDITION_LEGACY will be - used, and proto files will not be able to override it. - """ - - edition_deprecated: "Edition" = betterproto.enum_field(2) - """ - The edition this feature becomes deprecated in. Using this after this - edition may trigger warnings. - """ - - deprecation_warning: str = betterproto.string_field(3) - """ - The deprecation warning text if this feature is used after the edition it - was marked deprecated in. - """ - - edition_removed: "Edition" = betterproto.enum_field(4) - """ - The edition this feature is no longer available in. In editions after - this one, the last default assigned will be used, and proto files will - not be able to override it. - """ - - @dataclass(eq=False, repr=False) class OneofOptions(betterproto.Message): - features: "FeatureSet" = betterproto.message_field(1) - """Any features defined in the specific edition.""" + """ """ - uninterpreted_option: List["UninterpretedOption"] = betterproto.message_field(999) + uninterpreted_option: List["UninterpretedOption"] = betterproto.message_field( + 999, repeated=True + ) """The parser stores options it doesn't recognize here. See above.""" @dataclass(eq=False, repr=False) class EnumOptions(betterproto.Message): + """ """ + allow_alias: bool = betterproto.bool_field(2) """ Set this option to true to allow mapping different tag names to the same - value. + value. """ deprecated: bool = betterproto.bool_field(3) """ Is this enum deprecated? - Depending on the target platform, this can emit Deprecated annotations - for the enum, or it will be completely ignored; in the very least, this - is a formalization for deprecating enums. - """ - - deprecated_legacy_json_field_conflicts: bool = betterproto.bool_field(6) - """ - Enable the legacy handling of JSON field name conflicts. This lowercases - and strips underscored from the fields before comparison in proto3 only. - The new behavior takes `json_name` into account and applies to proto2 as - well. - TODO Remove this legacy behavior once downstream teams have - had time to migrate. + Depending on the target platform, this can emit Deprecated annotations + for the enum, or it will be completely ignored; in the very least, this + is a formalization for deprecating enums. """ - features: "FeatureSet" = betterproto.message_field(7) - """Any features defined in the specific edition.""" - - uninterpreted_option: List["UninterpretedOption"] = betterproto.message_field(999) + uninterpreted_option: List["UninterpretedOption"] = betterproto.message_field( + 999, repeated=True + ) """The parser stores options it doesn't recognize here. See above.""" - def __post_init__(self) -> None: - super().__post_init__() - if self.is_set("deprecated_legacy_json_field_conflicts"): - warnings.warn( - "EnumOptions.deprecated_legacy_json_field_conflicts is deprecated", - DeprecationWarning, - ) - @dataclass(eq=False, repr=False) class EnumValueOptions(betterproto.Message): + """ """ + deprecated: bool = betterproto.bool_field(1) """ Is this enum value deprecated? - Depending on the target platform, this can emit Deprecated annotations - for the enum value, or it will be completely ignored; in the very least, - this is a formalization for deprecating enum values. + Depending on the target platform, this can emit Deprecated annotations + for the enum value, or it will be completely ignored; in the very least, + this is a formalization for deprecating enum values. """ - features: "FeatureSet" = betterproto.message_field(2) - """Any features defined in the specific edition.""" - - debug_redact: bool = betterproto.bool_field(3) - """ - Indicate that fields annotated with this enum value should not be printed - out when using debug formats, e.g. when the field contains sensitive - credentials. - """ - - uninterpreted_option: List["UninterpretedOption"] = betterproto.message_field(999) + uninterpreted_option: List["UninterpretedOption"] = betterproto.message_field( + 999, repeated=True + ) """The parser stores options it doesn't recognize here. See above.""" @dataclass(eq=False, repr=False) class ServiceOptions(betterproto.Message): - features: "FeatureSet" = betterproto.message_field(34) - """Any features defined in the specific edition.""" + """ """ deprecated: bool = betterproto.bool_field(33) """ + Note: Field numbers 1 through 32 are reserved for Google's internal RPC + framework. We apologize for hoarding these numbers to ourselves, but + we were already using them long before we decided to release Protocol + Buffers. + Is this service deprecated? - Depending on the target platform, this can emit Deprecated annotations - for the service, or it will be completely ignored; in the very least, - this is a formalization for deprecating services. + Depending on the target platform, this can emit Deprecated annotations + for the service, or it will be completely ignored; in the very least, + this is a formalization for deprecating services. """ - uninterpreted_option: List["UninterpretedOption"] = betterproto.message_field(999) + uninterpreted_option: List["UninterpretedOption"] = betterproto.message_field( + 999, repeated=True + ) """The parser stores options it doesn't recognize here. See above.""" @dataclass(eq=False, repr=False) class MethodOptions(betterproto.Message): + """ """ + deprecated: bool = betterproto.bool_field(33) """ + Note: Field numbers 1 through 32 are reserved for Google's internal RPC + framework. We apologize for hoarding these numbers to ourselves, but + we were already using them long before we decided to release Protocol + Buffers. + Is this method deprecated? - Depending on the target platform, this can emit Deprecated annotations - for the method, or it will be completely ignored; in the very least, - this is a formalization for deprecating methods. + Depending on the target platform, this can emit Deprecated annotations + for the method, or it will be completely ignored; in the very least, + this is a formalization for deprecating methods. """ idempotency_level: "MethodOptionsIdempotencyLevel" = betterproto.enum_field(34) - features: "FeatureSet" = betterproto.message_field(35) - """Any features defined in the specific edition.""" + """ + + """ - uninterpreted_option: List["UninterpretedOption"] = betterproto.message_field(999) + uninterpreted_option: List["UninterpretedOption"] = betterproto.message_field( + 999, repeated=True + ) """The parser stores options it doesn't recognize here. See above.""" @@ -1623,279 +1673,260 @@ class MethodOptions(betterproto.Message): class UninterpretedOption(betterproto.Message): """ A message representing a option the parser does not recognize. This only - appears in options protos created by the compiler::Parser class. - DescriptorPool resolves these when building Descriptor objects. Therefore, - options protos in descriptor objects (e.g. returned by Descriptor::options(), - or produced by Descriptor::CopyTo()) will never have UninterpretedOptions - in them. + appears in options protos created by the compiler::Parser class. + DescriptorPool resolves these when building Descriptor objects. Therefore, + options protos in descriptor objects (e.g. returned by Descriptor::options(), + or produced by Descriptor::CopyTo()) will never have UninterpretedOptions + in them. + """ + + name: List["UninterpretedOptionNamePart"] = betterproto.message_field( + 2, repeated=True + ) + """ + """ - name: List["UninterpretedOptionNamePart"] = betterproto.message_field(2) identifier_value: str = betterproto.string_field(3) """ The value of the uninterpreted option, in whatever type the tokenizer - identified it as during parsing. Exactly one of these should be set. + identified it as during parsing. Exactly one of these should be set. """ positive_int_value: int = betterproto.uint64_field(4) - negative_int_value: int = betterproto.int64_field(5) - double_value: float = betterproto.double_field(6) - string_value: bytes = betterproto.bytes_field(7) - aggregate_value: str = betterproto.string_field(8) - - -@dataclass(eq=False, repr=False) -class UninterpretedOptionNamePart(betterproto.Message): """ - The name of the uninterpreted option. Each string represents a segment in - a dot-separated name. is_extension is true iff a segment represents an - extension (denoted with parentheses in options specs in .proto files). - E.g.,{ ["foo", false], ["bar.baz", true], ["moo", false] } represents - "foo.(bar.baz).moo". + """ - name_part: str = betterproto.string_field(1) - is_extension: bool = betterproto.bool_field(2) - - -@dataclass(eq=False, repr=False) -class FeatureSet(betterproto.Message): + negative_int_value: int = betterproto.int64_field(5) """ - TODO Enums in C++ gencode (and potentially other languages) are - not well scoped. This means that each of the feature enums below can clash - with each other. The short names we've chosen maximize call-site - readability, but leave us very open to this scenario. A future feature will - be designed and implemented to handle this, hopefully before we ever hit a - conflict here. + """ - field_presence: "FeatureSetFieldPresence" = betterproto.enum_field(1) - enum_type: "FeatureSetEnumType" = betterproto.enum_field(2) - repeated_field_encoding: "FeatureSetRepeatedFieldEncoding" = betterproto.enum_field( - 3 - ) - utf8_validation: "FeatureSetUtf8Validation" = betterproto.enum_field(4) - message_encoding: "FeatureSetMessageEncoding" = betterproto.enum_field(5) - json_format: "FeatureSetJsonFormat" = betterproto.enum_field(6) - - -@dataclass(eq=False, repr=False) -class FeatureSetDefaults(betterproto.Message): + double_value: float = betterproto.double_field(6) """ - A compiled specification for the defaults of a set of features. These - messages are generated from FeatureSet extensions and can be used to seed - feature resolution. The resolution with this object becomes a simple search - for the closest matching edition, followed by proto merges. + """ - defaults: List[ - "FeatureSetDefaultsFeatureSetEditionDefault" - ] = betterproto.message_field(1) - minimum_edition: "Edition" = betterproto.enum_field(4) + string_value: bytes = betterproto.bytes_field(7) """ - The minimum supported edition (inclusive) when this was constructed. - Editions before this will not have defaults. + """ - maximum_edition: "Edition" = betterproto.enum_field(5) + aggregate_value: str = betterproto.string_field(8) """ - The maximum known edition (inclusive) when this was constructed. Editions - after this will not have reliable defaults. + """ @dataclass(eq=False, repr=False) -class FeatureSetDefaultsFeatureSetEditionDefault(betterproto.Message): +class UninterpretedOptionNamePart(betterproto.Message): """ - A map from every known edition with a unique set of defaults to its - defaults. Not all editions may be contained here. For a given edition, - the defaults at the closest matching edition ordered at or before it should - be used. This field must be in strict ascending order by edition. + The name of the uninterpreted option. Each string represents a segment in + a dot-separated name. is_extension is true iff a segment represents an + extension (denoted with parentheses in options specs in .proto files). + E.g.,{ ["foo", false], ["bar.baz", true], ["qux", false] } represents + "foo.(bar.baz).qux". """ - edition: "Edition" = betterproto.enum_field(3) - overridable_features: "FeatureSet" = betterproto.message_field(4) - """Defaults of features that can be overridden in this edition.""" - - fixed_features: "FeatureSet" = betterproto.message_field(5) - """Defaults of features that can't be overridden in this edition.""" + name_part: str = betterproto.string_field(1) + """ + + """ - features: "FeatureSet" = betterproto.message_field(2) + is_extension: bool = betterproto.bool_field(2) """ - TODO Deprecate and remove this field, which is just the - above two merged. + """ @dataclass(eq=False, repr=False) class SourceCodeInfo(betterproto.Message): """ + =================================================================== + Optional source code info + Encapsulates information about the original source file from which a - FileDescriptorProto was generated. + FileDescriptorProto was generated. """ - location: List["SourceCodeInfoLocation"] = betterproto.message_field(1) + location: List["SourceCodeInfoLocation"] = betterproto.message_field( + 1, repeated=True + ) """ A Location identifies a piece of source code in a .proto file which - corresponds to a particular definition. This information is intended - to be useful to IDEs, code indexers, documentation generators, and similar - tools. - - For example, say we have a file like: - message Foo { - optional string foo = 1; - } - Let's look at just the field definition: - optional string foo = 1; - ^ ^^ ^^ ^ ^^^ - a bc de f ghi - We have the following locations: - span path represents - [a,i) [ 4, 0, 2, 0 ] The whole field definition. - [a,b) [ 4, 0, 2, 0, 4 ] The label (optional). - [c,d) [ 4, 0, 2, 0, 5 ] The type (string). - [e,f) [ 4, 0, 2, 0, 1 ] The name (foo). - [g,h) [ 4, 0, 2, 0, 3 ] The number (1). - - Notes: - - A location may refer to a repeated field itself (i.e. not to any - particular index within it). This is used whenever a set of elements are - logically enclosed in a single code segment. For example, an entire - extend block (possibly containing multiple extension definitions) will - have an outer location whose path refers to the "extensions" repeated - field without an index. - - Multiple locations may have the same path. This happens when a single - logical declaration is spread out across multiple places. The most - obvious example is the "extend" block again -- there may be multiple - extend blocks in the same scope, each of which will have the same path. - - A location's span is not always a subset of its parent's span. For - example, the "extendee" of an extension declaration appears at the - beginning of the "extend" block and is shared by all extensions within - the block. - - Just because a location's span is a subset of some other location's span - does not mean that it is a descendant. For example, a "group" defines - both a type and a field in a single declaration. Thus, the locations - corresponding to the type and field and their components will overlap. - - Code which tries to interpret locations should probably be designed to - ignore those that it doesn't understand, as more types of locations could - be recorded in the future. + corresponds to a particular definition. This information is intended + to be useful to IDEs, code indexers, documentation generators, and similar + tools. + + For example, say we have a file like: + message Foo { + optional string foo = 1; + } + Let's look at just the field definition: + optional string foo = 1; + ^ ^^ ^^ ^ ^^^ + a bc de f ghi + We have the following locations: + span path represents + [a,i) [ 4, 0, 2, 0 ] The whole field definition. + [a,b) [ 4, 0, 2, 0, 4 ] The label (optional). + [c,d) [ 4, 0, 2, 0, 5 ] The type (string). + [e,f) [ 4, 0, 2, 0, 1 ] The name (foo). + [g,h) [ 4, 0, 2, 0, 3 ] The number (1). + + Notes: + - A location may refer to a repeated field itself (i.e. not to any + particular index within it). This is used whenever a set of elements are + logically enclosed in a single code segment. For example, an entire + extend block (possibly containing multiple extension definitions) will + have an outer location whose path refers to the "extensions" repeated + field without an index. + - Multiple locations may have the same path. This happens when a single + logical declaration is spread out across multiple places. The most + obvious example is the "extend" block again -- there may be multiple + extend blocks in the same scope, each of which will have the same path. + - A location's span is not always a subset of its parent's span. For + example, the "extendee" of an extension declaration appears at the + beginning of the "extend" block and is shared by all extensions within + the block. + - Just because a location's span is a subset of some other location's span + does not mean that it is a descendant. For example, a "group" defines + both a type and a field in a single declaration. Thus, the locations + corresponding to the type and field and their components will overlap. + - Code which tries to interpret locations should probably be designed to + ignore those that it doesn't understand, as more types of locations could + be recorded in the future. """ @dataclass(eq=False, repr=False) class SourceCodeInfoLocation(betterproto.Message): - path: List[int] = betterproto.int32_field(1) + """ """ + + path: List[int] = betterproto.int32_field(1, repeated=True) """ Identifies which part of the FileDescriptorProto was defined at this - location. - - Each element is a field number or an index. They form a path from - the root FileDescriptorProto to the place where the definition appears. - For example, this path: - [ 4, 3, 2, 7, 1 ] - refers to: - file.message_type(3) // 4, 3 - .field(7) // 2, 7 - .name() // 1 - This is because FileDescriptorProto.message_type has field number 4: - repeated DescriptorProto message_type = 4; - and DescriptorProto.field has field number 2: - repeated FieldDescriptorProto field = 2; - and FieldDescriptorProto.name has field number 1: - optional string name = 1; - - Thus, the above path gives the location of a field name. If we removed - the last element: - [ 4, 3, 2, 7 ] - this path refers to the whole field declaration (from the beginning - of the label to the terminating semicolon). - """ - - span: List[int] = betterproto.int32_field(2) + location. + + Each element is a field number or an index. They form a path from + the root FileDescriptorProto to the place where the definition. For + example, this path: + [ 4, 3, 2, 7, 1 ] + refers to: + file.message_type(3) // 4, 3 + .field(7) // 2, 7 + .name() // 1 + This is because FileDescriptorProto.message_type has field number 4: + repeated DescriptorProto message_type = 4; + and DescriptorProto.field has field number 2: + repeated FieldDescriptorProto field = 2; + and FieldDescriptorProto.name has field number 1: + optional string name = 1; + + Thus, the above path gives the location of a field name. If we removed + the last element: + [ 4, 3, 2, 7 ] + this path refers to the whole field declaration (from the beginning + of the label to the terminating semicolon). + """ + + span: List[int] = betterproto.int32_field(2, repeated=True) """ Always has exactly three or four elements: start line, start column, - end line (optional, otherwise assumed same as start line), end column. - These are packed into a single field for efficiency. Note that line - and column numbers are zero-based -- typically you will want to add - 1 to each before displaying to a user. + end line (optional, otherwise assumed same as start line), end column. + These are packed into a single field for efficiency. Note that line + and column numbers are zero-based -- typically you will want to add + 1 to each before displaying to a user. """ leading_comments: str = betterproto.string_field(3) """ If this SourceCodeInfo represents a complete declaration, these are any - comments appearing before and after the declaration which appear to be - attached to the declaration. + comments appearing before and after the declaration which appear to be + attached to the declaration. - A series of line comments appearing on consecutive lines, with no other - tokens appearing on those lines, will be treated as a single comment. + A series of line comments appearing on consecutive lines, with no other + tokens appearing on those lines, will be treated as a single comment. - leading_detached_comments will keep paragraphs of comments that appear - before (but not connected to) the current element. Each paragraph, - separated by empty lines, will be one comment element in the repeated - field. + leading_detached_comments will keep paragraphs of comments that appear + before (but not connected to) the current element. Each paragraph, + separated by empty lines, will be one comment element in the repeated + field. - Only the comment content is provided; comment markers (e.g. //) are - stripped out. For block comments, leading whitespace and an asterisk - will be stripped from the beginning of each line other than the first. - Newlines are included in the output. + Only the comment content is provided; comment markers (e.g. //) are + stripped out. For block comments, leading whitespace and an asterisk + will be stripped from the beginning of each line other than the first. + Newlines are included in the output. - Examples: + Examples: - optional int32 foo = 1; // Comment attached to foo. - // Comment attached to bar. - optional int32 bar = 2; + optional int32 foo = 1; // Comment attached to foo. + // Comment attached to bar. + optional int32 bar = 2; - optional string baz = 3; - // Comment attached to baz. - // Another line attached to baz. + optional string baz = 3; + // Comment attached to baz. + // Another line attached to baz. - // Comment attached to moo. - // - // Another line attached to moo. - optional double moo = 4; + // Comment attached to qux. + // + // Another line attached to qux. + optional double qux = 4; - // Detached comment for corge. This is not leading or trailing comments - // to moo or corge because there are blank lines separating it from - // both. + // Detached comment for corge. This is not leading or trailing comments + // to qux or corge because there are blank lines separating it from + // both. - // Detached comment for corge paragraph 2. + // Detached comment for corge paragraph 2. - optional string corge = 5; - /* Block comment attached - * to corge. Leading asterisks - * will be removed. */ - /* Block comment attached to - * grault. */ - optional int32 grault = 6; + optional string corge = 5; + /* Block comment attached + * to corge. Leading asterisks + * will be removed. */ + /* Block comment attached to + * grault. */ + optional int32 grault = 6; - // ignored detached comments. + // ignored detached comments. """ trailing_comments: str = betterproto.string_field(4) - leading_detached_comments: List[str] = betterproto.string_field(6) + """ + + """ + + leading_detached_comments: List[str] = betterproto.string_field(6, repeated=True) + """ + + """ @dataclass(eq=False, repr=False) class GeneratedCodeInfo(betterproto.Message): """ Describes the relationship between generated code and its original source - file. A GeneratedCodeInfo message is associated with only one generated - source file, but may contain references to different source .proto files. + file. A GeneratedCodeInfo message is associated with only one generated + source file, but may contain references to different source .proto files. """ - annotation: List["GeneratedCodeInfoAnnotation"] = betterproto.message_field(1) + annotation: List["GeneratedCodeInfoAnnotation"] = betterproto.message_field( + 1, repeated=True + ) """ An Annotation connects some span of text in generated code to an element - of its generating .proto file. + of its generating .proto file. """ @dataclass(eq=False, repr=False) class GeneratedCodeInfoAnnotation(betterproto.Message): - path: List[int] = betterproto.int32_field(1) + """ """ + + path: List[int] = betterproto.int32_field(1, repeated=True) """ Identifies the element in the original source .proto file. This field - is formatted the same as SourceCodeInfo.Location.path. + is formatted the same as SourceCodeInfo.Location.path. """ source_file: str = betterproto.string_field(2) @@ -1904,97 +1935,95 @@ class GeneratedCodeInfoAnnotation(betterproto.Message): begin: int = betterproto.int32_field(3) """ Identifies the starting offset in bytes in the generated code - that relates to the identified object. + that relates to the identified object. """ end: int = betterproto.int32_field(4) """ Identifies the ending offset in bytes in the generated code that - relates to the identified object. The end offset should be one past - the last relevant byte (so the length of the text = end - begin). + relates to the identified offset. The end offset should be one past + the last relevant byte (so the length of the text = end - begin). """ - semantic: "GeneratedCodeInfoAnnotationSemantic" = betterproto.enum_field(5) - @dataclass(eq=False, repr=False) class Duration(betterproto.Message): """ A Duration represents a signed, fixed-length span of time represented - as a count of seconds and fractions of seconds at nanosecond - resolution. It is independent of any calendar and concepts like "day" - or "month". It is related to Timestamp in that the difference between - two Timestamp values is a Duration and it can be added or subtracted - from a Timestamp. Range is approximately +-10,000 years. + as a count of seconds and fractions of seconds at nanosecond + resolution. It is independent of any calendar and concepts like "day" + or "month". It is related to Timestamp in that the difference between + two Timestamp values is a Duration and it can be added or subtracted + from a Timestamp. Range is approximately +-10,000 years. - # Examples + # Examples - Example 1: Compute Duration from two Timestamps in pseudo code. + Example 1: Compute Duration from two Timestamps in pseudo code. - Timestamp start = ...; - Timestamp end = ...; - Duration duration = ...; + Timestamp start = ...; + Timestamp end = ...; + Duration duration = ...; - duration.seconds = end.seconds - start.seconds; - duration.nanos = end.nanos - start.nanos; + duration.seconds = end.seconds - start.seconds; + duration.nanos = end.nanos - start.nanos; - if (duration.seconds < 0 && duration.nanos > 0) { - duration.seconds += 1; - duration.nanos -= 1000000000; - } else if (duration.seconds > 0 && duration.nanos < 0) { - duration.seconds -= 1; - duration.nanos += 1000000000; - } + if (duration.seconds < 0 && duration.nanos > 0) { + duration.seconds += 1; + duration.nanos -= 1000000000; + } else if (duration.seconds > 0 && duration.nanos < 0) { + duration.seconds -= 1; + duration.nanos += 1000000000; + } - Example 2: Compute Timestamp from Timestamp + Duration in pseudo code. + Example 2: Compute Timestamp from Timestamp + Duration in pseudo code. - Timestamp start = ...; - Duration duration = ...; - Timestamp end = ...; + Timestamp start = ...; + Duration duration = ...; + Timestamp end = ...; - end.seconds = start.seconds + duration.seconds; - end.nanos = start.nanos + duration.nanos; + end.seconds = start.seconds + duration.seconds; + end.nanos = start.nanos + duration.nanos; - if (end.nanos < 0) { - end.seconds -= 1; - end.nanos += 1000000000; - } else if (end.nanos >= 1000000000) { - end.seconds += 1; - end.nanos -= 1000000000; - } + if (end.nanos < 0) { + end.seconds -= 1; + end.nanos += 1000000000; + } else if (end.nanos >= 1000000000) { + end.seconds += 1; + end.nanos -= 1000000000; + } - Example 3: Compute Duration from datetime.timedelta in Python. + Example 3: Compute Duration from datetime.timedelta in Python. - td = datetime.timedelta(days=3, minutes=10) - duration = Duration() - duration.FromTimedelta(td) + td = datetime.timedelta(days=3, minutes=10) + duration = Duration() + duration.FromTimedelta(td) - # JSON Mapping + # JSON Mapping - In JSON format, the Duration type is encoded as a string rather than an - object, where the string ends in the suffix "s" (indicating seconds) and - is preceded by the number of seconds, with nanoseconds expressed as - fractional seconds. For example, 3 seconds with 0 nanoseconds should be - encoded in JSON format as "3s", while 3 seconds and 1 nanosecond should - be expressed in JSON format as "3.000000001s", and 3 seconds and 1 - microsecond should be expressed in JSON format as "3.000001s". + In JSON format, the Duration type is encoded as a string rather than an + object, where the string ends in the suffix "s" (indicating seconds) and + is preceded by the number of seconds, with nanoseconds expressed as + fractional seconds. For example, 3 seconds with 0 nanoseconds should be + encoded in JSON format as "3s", while 3 seconds and 1 nanosecond should + be expressed in JSON format as "3.000000001s", and 3 seconds and 1 + microsecond should be expressed in JSON format as "3.000001s". """ seconds: int = betterproto.int64_field(1) """ Signed seconds of the span of time. Must be from -315,576,000,000 - to +315,576,000,000 inclusive. Note: these bounds are computed from: - 60 sec/min * 60 min/hr * 24 hr/day * 365.25 days/year * 10000 years + to +315,576,000,000 inclusive. Note: these bounds are computed from: + 60 sec/min * 60 min/hr * 24 hr/day * 365.25 days/year * 10000 years """ nanos: int = betterproto.int32_field(2) """ Signed fractions of a second at nanosecond resolution of the span - of time. Durations less than one second are represented with a 0 - `seconds` field and a positive or negative `nanos` field. For durations - of one second or more, a non-zero value for the `nanos` field must be - of the same sign as the `seconds` field. Must be from -999,999,999 - to +999,999,999 inclusive. + of time. Durations less than one second are represented with a 0 + `seconds` field and a positive or negative `nanos` field. For durations + of one second or more, a non-zero value for the `nanos` field must be + of the same sign as the `seconds` field. Must be from -999,999,999 + to +999,999,999 inclusive. """ @@ -2002,12 +2031,14 @@ class Duration(betterproto.Message): class Empty(betterproto.Message): """ A generic empty message that you can re-use to avoid defining duplicated - empty messages in your APIs. A typical example is to use it as the request - or the response type of an API method. For instance: + empty messages in your APIs. A typical example is to use it as the request + or the response type of an API method. For instance: - service Foo { - rpc Bar(google.protobuf.Empty) returns (google.protobuf.Empty); - } + service Foo { + rpc Bar(google.protobuf.Empty) returns (google.protobuf.Empty); + } + + The JSON representation for `Empty` is empty JSON object `{}`. """ pass @@ -2018,206 +2049,205 @@ class FieldMask(betterproto.Message): """ `FieldMask` represents a set of symbolic field paths, for example: - paths: "f.a" - paths: "f.b.d" - - Here `f` represents a field in some root message, `a` and `b` - fields in the message found in `f`, and `d` a field found in the - message in `f.b`. + paths: "f.a" + paths: "f.b.d" - Field masks are used to specify a subset of fields that should be - returned by a get operation or modified by an update operation. - Field masks also have a custom JSON encoding (see below). + Here `f` represents a field in some root message, `a` and `b` + fields in the message found in `f`, and `d` a field found in the + message in `f.b`. - # Field Masks in Projections + Field masks are used to specify a subset of fields that should be + returned by a get operation or modified by an update operation. + Field masks also have a custom JSON encoding (see below). - When used in the context of a projection, a response message or - sub-message is filtered by the API to only contain those fields as - specified in the mask. For example, if the mask in the previous - example is applied to a response message as follows: - - f { - a : 22 - b { - d : 1 - x : 2 - } - y : 13 - } - z: 8 + # Field Masks in Projections - The result will not contain specific values for fields x,y and z - (their value will be set to the default, and omitted in proto text - output): + When used in the context of a projection, a response message or + sub-message is filtered by the API to only contain those fields as + specified in the mask. For example, if the mask in the previous + example is applied to a response message as follows: + f { + a : 22 + b { + d : 1 + x : 2 + } + y : 13 + } + z: 8 + + The result will not contain specific values for fields x,y and z + (their value will be set to the default, and omitted in proto text + output): + + f { + a : 22 + b { + d : 1 + } + } + + A repeated field is not allowed except at the last position of a + paths string. + + If a FieldMask object is not present in a get operation, the + operation applies to all fields (as if a FieldMask of all fields + had been specified). + + Note that a field mask does not necessarily apply to the + top-level response message. In case of a REST get operation, the + field mask applies directly to the response, but in case of a REST + list operation, the mask instead applies to each individual message + in the returned resource list. In case of a REST custom method, + other definitions may be used. Where the mask applies will be + clearly documented together with its declaration in the API. In + any case, the effect on the returned resource/resources is required + behavior for APIs. + + # Field Masks in Update Operations + + A field mask in update operations specifies which fields of the + targeted resource are going to be updated. The API is required + to only change the values of the fields as specified in the mask + and leave the others untouched. If a resource is passed in to + describe the updated values, the API ignores the values of all + fields not covered by the mask. + + If a repeated field is specified for an update operation, new values will + be appended to the existing repeated field in the target resource. Note that + a repeated field is only allowed in the last position of a `paths` string. + + If a sub-message is specified in the last position of the field mask for an + update operation, then new value will be merged into the existing sub-message + in the target resource. + + For example, given the target message: + + f { + b { + d: 1 + x: 2 + } + c: [1] + } - f { - a : 22 - b { - d : 1 - } - } - - A repeated field is not allowed except at the last position of a - paths string. - - If a FieldMask object is not present in a get operation, the - operation applies to all fields (as if a FieldMask of all fields - had been specified). - - Note that a field mask does not necessarily apply to the - top-level response message. In case of a REST get operation, the - field mask applies directly to the response, but in case of a REST - list operation, the mask instead applies to each individual message - in the returned resource list. In case of a REST custom method, - other definitions may be used. Where the mask applies will be - clearly documented together with its declaration in the API. In - any case, the effect on the returned resource/resources is required - behavior for APIs. - - # Field Masks in Update Operations - - A field mask in update operations specifies which fields of the - targeted resource are going to be updated. The API is required - to only change the values of the fields as specified in the mask - and leave the others untouched. If a resource is passed in to - describe the updated values, the API ignores the values of all - fields not covered by the mask. - - If a repeated field is specified for an update operation, new values will - be appended to the existing repeated field in the target resource. Note that - a repeated field is only allowed in the last position of a `paths` string. - - If a sub-message is specified in the last position of the field mask for an - update operation, then new value will be merged into the existing sub-message - in the target resource. - - For example, given the target message: - - f { - b { - d: 1 - x: 2 - } - c: [1] - } - - And an update message: + And an update message: - f { - b { - d: 10 - } - c: [2] - } + f { + b { + d: 10 + } + c: [2] + } - then if the field mask is: + then if the field mask is: - paths: ["f.b", "f.c"] + paths: ["f.b", "f.c"] - then the result will be: + then the result will be: - f { - b { - d: 10 - x: 2 - } - c: [1, 2] - } + f { + b { + d: 10 + x: 2 + } + c: [1, 2] + } - An implementation may provide options to override this default behavior for - repeated and message fields. + An implementation may provide options to override this default behavior for + repeated and message fields. - In order to reset a field's value to the default, the field must - be in the mask and set to the default value in the provided resource. - Hence, in order to reset all fields of a resource, provide a default - instance of the resource and set all fields in the mask, or do - not provide a mask as described below. + In order to reset a field's value to the default, the field must + be in the mask and set to the default value in the provided resource. + Hence, in order to reset all fields of a resource, provide a default + instance of the resource and set all fields in the mask, or do + not provide a mask as described below. - If a field mask is not present on update, the operation applies to - all fields (as if a field mask of all fields has been specified). - Note that in the presence of schema evolution, this may mean that - fields the client does not know and has therefore not filled into - the request will be reset to their default. If this is unwanted - behavior, a specific service may require a client to always specify - a field mask, producing an error if not. + If a field mask is not present on update, the operation applies to + all fields (as if a field mask of all fields has been specified). + Note that in the presence of schema evolution, this may mean that + fields the client does not know and has therefore not filled into + the request will be reset to their default. If this is unwanted + behavior, a specific service may require a client to always specify + a field mask, producing an error if not. - As with get operations, the location of the resource which - describes the updated values in the request message depends on the - operation kind. In any case, the effect of the field mask is - required to be honored by the API. + As with get operations, the location of the resource which + describes the updated values in the request message depends on the + operation kind. In any case, the effect of the field mask is + required to be honored by the API. - ## Considerations for HTTP REST + ## Considerations for HTTP REST - The HTTP kind of an update operation which uses a field mask must - be set to PATCH instead of PUT in order to satisfy HTTP semantics - (PUT must only be used for full updates). + The HTTP kind of an update operation which uses a field mask must + be set to PATCH instead of PUT in order to satisfy HTTP semantics + (PUT must only be used for full updates). - # JSON Encoding of Field Masks + # JSON Encoding of Field Masks - In JSON, a field mask is encoded as a single string where paths are - separated by a comma. Fields name in each path are converted - to/from lower-camel naming conventions. + In JSON, a field mask is encoded as a single string where paths are + separated by a comma. Fields name in each path are converted + to/from lower-camel naming conventions. - As an example, consider the following message declarations: + As an example, consider the following message declarations: - message Profile { - User user = 1; - Photo photo = 2; - } - message User { - string display_name = 1; - string address = 2; - } + message Profile { + User user = 1; + Photo photo = 2; + } + message User { + string display_name = 1; + string address = 2; + } - In proto a field mask for `Profile` may look as such: + In proto a field mask for `Profile` may look as such: - mask { - paths: "user.display_name" - paths: "photo" - } + mask { + paths: "user.display_name" + paths: "photo" + } - In JSON, the same mask is represented as below: + In JSON, the same mask is represented as below: - { - mask: "user.displayName,photo" - } + { + mask: "user.displayName,photo" + } - # Field Masks and Oneof Fields + # Field Masks and Oneof Fields - Field masks treat fields in oneofs just as regular fields. Consider the - following message: + Field masks treat fields in oneofs just as regular fields. Consider the + following message: - message SampleMessage { - oneof test_oneof { - string name = 4; - SubMessage sub_message = 9; - } - } + message SampleMessage { + oneof test_oneof { + string name = 4; + SubMessage sub_message = 9; + } + } - The field mask can be: + The field mask can be: - mask { - paths: "name" - } + mask { + paths: "name" + } - Or: + Or: - mask { - paths: "sub_message" - } + mask { + paths: "sub_message" + } - Note that oneof type names ("test_oneof" in this case) cannot be used in - paths. + Note that oneof type names ("test_oneof" in this case) cannot be used in + paths. - ## Field Mask Verification + ## Field Mask Verification - The implementation of any API method which has a FieldMask type field in the - request should verify the included field paths, and return an - `INVALID_ARGUMENT` error if any path is unmappable. + The implementation of any API method which has a FieldMask type field in the + request should verify the included field paths, and return an + `INVALID_ARGUMENT` error if any path is unmappable. """ - paths: List[str] = betterproto.string_field(1) + paths: List[str] = betterproto.string_field(1, repeated=True) """The set of field mask paths.""" @@ -2225,13 +2255,13 @@ class FieldMask(betterproto.Message): class Struct(betterproto.Message): """ `Struct` represents a structured data value, consisting of fields - which map to dynamically typed values. In some languages, `Struct` - might be supported by a native representation. For example, in - scripting languages like JS a struct is represented as an - object. The details of that representation are described together - with the proto support for the language. + which map to dynamically typed values. In some languages, `Struct` + might be supported by a native representation. For example, in + scripting languages like JS a struct is represented as an + object. The details of that representation are described together + with the proto support for the language. - The JSON representation for `Struct` is JSON object. + The JSON representation for `Struct` is JSON object. """ fields: Dict[str, "Value"] = betterproto.map_field( @@ -2270,11 +2300,11 @@ def to_dict( class Value(betterproto.Message): """ `Value` represents a dynamically typed value which can be either - null, a number, a string, a boolean, a recursive struct value, or a - list of values. A producer of value is expected to set one of these - variants. Absence of any variant indicates an error. + null, a number, a string, a boolean, a recursive struct value, or a + list of values. A producer of value is expected to set one of that + variants, absence of any variant indicates an error. - The JSON representation for `Value` is JSON value. + The JSON representation for `Value` is JSON value. """ null_value: "NullValue" = betterproto.enum_field(1, group="kind") @@ -2301,10 +2331,10 @@ class ListValue(betterproto.Message): """ `ListValue` is a wrapper around a repeated field of values. - The JSON representation for `ListValue` is JSON array. + The JSON representation for `ListValue` is JSON array. """ - values: List["Value"] = betterproto.message_field(1) + values: List["Value"] = betterproto.message_field(1, repeated=True) """Repeated field of dynamically typed values.""" @@ -2312,109 +2342,101 @@ class ListValue(betterproto.Message): class Timestamp(betterproto.Message): """ A Timestamp represents a point in time independent of any time zone or local - calendar, encoded as a count of seconds and fractions of seconds at - nanosecond resolution. The count is relative to an epoch at UTC midnight on - January 1, 1970, in the proleptic Gregorian calendar which extends the - Gregorian calendar backwards to year one. - - All minutes are 60 seconds long. Leap seconds are "smeared" so that no leap - second table is needed for interpretation, using a [24-hour linear - smear](https://developers.google.com/time/smear). - - The range is from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z. By - restricting to that range, we ensure that we can convert to and from [RFC - 3339](https://www.ietf.org/rfc/rfc3339.txt) date strings. - - # Examples + calendar, encoded as a count of seconds and fractions of seconds at + nanosecond resolution. The count is relative to an epoch at UTC midnight on + January 1, 1970, in the proleptic Gregorian calendar which extends the + Gregorian calendar backwards to year one. - Example 1: Compute Timestamp from POSIX `time()`. + All minutes are 60 seconds long. Leap seconds are "smeared" so that no leap + second table is needed for interpretation, using a [24-hour linear + smear](https://developers.google.com/time/smear). - Timestamp timestamp; - timestamp.set_seconds(time(NULL)); - timestamp.set_nanos(0); + The range is from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z. By + restricting to that range, we ensure that we can convert to and from [RFC + 3339](https://www.ietf.org/rfc/rfc3339.txt) date strings. - Example 2: Compute Timestamp from POSIX `gettimeofday()`. + # Examples - struct timeval tv; - gettimeofday(&tv, NULL); + Example 1: Compute Timestamp from POSIX `time()`. - Timestamp timestamp; - timestamp.set_seconds(tv.tv_sec); - timestamp.set_nanos(tv.tv_usec * 1000); + Timestamp timestamp; + timestamp.set_seconds(time(NULL)); + timestamp.set_nanos(0); - Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`. + Example 2: Compute Timestamp from POSIX `gettimeofday()`. - FILETIME ft; - GetSystemTimeAsFileTime(&ft); - UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime; + struct timeval tv; + gettimeofday(&tv, NULL); - // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z - // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z. - Timestamp timestamp; - timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL)); - timestamp.set_nanos((INT32) ((ticks % 10000000) * 100)); + Timestamp timestamp; + timestamp.set_seconds(tv.tv_sec); + timestamp.set_nanos(tv.tv_usec * 1000); - Example 4: Compute Timestamp from Java `System.currentTimeMillis()`. + Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`. - long millis = System.currentTimeMillis(); + FILETIME ft; + GetSystemTimeAsFileTime(&ft); + UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime; - Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000) - .setNanos((int) ((millis % 1000) * 1000000)).build(); + // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z + // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z. + Timestamp timestamp; + timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL)); + timestamp.set_nanos((INT32) ((ticks % 10000000) * 100)); - Example 5: Compute Timestamp from Java `Instant.now()`. + Example 4: Compute Timestamp from Java `System.currentTimeMillis()`. - Instant now = Instant.now(); + long millis = System.currentTimeMillis(); - Timestamp timestamp = - Timestamp.newBuilder().setSeconds(now.getEpochSecond()) - .setNanos(now.getNano()).build(); + Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000) + .setNanos((int) ((millis % 1000) * 1000000)).build(); - Example 6: Compute Timestamp from current time in Python. + Example 5: Compute Timestamp from current time in Python. - timestamp = Timestamp() - timestamp.GetCurrentTime() + timestamp = Timestamp() + timestamp.GetCurrentTime() - # JSON Mapping + # JSON Mapping - In JSON format, the Timestamp type is encoded as a string in the - [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format. That is, the - format is "{year}-{month}-{day}T{hour}:{min}:{sec}[.{frac_sec}]Z" - where {year} is always expressed using four digits while {month}, {day}, - {hour}, {min}, and {sec} are zero-padded to two digits each. The fractional - seconds, which can go up to 9 digits (i.e. up to 1 nanosecond resolution), - are optional. The "Z" suffix indicates the timezone ("UTC"); the timezone - is required. A proto3 JSON serializer should always use UTC (as indicated by - "Z") when printing the Timestamp type and a proto3 JSON parser should be - able to accept both UTC and other timezones (as indicated by an offset). + In JSON format, the Timestamp type is encoded as a string in the + [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format. That is, the + format is "{year}-{month}-{day}T{hour}:{min}:{sec}[.{frac_sec}]Z" + where {year} is always expressed using four digits while {month}, {day}, + {hour}, {min}, and {sec} are zero-padded to two digits each. The fractional + seconds, which can go up to 9 digits (i.e. up to 1 nanosecond resolution), + are optional. The "Z" suffix indicates the timezone ("UTC"); the timezone + is required. A proto3 JSON serializer should always use UTC (as indicated by + "Z") when printing the Timestamp type and a proto3 JSON parser should be + able to accept both UTC and other timezones (as indicated by an offset). - For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past - 01:30 UTC on January 15, 2017. + For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past + 01:30 UTC on January 15, 2017. - In JavaScript, one can convert a Date object to this format using the - standard - [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString) - method. In Python, a standard `datetime.datetime` object can be converted - to this format using - [`strftime`](https://docs.python.org/2/library/time.html#time.strftime) with - the time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one can use - the Joda Time's [`ISODateTimeFormat.dateTime()`]( - http://joda-time.sourceforge.net/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime() - ) to obtain a formatter capable of generating timestamps in this format. + In JavaScript, one can convert a Date object to this format using the + standard + [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString) + method. In Python, a standard `datetime.datetime` object can be converted + to this format using + [`strftime`](https://docs.python.org/2/library/time.html#time.strftime) with + the time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one can use + the Joda Time's [`ISODateTimeFormat.dateTime()`]( + http://www.joda.org/joda-time/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime%2D%2D + ) to obtain a formatter capable of generating timestamps in this format. """ seconds: int = betterproto.int64_field(1) """ Represents seconds of UTC time since Unix epoch - 1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to - 9999-12-31T23:59:59Z inclusive. + 1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to + 9999-12-31T23:59:59Z inclusive. """ nanos: int = betterproto.int32_field(2) """ Non-negative fractions of a second at nanosecond resolution. Negative - second values with fractions must still have non-negative nanos values - that count forward in time. Must be from 0 to 999,999,999 - inclusive. + second values with fractions must still have non-negative nanos values + that count forward in time. Must be from 0 to 999,999,999 + inclusive. """ @@ -2423,7 +2445,7 @@ class DoubleValue(betterproto.Message): """ Wrapper message for `double`. - The JSON representation for `DoubleValue` is JSON number. + The JSON representation for `DoubleValue` is JSON number. """ value: float = betterproto.double_field(1) @@ -2435,7 +2457,7 @@ class FloatValue(betterproto.Message): """ Wrapper message for `float`. - The JSON representation for `FloatValue` is JSON number. + The JSON representation for `FloatValue` is JSON number. """ value: float = betterproto.float_field(1) @@ -2447,7 +2469,7 @@ class Int64Value(betterproto.Message): """ Wrapper message for `int64`. - The JSON representation for `Int64Value` is JSON string. + The JSON representation for `Int64Value` is JSON string. """ value: int = betterproto.int64_field(1) @@ -2459,7 +2481,7 @@ class UInt64Value(betterproto.Message): """ Wrapper message for `uint64`. - The JSON representation for `UInt64Value` is JSON string. + The JSON representation for `UInt64Value` is JSON string. """ value: int = betterproto.uint64_field(1) @@ -2471,7 +2493,7 @@ class Int32Value(betterproto.Message): """ Wrapper message for `int32`. - The JSON representation for `Int32Value` is JSON number. + The JSON representation for `Int32Value` is JSON number. """ value: int = betterproto.int32_field(1) @@ -2483,7 +2505,7 @@ class UInt32Value(betterproto.Message): """ Wrapper message for `uint32`. - The JSON representation for `UInt32Value` is JSON number. + The JSON representation for `UInt32Value` is JSON number. """ value: int = betterproto.uint32_field(1) @@ -2495,7 +2517,7 @@ class BoolValue(betterproto.Message): """ Wrapper message for `bool`. - The JSON representation for `BoolValue` is JSON `true` and `false`. + The JSON representation for `BoolValue` is JSON `true` and `false`. """ value: bool = betterproto.bool_field(1) @@ -2507,7 +2529,7 @@ class StringValue(betterproto.Message): """ Wrapper message for `string`. - The JSON representation for `StringValue` is JSON string. + The JSON representation for `StringValue` is JSON string. """ value: str = betterproto.string_field(1) @@ -2519,7 +2541,7 @@ class BytesValue(betterproto.Message): """ Wrapper message for `bytes`. - The JSON representation for `BytesValue` is JSON string. + The JSON representation for `BytesValue` is JSON string. """ value: bytes = betterproto.bytes_field(1) From 7138ff8b979dd3466352d0310c46313fa1835ec7 Mon Sep 17 00:00:00 2001 From: Adrien Vannson Date: Mon, 11 Nov 2024 14:22:36 +0100 Subject: [PATCH 03/37] Remove placeholders --- src/betterproto/__init__.py | 159 ++++++++++++------------------------ 1 file changed, 50 insertions(+), 109 deletions(-) diff --git a/src/betterproto/__init__.py b/src/betterproto/__init__.py index cb03f4390..729d94734 100644 --- a/src/betterproto/__init__.py +++ b/src/betterproto/__init__.py @@ -169,24 +169,6 @@ class Casing(builtin_enum.Enum): SNAKE = snake_case #: A snake_case sterilization function. -class Placeholder: - __slots__ = () - - def __repr__(self) -> str: - return "" - - def __copy__(self) -> Self: - return self - - def __deepcopy__(self, _) -> Self: - return self - - -# We can't simply use object() here because pydantic automatically performs deep-copy of mutable default values -# See #606 -PLACEHOLDER: Any = Placeholder() - - @dataclasses.dataclass(frozen=True) class FieldMetadata: """Stores internal metadata used for parsing & serialization.""" @@ -213,6 +195,7 @@ def get(field: dataclasses.Field) -> "FieldMetadata": def dataclass_field( number: int, proto_type: str, + default_factory: Callable[[], Any], *, map_types: Optional[Tuple[str, str]] = None, group: Optional[str] = None, @@ -221,8 +204,15 @@ def dataclass_field( repeated: bool = False, ) -> dataclasses.Field: """Creates a dataclass field with attached protobuf metadata.""" + if optional: + def default_factory(): + return None + elif repeated: + def default_factory(): + return [] + return dataclasses.field( - default=None if optional else PLACEHOLDER, # type: ignore + default_factory=default_factory, metadata={ "betterproto": FieldMetadata( number, proto_type, map_types, group, wraps, optional @@ -236,96 +226,96 @@ def dataclass_field( # out at runtime. The generated dataclass variables are still typed correctly. -def enum_field(number: int, group: Optional[str] = None, optional: bool = False, repeated: bool = False,) -> Any: - return dataclass_field(number, TYPE_ENUM, group=group, optional=optional, repeated=repeated) +def enum_field(number: int, group: Optional[str] = None, optional: bool = False, repeated: bool = False) -> Any: + return dataclass_field(number, TYPE_ENUM, lambda: 0, optional=optional, repeated=repeated) -def bool_field(number: int, group: Optional[str] = None, optional: bool = False, repeated: bool = False,) -> Any: - return dataclass_field(number, TYPE_BOOL, group=group, optional=optional, repeated=repeated) +def bool_field(number: int, group: Optional[str] = None, optional: bool = False, repeated: bool = False) -> Any: + return dataclass_field(number, TYPE_BOOL, lambda: False, group=group, optional=optional, repeated=repeated) def int32_field( number: int, group: Optional[str] = None, optional: bool = False, repeated: bool = False, ) -> Any: - return dataclass_field(number, TYPE_INT32, group=group, optional=optional, repeated=repeated) + return dataclass_field(number, TYPE_INT32, lambda: 0, group=group, optional=optional, repeated=repeated) def int64_field( number: int, group: Optional[str] = None, optional: bool = False, repeated: bool = False, ) -> Any: - return dataclass_field(number, TYPE_INT64, group=group, optional=optional, repeated=repeated) + return dataclass_field(number, TYPE_INT64, lambda: 0, group=group, optional=optional, repeated=repeated) def uint32_field( number: int, group: Optional[str] = None, optional: bool = False, repeated: bool = False, ) -> Any: - return dataclass_field(number, TYPE_UINT32, group=group, optional=optional, repeated=repeated) + return dataclass_field(number, TYPE_UINT32, lambda: 0, group=group, optional=optional, repeated=repeated) def uint64_field( number: int, group: Optional[str] = None, optional: bool = False, repeated: bool = False, ) -> Any: - return dataclass_field(number, TYPE_UINT64, group=group, optional=optional, repeated=repeated) + return dataclass_field(number, TYPE_UINT64, lambda: 0, group=group, optional=optional, repeated=repeated) def sint32_field( number: int, group: Optional[str] = None, optional: bool = False, repeated: bool = False, ) -> Any: - return dataclass_field(number, TYPE_SINT32, group=group, optional=optional, repeated=repeated) + return dataclass_field(number, TYPE_SINT32, lambda: 0, group=group, optional=optional, repeated=repeated) def sint64_field( number: int, group: Optional[str] = None, optional: bool = False, repeated: bool = False, ) -> Any: - return dataclass_field(number, TYPE_SINT64, group=group, optional=optional, repeated=repeated) + return dataclass_field(number, TYPE_SINT64, lambda: 0, group=group, optional=optional, repeated=repeated) def float_field( number: int, group: Optional[str] = None, optional: bool = False, repeated: bool = False, ) -> Any: - return dataclass_field(number, TYPE_FLOAT, group=group, optional=optional, repeated=repeated) + return dataclass_field(number, TYPE_FLOAT, lambda: 0., group=group, optional=optional, repeated=repeated) def double_field( number: int, group: Optional[str] = None, optional: bool = False, repeated: bool = False, ) -> Any: - return dataclass_field(number, TYPE_DOUBLE, group=group, optional=optional, repeated=repeated) + return dataclass_field(number, TYPE_DOUBLE, lambda: 0., group=group, optional=optional, repeated=repeated) def fixed32_field( number: int, group: Optional[str] = None, optional: bool = False, repeated: bool = False, ) -> Any: - return dataclass_field(number, TYPE_FIXED32, group=group, optional=optional, repeated=repeated) + return dataclass_field(number, TYPE_FIXED32, lambda: 0., group=group, optional=optional, repeated=repeated) def fixed64_field( number: int, group: Optional[str] = None, optional: bool = False, repeated: bool = False, ) -> Any: - return dataclass_field(number, TYPE_FIXED64, group=group, optional=optional, repeated=repeated) + return dataclass_field(number, TYPE_FIXED64, lambda: 0., group=group, optional=optional, repeated=repeated) def sfixed32_field( number: int, group: Optional[str] = None, optional: bool = False, repeated: bool = False, ) -> Any: - return dataclass_field(number, TYPE_SFIXED32, group=group, optional=optional, repeated=repeated) + return dataclass_field(number, TYPE_SFIXED32, lambda: 0., group=group, optional=optional, repeated=repeated) def sfixed64_field( number: int, group: Optional[str] = None, optional: bool = False, repeated: bool = False, ) -> Any: - return dataclass_field(number, TYPE_SFIXED64, group=group, optional=optional, repeated=repeated) + return dataclass_field(number, TYPE_SFIXED64, lambda: 0., group=group, optional=optional, repeated=repeated) def string_field( number: int, group: Optional[str] = None, optional: bool = False, repeated: bool = False, ) -> Any: - return dataclass_field(number, TYPE_STRING, group=group, optional=optional, repeated=repeated) + return dataclass_field(number, TYPE_STRING, lambda: "", group=group, optional=optional, repeated=repeated) def bytes_field( number: int, group: Optional[str] = None, optional: bool = False, repeated: bool = False, ) -> Any: - return dataclass_field(number, TYPE_BYTES, group=group, optional=optional, repeated=repeated) + return dataclass_field(number, TYPE_BYTES, lambda: b"", group=group, optional=optional, repeated=repeated) def message_field( @@ -336,7 +326,7 @@ def message_field( repeated: bool = False, ) -> Any: return dataclass_field( - number, TYPE_MESSAGE, group=group, wraps=wraps, optional=optional + number, TYPE_MESSAGE, lambda: None, group=group, wraps=wraps, optional=optional, repeated=repeated ) @@ -344,7 +334,7 @@ def map_field( number: int, key_type: str, value_type: str, group: Optional[str] = None ) -> Any: return dataclass_field( - number, TYPE_MAP, map_types=(key_type, value_type), group=group + number, TYPE_MAP, lambda: dict(), map_types=(key_type, value_type), group=group ) @@ -729,8 +719,8 @@ def _get_cls_by_field( field_cls[field.name] = dataclasses.make_dataclass( "Entry", [ - ("key", kt, dataclass_field(1, meta.map_types[0])), - ("value", vt, dataclass_field(2, meta.map_types[1])), + ("key", kt, dataclass_field(1, meta.map_types[0], default_factory=lambda: kt())), + ("value", vt, dataclass_field(2, meta.map_types[1], default_factory=lambda: vt())), ], bases=(Message,), ) @@ -764,8 +754,8 @@ class Message(ABC): _betterproto_meta: ClassVar[ProtoClassMetadata] def __post_init__(self) -> None: - # Keep track of whether every field was default - all_sentinel = True + # # Keep track of whether every field was default + # all_sentinel = True # Set current field of each group after `__init__` has already been run. group_current: Dict[str, Optional[str]] = {} @@ -773,17 +763,18 @@ def __post_init__(self) -> None: if meta.group: group_current.setdefault(meta.group) - value = self.__raw_get(field_name) - if value is not PLACEHOLDER and not (meta.optional and value is None): - # Found a non-sentinel value - all_sentinel = False + # value = self.__raw_get(field_name) + # if value is not PLACEHOLDER and not (meta.optional and value is None): + # # Found a non-sentinel value + # all_sentinel = False - if meta.group: - # This was set, so make it the selected value of the one-of. - group_current[meta.group] = field_name + # if meta.group: + # # This was set, so make it the selected value of the one-of. + # group_current[meta.group] = field_name # Now that all the defaults are set, reset it! - self.__dict__["_serialized_on_wire"] = not all_sentinel + # self.__dict__["_serialized_on_wire"] = not all_sentinel + self.__dict__["_serialized_on_wire"] = False self.__dict__["_unknown_fields"] = b"" self.__dict__["_group_current"] = group_current @@ -797,12 +788,6 @@ def __eq__(self, other) -> bool: for field_name in self._betterproto.meta_by_field_name: self_val = self.__raw_get(field_name) other_val = other.__raw_get(field_name) - if self_val is PLACEHOLDER: - if other_val is PLACEHOLDER: - continue - self_val = self._get_field_default(field_name) - elif other_val is PLACEHOLDER: - other_val = other._get_field_default(field_name) if self_val != other_val: # We consider two nan values to be the same for the @@ -825,48 +810,12 @@ def __repr__(self) -> str: f"{field_name}={value!r}" for field_name in self._betterproto.sorted_field_names for value in (self.__raw_get(field_name),) - if value is not PLACEHOLDER ] return f"{self.__class__.__name__}({', '.join(parts)})" - def __rich_repr__(self) -> Iterable[Tuple[str, Any, Any]]: - for field_name in self._betterproto.sorted_field_names: - yield field_name, self.__raw_get(field_name), PLACEHOLDER - - if not TYPE_CHECKING: - - def __getattribute__(self, name: str) -> Any: - """ - Lazily initialize default values to avoid infinite recursion for recursive - message types. - Raise :class:`AttributeError` on attempts to access unset ``oneof`` fields. - """ - try: - group_current = super().__getattribute__("_group_current") - except AttributeError: - pass - else: - if name not in {"__class__", "_betterproto"}: - group = self._betterproto.oneof_group_by_field.get(name) - if group is not None and group_current[group] != name: - if sys.version_info < (3, 10): - raise AttributeError( - f"{group!r} is set to {group_current[group]!r}, not {name!r}" - ) - else: - raise AttributeError( - f"{group!r} is set to {group_current[group]!r}, not {name!r}", - name=name, - obj=self, - ) - - value = super().__getattribute__(name) - if value is not PLACEHOLDER: - return value - - value = self._get_field_default(name) - super().__setattr__(name, value) - return value + # def __rich_repr__(self) -> Iterable[Tuple[str, Any, Any]]: + # for field_name in self._betterproto.sorted_field_names: + # yield field_name, self.__raw_get(field_name), PLACEHOLDER def __setattr__(self, attr: str, value: Any) -> None: if ( @@ -887,15 +836,14 @@ def __setattr__(self, attr: str, value: Any) -> None: if field.name == attr: self._group_current[group] = field.name else: - super().__setattr__(field.name, PLACEHOLDER) + super().__setattr__(field.name, None) super().__setattr__(attr, value) def __bool__(self) -> bool: """True if the Message has any fields with non-default values.""" return any( - self.__raw_get(field_name) - not in (PLACEHOLDER, self._get_field_default(field_name)) + self.__raw_get(field_name) != self._get_field_default(field_name) for field_name in self._betterproto.meta_by_field_name ) @@ -903,16 +851,14 @@ def __deepcopy__(self: T, _: Any = {}) -> T: kwargs = {} for name in self._betterproto.sorted_field_names: value = self.__raw_get(name) - if value is not PLACEHOLDER: - kwargs[name] = deepcopy(value) + kwargs[name] = deepcopy(value) return self.__class__(**kwargs) # type: ignore def __copy__(self: T, _: Any = {}) -> T: kwargs = {} for name in self._betterproto.sorted_field_names: value = self.__raw_get(name) - if value is not PLACEHOLDER: - kwargs[name] = value + kwargs[name] = value return self.__class__(**kwargs) # type: ignore @classproperty @@ -1853,12 +1799,7 @@ def is_set(self, name: str) -> bool: :class:`bool` `True` if field has been set, otherwise `False`. """ - default = ( - PLACEHOLDER - if not self._betterproto.meta_by_field_name[name].optional - else None - ) - return self.__raw_get(name) is not default + return self.__raw_get(name) is not self._get_field_default(name) @classmethod def _validate_field_groups(cls, values): From f8e7e541a4bb330599a998ab515909033d1e3968 Mon Sep 17 00:00:00 2001 From: Adrien Vannson Date: Mon, 11 Nov 2024 14:40:08 +0100 Subject: [PATCH 04/37] Fix groups in post_init --- src/betterproto/__init__.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/betterproto/__init__.py b/src/betterproto/__init__.py index 729d94734..20df1314f 100644 --- a/src/betterproto/__init__.py +++ b/src/betterproto/__init__.py @@ -763,7 +763,10 @@ def __post_init__(self) -> None: if meta.group: group_current.setdefault(meta.group) - # value = self.__raw_get(field_name) + value = self.__raw_get(field_name) + if value is not None: + group_current[meta.group] = field_name + # if value is not PLACEHOLDER and not (meta.optional and value is None): # # Found a non-sentinel value # all_sentinel = False From 2324c06563f89fc95df2b894d8f91375d1a82ae6 Mon Sep 17 00:00:00 2001 From: Adrien Vannson Date: Mon, 11 Nov 2024 15:04:33 +0100 Subject: [PATCH 05/37] Fix test --- tests/inputs/oneof_enum/test_oneof_enum.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/inputs/oneof_enum/test_oneof_enum.py b/tests/inputs/oneof_enum/test_oneof_enum.py index e54fa3859..854ac3fbe 100644 --- a/tests/inputs/oneof_enum/test_oneof_enum.py +++ b/tests/inputs/oneof_enum/test_oneof_enum.py @@ -42,6 +42,5 @@ def test_which_one_of_returns_second_field_when_set(): message = Test() message.from_json(get_test_case_json_data("oneof_enum")[0].json) assert message.move == Move(x=2, y=3) - assert not hasattr(message, "signal") - assert object.__getattribute__(message, "signal") == betterproto.PLACEHOLDER + assert message.signal == 0 assert betterproto.which_one_of(message, "action") == ("move", Move(x=2, y=3)) From 3574d6bdd0ded7bfacb4456eec9584eb1a3434bf Mon Sep 17 00:00:00 2001 From: Adrien Vannson Date: Mon, 11 Nov 2024 15:40:13 +0100 Subject: [PATCH 06/37] Fix bugs --- src/betterproto/__init__.py | 5 ++++- tests/inputs/oneof_enum/test_oneof_enum.py | 11 ++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/betterproto/__init__.py b/src/betterproto/__init__.py index 20df1314f..96962175b 100644 --- a/src/betterproto/__init__.py +++ b/src/betterproto/__init__.py @@ -227,7 +227,7 @@ def default_factory(): def enum_field(number: int, group: Optional[str] = None, optional: bool = False, repeated: bool = False) -> Any: - return dataclass_field(number, TYPE_ENUM, lambda: 0, optional=optional, repeated=repeated) + return dataclass_field(number, TYPE_ENUM, lambda: 0, group=group, optional=optional, repeated=repeated) def bool_field(number: int, group: Optional[str] = None, optional: bool = False, repeated: bool = False) -> Any: @@ -1160,6 +1160,9 @@ def _get_field_default_gen(cls, field: dataclasses.Field) -> Any: if t is datetime: # Offsets are relative to 1970-01-01T00:00:00Z return datetime_default_gen + # In proto 3, message fields are always optional + if issubclass(t, Message): + return type(None) # This is either a primitive scalar or another message type. Calling # it should result in its zero value. return t diff --git a/tests/inputs/oneof_enum/test_oneof_enum.py b/tests/inputs/oneof_enum/test_oneof_enum.py index 854ac3fbe..8dda1a979 100644 --- a/tests/inputs/oneof_enum/test_oneof_enum.py +++ b/tests/inputs/oneof_enum/test_oneof_enum.py @@ -1,5 +1,3 @@ -import pytest - import betterproto from tests.output_betterproto.oneof_enum import ( Move, @@ -18,8 +16,7 @@ def test_which_one_of_returns_enum_with_default_value(): get_test_case_json_data("oneof_enum", "oneof_enum-enum-0.json")[0].json ) - assert not hasattr(message, "move") - assert object.__getattribute__(message, "move") == betterproto.PLACEHOLDER + assert message.move is None assert message.signal == Signal.PASS assert betterproto.which_one_of(message, "action") == ("signal", Signal.PASS) @@ -32,8 +29,8 @@ def test_which_one_of_returns_enum_with_non_default_value(): message.from_json( get_test_case_json_data("oneof_enum", "oneof_enum-enum-1.json")[0].json ) - assert not hasattr(message, "move") - assert object.__getattribute__(message, "move") == betterproto.PLACEHOLDER + + assert message.move is None assert message.signal == Signal.RESIGN assert betterproto.which_one_of(message, "action") == ("signal", Signal.RESIGN) @@ -42,5 +39,5 @@ def test_which_one_of_returns_second_field_when_set(): message = Test() message.from_json(get_test_case_json_data("oneof_enum")[0].json) assert message.move == Move(x=2, y=3) - assert message.signal == 0 + assert message.signal is None assert betterproto.which_one_of(message, "action") == ("move", Move(x=2, y=3)) From 8fdea02fb959138ce6fad87c9bccf842f7bf3dff Mon Sep 17 00:00:00 2001 From: Adrien Vannson Date: Mon, 11 Nov 2024 15:43:40 +0100 Subject: [PATCH 07/37] Fix test --- tests/test_features.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/test_features.py b/tests/test_features.py index 193e6b250..31558c145 100644 --- a/tests/test_features.py +++ b/tests/test_features.py @@ -34,11 +34,10 @@ class Bar(betterproto.Message): class Foo(betterproto.Message): bar: Bar = betterproto.message_field(1) - # Unset by default foo = Foo() - assert betterproto.serialized_on_wire(foo.bar) is False # Serialized after setting something + foo.bar = Bar() foo.bar.baz = 1 assert betterproto.serialized_on_wire(foo.bar) is True From fa000bdbb2a83399f10e6be4bfa0f42602fdf88c Mon Sep 17 00:00:00 2001 From: Adrien Vannson Date: Mon, 11 Nov 2024 16:49:45 +0100 Subject: [PATCH 08/37] Right type for default values of enum fields --- src/betterproto/__init__.py | 4 +- .../lib/pydantic/google/protobuf/__init__.py | 56 +++++++++---------- .../lib/std/google/protobuf/__init__.py | 26 ++++----- tests/test_features.py | 2 +- 4 files changed, 44 insertions(+), 44 deletions(-) diff --git a/src/betterproto/__init__.py b/src/betterproto/__init__.py index 96962175b..bd7e926c4 100644 --- a/src/betterproto/__init__.py +++ b/src/betterproto/__init__.py @@ -226,8 +226,8 @@ def default_factory(): # out at runtime. The generated dataclass variables are still typed correctly. -def enum_field(number: int, group: Optional[str] = None, optional: bool = False, repeated: bool = False) -> Any: - return dataclass_field(number, TYPE_ENUM, lambda: 0, group=group, optional=optional, repeated=repeated) +def enum_field(number: int, enum_default_value: Callable[[], Enum], group: Optional[str] = None, optional: bool = False, repeated: bool = False) -> Any: + return dataclass_field(number, TYPE_ENUM, enum_default_value, group=group, optional=optional, repeated=repeated) def bool_field(number: int, group: Optional[str] = None, optional: bool = False, repeated: bool = False) -> Any: diff --git a/src/betterproto/lib/pydantic/google/protobuf/__init__.py b/src/betterproto/lib/pydantic/google/protobuf/__init__.py index c6b824d2f..4e55e1d33 100644 --- a/src/betterproto/lib/pydantic/google/protobuf/__init__.py +++ b/src/betterproto/lib/pydantic/google/protobuf/__init__.py @@ -663,7 +663,7 @@ class Type(betterproto.Message): source_context: "SourceContext" = betterproto.message_field(5) """The source context.""" - syntax: "Syntax" = betterproto.enum_field(6) + syntax: "Syntax" = betterproto.enum_field(6, enum_default_value=lambda: Syntax.try_value(0)) """The source syntax.""" edition: str = betterproto.string_field(7) @@ -676,10 +676,10 @@ class Type(betterproto.Message): class Field(betterproto.Message): """A single field of a message type.""" - kind: "FieldKind" = betterproto.enum_field(1) + kind: "FieldKind" = betterproto.enum_field(1, enum_default_value=lambda: FieldKind.try_value(0)) """The field type.""" - cardinality: "FieldCardinality" = betterproto.enum_field(2) + cardinality: "FieldCardinality" = betterproto.enum_field(2, enum_default_value=lambda: FieldCardinality.try_value(0)) """The field cardinality.""" number: int = betterproto.int32_field(3) @@ -733,7 +733,7 @@ class Enum(betterproto.Message): source_context: "SourceContext" = betterproto.message_field(4) """The source context.""" - syntax: "Syntax" = betterproto.enum_field(5) + syntax: "Syntax" = betterproto.enum_field(5, enum_default_value=lambda: Syntax.try_value(0)) """The source syntax.""" edition: str = betterproto.string_field(6) @@ -838,7 +838,7 @@ class Api(betterproto.Message): mixins: List["Mixin"] = betterproto.message_field(6) """Included interfaces. See [Mixin][].""" - syntax: "Syntax" = betterproto.enum_field(7) + syntax: "Syntax" = betterproto.enum_field(7, enum_default_value=lambda: Syntax.try_value(0)) """The source syntax of the service.""" @@ -864,7 +864,7 @@ class Method(betterproto.Message): options: List["Option"] = betterproto.message_field(6) """Any metadata attached to the method.""" - syntax: "Syntax" = betterproto.enum_field(7) + syntax: "Syntax" = betterproto.enum_field(7, enum_default_value=lambda: Syntax.try_value(0)) """The source syntax of this method.""" @@ -1012,7 +1012,7 @@ class FileDescriptorProto(betterproto.Message): If `edition` is present, this value must be "editions". """ - edition: "Edition" = betterproto.enum_field(14) + edition: "Edition" = betterproto.enum_field(14, enum_default_value=lambda: Edition.try_value(0)) """The edition of the proto file.""" @@ -1072,7 +1072,7 @@ class ExtensionRangeOptions(betterproto.Message): features: "FeatureSet" = betterproto.message_field(50) """Any features defined in the specific edition.""" - verification: "ExtensionRangeOptionsVerificationState" = betterproto.enum_field(3) + verification: "ExtensionRangeOptionsVerificationState" = betterproto.enum_field(3, enum_default_value=lambda: ExtensionRangeOptionsVerificationState.try_value(0)) """ The verification state of the range. TODO: flip the default to DECLARATION once all empty ranges @@ -1118,8 +1118,8 @@ class FieldDescriptorProto(betterproto.Message): name: str = betterproto.string_field(1) number: int = betterproto.int32_field(3) - label: "FieldDescriptorProtoLabel" = betterproto.enum_field(4) - type: "FieldDescriptorProtoType" = betterproto.enum_field(5) + label: "FieldDescriptorProtoLabel" = betterproto.enum_field(4, enum_default_value=lambda: FieldDescriptorProtoLabel.try_value(0)) + type: "FieldDescriptorProtoType" = betterproto.enum_field(5, enum_default_value=lambda: FieldDescriptorProtoType.try_value(0)) """ If type_name is set, this need not be set. If both this and type_name are set, this must be one of TYPE_ENUM, TYPE_MESSAGE or TYPE_GROUP. @@ -1315,7 +1315,7 @@ class FileOptions(betterproto.Message): This option has no effect on when used with the lite runtime. """ - optimize_for: "FileOptionsOptimizeMode" = betterproto.enum_field(9) + optimize_for: "FileOptionsOptimizeMode" = betterproto.enum_field(9, enum_default_value=lambda: FileOptionsOptimizeMode.try_value(0)) go_package: str = betterproto.string_field(11) """ Sets the Go package where structs generated from this .proto will be @@ -1512,7 +1512,7 @@ def __post_init__(self) -> None: @dataclass(eq=False, repr=False) class FieldOptions(betterproto.Message): - ctype: "FieldOptionsCType" = betterproto.enum_field(1) + ctype: "FieldOptionsCType" = betterproto.enum_field(1, enum_default_value=lambda: FieldOptionsCType.try_value(0)) """ The ctype option instructs the C++ code generator to use a different representation of the field than it normally would. See the specific @@ -1533,7 +1533,7 @@ class FieldOptions(betterproto.Message): the behavior. """ - jstype: "FieldOptionsJsType" = betterproto.enum_field(6) + jstype: "FieldOptionsJsType" = betterproto.enum_field(6, enum_default_value=lambda: FieldOptionsJsType.try_value(0)) """ The jstype option determines the JavaScript type used for values of the field. The option is permitted only for 64 bit integral and fixed types @@ -1598,8 +1598,8 @@ class FieldOptions(betterproto.Message): formats, e.g. when the field contains sensitive credentials. """ - retention: "FieldOptionsOptionRetention" = betterproto.enum_field(17) - targets: List["FieldOptionsOptionTargetType"] = betterproto.enum_field(19) + retention: "FieldOptionsOptionRetention" = betterproto.enum_field(17, enum_default_value=lambda: FieldOptionsOptionRetention.try_value(0)) + targets: List["FieldOptionsOptionTargetType"] = betterproto.enum_field(19, enum_default_value=lambda: FieldOptionsOptionTargetType.try_value(0)) edition_defaults: List["FieldOptionsEditionDefault"] = betterproto.message_field(20) features: "FeatureSet" = betterproto.message_field(21) """Any features defined in the specific edition.""" @@ -1610,7 +1610,7 @@ class FieldOptions(betterproto.Message): @dataclass(eq=False, repr=False) class FieldOptionsEditionDefault(betterproto.Message): - edition: "Edition" = betterproto.enum_field(3) + edition: "Edition" = betterproto.enum_field(3, enum_default_value=lambda: Edition.try_value(0)) value: str = betterproto.string_field(2) @@ -1715,7 +1715,7 @@ class MethodOptions(betterproto.Message): this is a formalization for deprecating methods. """ - idempotency_level: "MethodOptionsIdempotencyLevel" = betterproto.enum_field(34) + idempotency_level: "MethodOptionsIdempotencyLevel" = betterproto.enum_field(34, enum_default_value=lambda: MethodOptionsIdempotencyLevel.try_value(0)) features: "FeatureSet" = betterproto.message_field(35) """Any features defined in the specific edition.""" @@ -1773,14 +1773,14 @@ class FeatureSet(betterproto.Message): conflict here. """ - field_presence: "FeatureSetFieldPresence" = betterproto.enum_field(1) - enum_type: "FeatureSetEnumType" = betterproto.enum_field(2) + field_presence: "FeatureSetFieldPresence" = betterproto.enum_field(1, enum_default_value=lambda: FeatureSetFieldPresence.try_value(0)) + enum_type: "FeatureSetEnumType" = betterproto.enum_field(2, enum_default_value=lambda: FeatureSetEnumType.try_value(0)) repeated_field_encoding: "FeatureSetRepeatedFieldEncoding" = betterproto.enum_field( - 3 + 3, enum_default_value=lambda: FeatureSetRepeatedFieldEncoding.try_value(0) ) - utf8_validation: "FeatureSetUtf8Validation" = betterproto.enum_field(4) - message_encoding: "FeatureSetMessageEncoding" = betterproto.enum_field(5) - json_format: "FeatureSetJsonFormat" = betterproto.enum_field(6) + utf8_validation: "FeatureSetUtf8Validation" = betterproto.enum_field(4, enum_default_value=lambda: FeatureSetUtf8Validation.try_value(0)) + message_encoding: "FeatureSetMessageEncoding" = betterproto.enum_field(5, enum_default_value=lambda: FeatureSetMessageEncoding.try_value(0)) + json_format: "FeatureSetJsonFormat" = betterproto.enum_field(6, enum_default_value=lambda: FeatureSetJsonFormat.try_value(0)) @dataclass(eq=False, repr=False) @@ -1795,13 +1795,13 @@ class FeatureSetDefaults(betterproto.Message): defaults: List[ "FeatureSetDefaultsFeatureSetEditionDefault" ] = betterproto.message_field(1) - minimum_edition: "Edition" = betterproto.enum_field(4) + minimum_edition: "Edition" = betterproto.enum_field(4, enum_default_value=lambda: Edition.try_value(0)) """ The minimum supported edition (inclusive) when this was constructed. Editions before this will not have defaults. """ - maximum_edition: "Edition" = betterproto.enum_field(5) + maximum_edition: "Edition" = betterproto.enum_field(5, enum_default_value=lambda: Edition.try_value(0)) """ The maximum known edition (inclusive) when this was constructed. Editions after this will not have reliable defaults. @@ -1817,7 +1817,7 @@ class FeatureSetDefaultsFeatureSetEditionDefault(betterproto.Message): be used. This field must be in strict ascending order by edition. """ - edition: "Edition" = betterproto.enum_field(3) + edition: "Edition" = betterproto.enum_field(3, enum_default_value=lambda: Edition.try_value(0)) features: "FeatureSet" = betterproto.message_field(2) @@ -2008,7 +2008,7 @@ class GeneratedCodeInfoAnnotation(betterproto.Message): the last relevant byte (so the length of the text = end - begin). """ - semantic: "GeneratedCodeInfoAnnotationSemantic" = betterproto.enum_field(5) + semantic: "GeneratedCodeInfoAnnotationSemantic" = betterproto.enum_field(5, enum_default_value=lambda: GeneratedCodeInfoAnnotationSemantic.try_value(0)) @dataclass(eq=False, repr=False) @@ -2372,7 +2372,7 @@ class Value(betterproto.Message): """ null_value: Optional["NullValue"] = betterproto.enum_field( - 1, optional=True, group="kind" + 1, enum_default_value=lambda: NullValue.try_value(0), optional=True, group="kind" ) """Represents a null value.""" diff --git a/src/betterproto/lib/std/google/protobuf/__init__.py b/src/betterproto/lib/std/google/protobuf/__init__.py index bb34c611b..1d0832b03 100644 --- a/src/betterproto/lib/std/google/protobuf/__init__.py +++ b/src/betterproto/lib/std/google/protobuf/__init__.py @@ -510,7 +510,7 @@ class Type(betterproto.Message): source_context: "SourceContext" = betterproto.message_field(5) """The source context.""" - syntax: "Syntax" = betterproto.enum_field(6) + syntax: "Syntax" = betterproto.enum_field(6, enum_default_value=lambda: Syntax.try_value(0)) """The source syntax.""" @@ -518,10 +518,10 @@ class Type(betterproto.Message): class Field(betterproto.Message): """A single field of a message type.""" - kind: "FieldKind" = betterproto.enum_field(1) + kind: "FieldKind" = betterproto.enum_field(1, enum_default_value=lambda: FieldKind.try_value(0)) """The field type.""" - cardinality: "FieldCardinality" = betterproto.enum_field(2) + cardinality: "FieldCardinality" = betterproto.enum_field(2, enum_default_value=lambda: FieldCardinality.try_value(0)) """The field cardinality.""" number: int = betterproto.int32_field(3) @@ -575,7 +575,7 @@ class Enum(betterproto.Message): source_context: "SourceContext" = betterproto.message_field(4) """The source context.""" - syntax: "Syntax" = betterproto.enum_field(5) + syntax: "Syntax" = betterproto.enum_field(5, enum_default_value=lambda: Syntax.try_value(0)) """The source syntax.""" @@ -675,7 +675,7 @@ class Api(betterproto.Message): mixins: List["Mixin"] = betterproto.message_field(6, repeated=True) """Included interfaces. See [Mixin][].""" - syntax: "Syntax" = betterproto.enum_field(7) + syntax: "Syntax" = betterproto.enum_field(7, enum_default_value=lambda: Syntax.try_value(0)) """The source syntax of the service.""" @@ -701,7 +701,7 @@ class Method(betterproto.Message): options: List["Option"] = betterproto.message_field(6, repeated=True) """Any metadata attached to the method.""" - syntax: "Syntax" = betterproto.enum_field(7) + syntax: "Syntax" = betterproto.enum_field(7, enum_default_value=lambda: Syntax.try_value(0)) """The source syntax of this method.""" @@ -994,12 +994,12 @@ class FieldDescriptorProto(betterproto.Message): """ - label: "FieldDescriptorProtoLabel" = betterproto.enum_field(4) + label: "FieldDescriptorProtoLabel" = betterproto.enum_field(4, enum_default_value=lambda: FieldDescriptorProtoLabel.try_value(0)) """ """ - type: "FieldDescriptorProtoType" = betterproto.enum_field(5) + type: "FieldDescriptorProtoType" = betterproto.enum_field(5, enum_default_value=lambda: FieldDescriptorProtoType.try_value(0)) """ If type_name is set, this need not be set. If both this and type_name are set, this must be one of TYPE_ENUM, TYPE_MESSAGE or TYPE_GROUP. @@ -1292,7 +1292,7 @@ class FileOptions(betterproto.Message): This option has no effect on when used with the lite runtime. """ - optimize_for: "FileOptionsOptimizeMode" = betterproto.enum_field(9) + optimize_for: "FileOptionsOptimizeMode" = betterproto.enum_field(9, enum_default_value=lambda: FileOptionsOptimizeMode.try_value(0)) """ """ @@ -1486,7 +1486,7 @@ class MessageOptions(betterproto.Message): class FieldOptions(betterproto.Message): """ """ - ctype: "FieldOptionsCType" = betterproto.enum_field(1) + ctype: "FieldOptionsCType" = betterproto.enum_field(1, enum_default_value=lambda: FieldOptionsCType.try_value(0)) """ The ctype option instructs the C++ code generator to use a different representation of the field than it normally would. See the specific @@ -1503,7 +1503,7 @@ class FieldOptions(betterproto.Message): false will avoid using packed encoding. """ - jstype: "FieldOptionsJsType" = betterproto.enum_field(6) + jstype: "FieldOptionsJsType" = betterproto.enum_field(6, enum_default_value=lambda: FieldOptionsJsType.try_value(0)) """ The jstype option determines the JavaScript type used for values of the field. The option is permitted only for 64 bit integral and fixed types @@ -1658,7 +1658,7 @@ class MethodOptions(betterproto.Message): this is a formalization for deprecating methods. """ - idempotency_level: "MethodOptionsIdempotencyLevel" = betterproto.enum_field(34) + idempotency_level: "MethodOptionsIdempotencyLevel" = betterproto.enum_field(34, enum_default_value=lambda: MethodOptionsIdempotencyLevel.try_value(0)) """ """ @@ -2307,7 +2307,7 @@ class Value(betterproto.Message): The JSON representation for `Value` is JSON value. """ - null_value: "NullValue" = betterproto.enum_field(1, group="kind") + null_value: "NullValue" = betterproto.enum_field(1, enum_default_value=lambda: NullValue.try_value(0), group="kind") """Represents a null value.""" number_value: float = betterproto.double_field(2, group="kind") diff --git a/tests/test_features.py b/tests/test_features.py index 31558c145..3c9110856 100644 --- a/tests/test_features.py +++ b/tests/test_features.py @@ -96,7 +96,7 @@ class TestEnum(betterproto.Enum): @dataclass class Foo(betterproto.Message): - bar: TestEnum = betterproto.enum_field(1) + bar: TestEnum = betterproto.enum_field(1, enum_default_value=lambda: TestEnum.try_value(0)) # JSON strings are supported, but ints should still be supported too. foo = Foo().from_dict({"bar": 1}) From bff2547834f6f145e8872621823a4e69b867de19 Mon Sep 17 00:00:00 2001 From: Adrien Vannson Date: Mon, 11 Nov 2024 16:54:35 +0100 Subject: [PATCH 09/37] Fix default value for field in group --- src/betterproto/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/betterproto/__init__.py b/src/betterproto/__init__.py index bd7e926c4..6308d4a01 100644 --- a/src/betterproto/__init__.py +++ b/src/betterproto/__init__.py @@ -204,7 +204,7 @@ def dataclass_field( repeated: bool = False, ) -> dataclasses.Field: """Creates a dataclass field with attached protobuf metadata.""" - if optional: + if optional or group: def default_factory(): return None elif repeated: From f7f51620d4812fe816e779df6b752d829b9b7037 Mon Sep 17 00:00:00 2001 From: Adrien Vannson Date: Mon, 11 Nov 2024 17:00:07 +0100 Subject: [PATCH 10/37] Add repeated in message definition in tests --- tests/test_features.py | 4 ++-- tests/test_pickling.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/test_features.py b/tests/test_features.py index 3c9110856..c4f8bfce2 100644 --- a/tests/test_features.py +++ b/tests/test_features.py @@ -55,7 +55,7 @@ class Foo(betterproto.Message): @dataclass class WithCollections(betterproto.Message): - test_list: List[str] = betterproto.string_field(1) + test_list: List[str] = betterproto.string_field(1, repeated=True) test_map: Dict[str, str] = betterproto.map_field( 2, betterproto.TYPE_STRING, betterproto.TYPE_STRING ) @@ -640,7 +640,7 @@ class Envelope(betterproto.Message): def test_iso_datetime_list(): @dataclass class Envelope(betterproto.Message): - timestamps: List[datetime] = betterproto.message_field(1) + timestamps: List[datetime] = betterproto.message_field(1, repeated=True) msg = Envelope() diff --git a/tests/test_pickling.py b/tests/test_pickling.py index 5650f7501..95e02c70f 100644 --- a/tests/test_pickling.py +++ b/tests/test_pickling.py @@ -148,7 +148,7 @@ def test_recursive_message_defaults(): class PickledMessage(betterproto.Message): foo: bool = betterproto.bool_field(1) bar: int = betterproto.int32_field(2) - baz: List[str] = betterproto.string_field(3) + baz: List[str] = betterproto.string_field(3, repeated=True) def test_copyability(): From 1340bd8f6f181794bc4b170c38ec473360a31c0f Mon Sep 17 00:00:00 2001 From: Adrien Vannson Date: Mon, 11 Nov 2024 17:20:33 +0100 Subject: [PATCH 11/37] Fix missing messages in to_dict and to_pydict --- src/betterproto/__init__.py | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/src/betterproto/__init__.py b/src/betterproto/__init__.py index 6308d4a01..858c9942b 100644 --- a/src/betterproto/__init__.py +++ b/src/betterproto/__init__.py @@ -1428,13 +1428,7 @@ def to_dict( elif value is None: if include_default_values: output[cased_name] = value - elif ( - value._serialized_on_wire - or include_default_values - or self._include_default_value_for_oneof( - field_name=field_name, meta=meta - ) - ): + else: output[cased_name] = value.to_dict(casing, include_default_values) elif meta.proto_type == TYPE_MAP: output_map = {**value} @@ -1715,13 +1709,7 @@ def to_pydict( elif value is None: if include_default_values: output[cased_name] = None - elif ( - value._serialized_on_wire - or include_default_values - or self._include_default_value_for_oneof( - field_name=field_name, meta=meta - ) - ): + else: output[cased_name] = value.to_pydict(casing, include_default_values) elif meta.proto_type == TYPE_MAP: for k in value: From a9ec707cb3cea455113005cf4be99d1a726c2a77 Mon Sep 17 00:00:00 2001 From: Adrien Vannson Date: Mon, 11 Nov 2024 17:26:51 +0100 Subject: [PATCH 12/37] Fix pickling tests --- tests/test_pickling.py | 21 +-------------------- 1 file changed, 1 insertion(+), 20 deletions(-) diff --git a/tests/test_pickling.py b/tests/test_pickling.py index 95e02c70f..d4d809462 100644 --- a/tests/test_pickling.py +++ b/tests/test_pickling.py @@ -101,21 +101,6 @@ def test_pickling_complex_message(): ) -def test_recursive_message(): - from tests.output_betterproto.recursivemessage import Test as RecursiveMessage - - msg = RecursiveMessage() - msg = unpickled(msg) - - assert msg.child == RecursiveMessage() - - # Lazily-created zero-value children must not affect equality. - assert msg == RecursiveMessage() - - # Lazily-created zero-value children must not affect serialization. - assert bytes(msg) == b"" - - def test_recursive_message_defaults(): from tests.output_betterproto.recursivemessage import ( Intermediate, @@ -132,17 +117,13 @@ def test_recursive_message_defaults(): assert msg != RecursiveMessage( name="bob", intermediate=Intermediate(42), child=RecursiveMessage(name="jude") ) - msg.child.child.name = "jude" + msg.child = RecursiveMessage(child=RecursiveMessage(name="jude")) assert msg == RecursiveMessage( name="bob", intermediate=Intermediate(42), child=RecursiveMessage(child=RecursiveMessage(name="jude")), ) - # lazily initialization recurses as needed - assert msg.child.child.child.child.child.child.child == RecursiveMessage() - assert msg.intermediate.child.intermediate == Intermediate() - @dataclass class PickledMessage(betterproto.Message): From a613dff521ff31402f0f42368da7eb8c383320ff Mon Sep 17 00:00:00 2001 From: Adrien Vannson Date: Mon, 11 Nov 2024 17:51:13 +0100 Subject: [PATCH 13/37] Fix placeholders in tests --- .../test_google_impl_behavior_equivalence.py | 6 ++---- tests/test_features.py | 6 ++---- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/tests/inputs/google_impl_behavior_equivalence/test_google_impl_behavior_equivalence.py b/tests/inputs/google_impl_behavior_equivalence/test_google_impl_behavior_equivalence.py index 6d2991bdd..1faa6d455 100644 --- a/tests/inputs/google_impl_behavior_equivalence/test_google_impl_behavior_equivalence.py +++ b/tests/inputs/google_impl_behavior_equivalence/test_google_impl_behavior_equivalence.py @@ -58,10 +58,8 @@ def test_bytes_are_the_same_for_oneof(): # None of these fields were explicitly set BUT they should not actually be null # themselves - assert not hasattr(message, "foo") - assert object.__getattribute__(message, "foo") == betterproto.PLACEHOLDER - assert not hasattr(message2, "foo") - assert object.__getattribute__(message2, "foo") == betterproto.PLACEHOLDER + assert message.foo is None + assert message2.foo is None assert isinstance(message_reference.foo, ReferenceFoo) assert isinstance(message_reference2.foo, ReferenceFoo) diff --git a/tests/test_features.py b/tests/test_features.py index c4f8bfce2..f6b223e17 100644 --- a/tests/test_features.py +++ b/tests/test_features.py @@ -154,8 +154,7 @@ class Foo(betterproto.Message): foo.baz = "test" # Other oneof fields should now be unset - assert not hasattr(foo, "bar") - assert object.__getattribute__(foo, "bar") == betterproto.PLACEHOLDER + assert foo.bar is None assert betterproto.which_one_of(foo, "group1")[0] == "baz" foo.sub = Sub(val=1) @@ -164,8 +163,7 @@ class Foo(betterproto.Message): foo.abc = "test" # Group 1 shouldn't be touched, group 2 should have reset - assert not hasattr(foo, "sub") - assert object.__getattribute__(foo, "sub") == betterproto.PLACEHOLDER + assert foo.sub is None assert betterproto.which_one_of(foo, "group2")[0] == "abc" # Zero value should always serialize for one-of From d3e17f408af6b01922955668cbd143c7ab92c500 Mon Sep 17 00:00:00 2001 From: Adrien Vannson Date: Mon, 11 Nov 2024 18:02:11 +0100 Subject: [PATCH 14/37] Remove serialize_on_wire from condition --- src/betterproto/__init__.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/betterproto/__init__.py b/src/betterproto/__init__.py index 858c9942b..ff62803ec 100644 --- a/src/betterproto/__init__.py +++ b/src/betterproto/__init__.py @@ -913,7 +913,8 @@ def dump(self, stream: "SupportsWrite[bytes]", delimit: bool = False) -> None: # Empty messages can still be sent on the wire if they were # set (or received empty). - serialize_empty = isinstance(value, Message) and value._serialized_on_wire + # TODO this is here for historical reasons, now if a message is defined (ie not None), it should be sent + serialize_empty = isinstance(value, Message) include_default_value_for_oneof = self._include_default_value_for_oneof( field_name=field_name, meta=meta @@ -1019,7 +1020,7 @@ def __len__(self) -> int: # Empty messages can still be sent on the wire if they were # set (or received empty). - serialize_empty = isinstance(value, Message) and value._serialized_on_wire + serialize_empty = isinstance(value, Message) include_default_value_for_oneof = self._include_default_value_for_oneof( field_name=field_name, meta=meta From d5701ab1d20732f4ee683bd4268b7961c9bb9e45 Mon Sep 17 00:00:00 2001 From: Adrien Vannson Date: Mon, 11 Nov 2024 18:33:38 +0100 Subject: [PATCH 15/37] Remove serialize_on_wire --- src/betterproto/__init__.py | 44 +------------------------------------ 1 file changed, 1 insertion(+), 43 deletions(-) diff --git a/src/betterproto/__init__.py b/src/betterproto/__init__.py index ff62803ec..5f8db646e 100644 --- a/src/betterproto/__init__.py +++ b/src/betterproto/__init__.py @@ -748,7 +748,6 @@ class Message(ABC): Calls :meth:`__bool__`. """ - _serialized_on_wire: bool _unknown_fields: bytes _group_current: Dict[str, str] _betterproto_meta: ClassVar[ProtoClassMetadata] @@ -767,17 +766,7 @@ def __post_init__(self) -> None: if value is not None: group_current[meta.group] = field_name - # if value is not PLACEHOLDER and not (meta.optional and value is None): - # # Found a non-sentinel value - # all_sentinel = False - - # if meta.group: - # # This was set, so make it the selected value of the one-of. - # group_current[meta.group] = field_name - # Now that all the defaults are set, reset it! - # self.__dict__["_serialized_on_wire"] = not all_sentinel - self.__dict__["_serialized_on_wire"] = False self.__dict__["_unknown_fields"] = b"" self.__dict__["_group_current"] = group_current @@ -821,17 +810,6 @@ def __repr__(self) -> str: # yield field_name, self.__raw_get(field_name), PLACEHOLDER def __setattr__(self, attr: str, value: Any) -> None: - if ( - isinstance(value, Message) - and hasattr(value, "_betterproto") - and not value._betterproto.meta_by_field_name - ): - value._serialized_on_wire = True - - if attr != "_serialized_on_wire": - # Track when a field has been set. - self.__dict__["_serialized_on_wire"] = True - if hasattr(self, "_group_current"): # __post_init__ had already run if attr in self._betterproto.oneof_group_by_field: group = self._betterproto.oneof_group_by_field[attr] @@ -1206,7 +1184,6 @@ def _postprocess_single( value = _get_wrapper(meta.wraps)().parse(value).value else: value = cls().parse(value) - value._serialized_on_wire = True elif meta.proto_type == TYPE_MAP: value = self._betterproto.cls_by_field[field_name]().parse(value) @@ -1247,7 +1224,6 @@ def load( size, _ = load_varint(stream) # Got some data over the wire - self._serialized_on_wire = True proto_meta = self._betterproto read = 0 for parsed in load_fields(stream): @@ -1570,9 +1546,7 @@ def from_dict(cls: type[Self], value: Mapping[str, Any]) -> Self: # type: ignor :class:`Message` The initialized message. """ - self = cls(**cls._from_dict_init(value)) - self._serialized_on_wire = True - return self + return cls(**cls._from_dict_init(value)) @from_dict.instancemethod def from_dict(self, value: Mapping[str, Any]) -> Self: @@ -1590,7 +1564,6 @@ def from_dict(self, value: Mapping[str, Any]) -> Self: :class:`Message` The initialized message. """ - self._serialized_on_wire = True for field, value in self._from_dict_init(value).items(): setattr(self, field, value) return self @@ -1744,7 +1717,6 @@ def from_pydict(self: T, value: Mapping[str, Any]) -> T: :class:`Message` The initialized message. """ - self._serialized_on_wire = True for key in value: field_name = safe_snake_case(key) meta = self._betterproto.meta_by_field_name.get(field_name) @@ -1846,20 +1818,6 @@ def __bytes_patch(self) -> bytes: pass -def serialized_on_wire(message: Message) -> bool: - """ - If this message was or should be serialized on the wire. This can be used to detect - presence (e.g. optional wrapper message) and is used internally during - parsing/serialization. - - Returns - -------- - :class:`bool` - Whether this message was or should be serialized on the wire. - """ - return message._serialized_on_wire - - def which_one_of(message: Message, group_name: str) -> Tuple[str, Optional[Any]]: """ Return the name and value of a message's one-of field group. From 0936fb19e1289211143c8f7f81fd397a7d6beefd Mon Sep 17 00:00:00 2001 From: Adrien Vannson Date: Tue, 12 Nov 2024 10:11:50 +0100 Subject: [PATCH 16/37] Remove serialize_on_wire tests --- .../test_google_impl_behavior_equivalence.py | 3 -- tests/test_features.py | 49 ------------------- 2 files changed, 52 deletions(-) diff --git a/tests/inputs/google_impl_behavior_equivalence/test_google_impl_behavior_equivalence.py b/tests/inputs/google_impl_behavior_equivalence/test_google_impl_behavior_equivalence.py index 1faa6d455..97587cfa9 100644 --- a/tests/inputs/google_impl_behavior_equivalence/test_google_impl_behavior_equivalence.py +++ b/tests/inputs/google_impl_behavior_equivalence/test_google_impl_behavior_equivalence.py @@ -85,7 +85,4 @@ def test_empty_message_field(): message.foo = Empty() reference_message.foo.CopyFrom(ReferenceEmpty()) - assert betterproto.serialized_on_wire(message.foo) - assert reference_message.HasField("foo") - assert bytes(message) == reference_message.SerializeToString() diff --git a/tests/test_features.py b/tests/test_features.py index f6b223e17..349d0616a 100644 --- a/tests/test_features.py +++ b/tests/test_features.py @@ -25,54 +25,6 @@ import betterproto -def test_has_field(): - @dataclass - class Bar(betterproto.Message): - baz: int = betterproto.int32_field(1) - - @dataclass - class Foo(betterproto.Message): - bar: Bar = betterproto.message_field(1) - - foo = Foo() - - # Serialized after setting something - foo.bar = Bar() - foo.bar.baz = 1 - assert betterproto.serialized_on_wire(foo.bar) is True - - # Still has it after setting the default value - foo.bar.baz = 0 - assert betterproto.serialized_on_wire(foo.bar) is True - - # Manual override (don't do this) - foo.bar._serialized_on_wire = False - assert betterproto.serialized_on_wire(foo.bar) is False - - # Can manually set it but defaults to false - foo.bar = Bar() - assert betterproto.serialized_on_wire(foo.bar) is False - - @dataclass - class WithCollections(betterproto.Message): - test_list: List[str] = betterproto.string_field(1, repeated=True) - test_map: Dict[str, str] = betterproto.map_field( - 2, betterproto.TYPE_STRING, betterproto.TYPE_STRING - ) - - # Is always set from parse, even if all collections are empty - with_collections_empty = WithCollections().parse(bytes(WithCollections())) - assert betterproto.serialized_on_wire(with_collections_empty) == True - with_collections_list = WithCollections().parse( - bytes(WithCollections(test_list=["a", "b", "c"])) - ) - assert betterproto.serialized_on_wire(with_collections_list) == True - with_collections_map = WithCollections().parse( - bytes(WithCollections(test_map={"a": "b", "c": "d"})) - ) - assert betterproto.serialized_on_wire(with_collections_map) == True - - def test_class_init(): @dataclass class Bar(betterproto.Message): @@ -158,7 +110,6 @@ class Foo(betterproto.Message): assert betterproto.which_one_of(foo, "group1")[0] == "baz" foo.sub = Sub(val=1) - assert betterproto.serialized_on_wire(foo.sub) foo.abc = "test" From fded4d38ebb7c9f5ba6891f235b855014cbf7d62 Mon Sep 17 00:00:00 2001 From: Adrien Vannson Date: Tue, 12 Nov 2024 10:31:15 +0100 Subject: [PATCH 17/37] Remove wrong test --- .../test_proto3_field_presence_oneof.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/inputs/proto3_field_presence_oneof/test_proto3_field_presence_oneof.py b/tests/inputs/proto3_field_presence_oneof/test_proto3_field_presence_oneof.py index d5f69d01a..6008e6a4f 100644 --- a/tests/inputs/proto3_field_presence_oneof/test_proto3_field_presence_oneof.py +++ b/tests/inputs/proto3_field_presence_oneof/test_proto3_field_presence_oneof.py @@ -18,7 +18,6 @@ def test_empty_nested(message: Test) -> None: test_empty_nested(Test(nested=Nested())) test_empty_nested(Test(nested=Nested(inner=None))) - test_empty_nested(Test(nested=Nested(inner=InnerNested(a=None)))) def test_empty_with_optional(message: Test) -> None: # '12' => tag 2, length delimited From c9df9c1723b7ea26206afde8a88ad20498cd367f Mon Sep 17 00:00:00 2001 From: Adrien Vannson Date: Tue, 12 Nov 2024 10:33:51 +0100 Subject: [PATCH 18/37] Load test directly --- tests/oneof_pattern_matching.py | 46 --------------------------------- tests/test_features.py | 10 ------- 2 files changed, 56 deletions(-) delete mode 100644 tests/oneof_pattern_matching.py diff --git a/tests/oneof_pattern_matching.py b/tests/oneof_pattern_matching.py deleted file mode 100644 index d4f18aab2..000000000 --- a/tests/oneof_pattern_matching.py +++ /dev/null @@ -1,46 +0,0 @@ -from dataclasses import dataclass - -import pytest - -import betterproto - - -def test_oneof_pattern_matching(): - @dataclass - class Sub(betterproto.Message): - val: int = betterproto.int32_field(1) - - @dataclass - class Foo(betterproto.Message): - bar: int = betterproto.int32_field(1, group="group1") - baz: str = betterproto.string_field(2, group="group1") - sub: Sub = betterproto.message_field(3, group="group2") - abc: str = betterproto.string_field(4, group="group2") - - foo = Foo(baz="test1", abc="test2") - - match foo: - case Foo(bar=_): - pytest.fail("Matched 'bar' instead of 'baz'") - case Foo(baz=v): - assert v == "test1" - case _: - pytest.fail("Matched neither 'bar' nor 'baz'") - - match foo: - case Foo(sub=_): - pytest.fail("Matched 'sub' instead of 'abc'") - case Foo(abc=v): - assert v == "test2" - case _: - pytest.fail("Matched neither 'sub' nor 'abc'") - - foo.sub = Sub(val=1) - - match foo: - case Foo(sub=Sub(val=v)): - assert v == 1 - case Foo(abc=v): - pytest.fail("Matched 'abc' instead of 'sub'") - case _: - pytest.fail("Matched neither 'sub' nor 'abc'") diff --git a/tests/test_features.py b/tests/test_features.py index 349d0616a..4946b3f97 100644 --- a/tests/test_features.py +++ b/tests/test_features.py @@ -129,16 +129,6 @@ class Foo(betterproto.Message): assert betterproto.which_one_of(foo2, "group2")[0] == "" -@pytest.mark.skipif( - sys.version_info < (3, 10), - reason="pattern matching is only supported in python3.10+", -) -def test_oneof_pattern_matching(): - from .oneof_pattern_matching import test_oneof_pattern_matching - - test_oneof_pattern_matching() - - def test_json_casing(): @dataclass class CasingTest(betterproto.Message): From bc9d79ed593c230aef35817a51b193e76abde42e Mon Sep 17 00:00:00 2001 From: Adrien Vannson Date: Tue, 12 Nov 2024 10:43:41 +0100 Subject: [PATCH 19/37] Fix match test --- tests/test_oneof_pattern_matching.py | 52 ++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 tests/test_oneof_pattern_matching.py diff --git a/tests/test_oneof_pattern_matching.py b/tests/test_oneof_pattern_matching.py new file mode 100644 index 000000000..2bd07ab50 --- /dev/null +++ b/tests/test_oneof_pattern_matching.py @@ -0,0 +1,52 @@ +from dataclasses import dataclass + +import pytest +import sys +from typing import Optional + +import betterproto + + +@pytest.mark.skipif( + sys.version_info < (3, 10), + reason="pattern matching is only supported in python3.10+", +) +def test_oneof_pattern_matching(): + @dataclass + class Sub(betterproto.Message): + val: int = betterproto.int32_field(1) + + @dataclass + class Foo(betterproto.Message): + bar: Optional[int] = betterproto.int32_field(1, group="group1") + baz: Optional[str] = betterproto.string_field(2, group="group1") + sub: Optional[Sub] = betterproto.message_field(3, group="group2") + abc: Optional[str] = betterproto.string_field(4, group="group2") + + foo = Foo(baz="test1", abc="test2") + + match foo: + case Foo(bar=int(_)): + pytest.fail("Matched 'bar' instead of 'baz'") + case Foo(baz=v): + assert v == "test1" + case _: + pytest.fail("Matched neither 'bar' nor 'baz'") + + match foo: + case Foo(sub=Sub(_)): + pytest.fail("Matched 'sub' instead of 'abc'") + case Foo(abc=v): + assert v == "test2" + case _: + pytest.fail("Matched neither 'sub' nor 'abc'") + + foo.sub = Sub(val=1) + + match foo: + case Foo(sub=Sub(val=v)): + assert v == 1 + case Foo(abc=str(v)): + pytest.fail("Matched 'abc' instead of 'sub'") + case _: + pytest.fail("Matched neither 'sub' nor 'abc'") From 02e46f21de2e8ca4310c9b76b88e8d0e9eccb368 Mon Sep 17 00:00:00 2001 From: Adrien Vannson Date: Tue, 12 Nov 2024 10:44:44 +0100 Subject: [PATCH 20/37] Fix README --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 4bbfc174b..d0232f869 100644 --- a/README.md +++ b/README.md @@ -283,11 +283,11 @@ On Python 3.10 and later, you can use a `match` statement to access the provided ```py test = Test() match test: - case Test(on=value): + case Test(on=bool(value)): print(value) # value: bool - case Test(count=value): + case Test(count=int(value)): print(value) # value: int - case Test(name=value): + case Test(name=str(value)): print(value) # value: str case _: print("No value provided") From 48c8fea5a3b2c60800340e831a94ee63db327ab8 Mon Sep 17 00:00:00 2001 From: Adrien Vannson Date: Tue, 12 Nov 2024 11:08:47 +0100 Subject: [PATCH 21/37] Add error (tofix) --- src/betterproto/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/betterproto/__init__.py b/src/betterproto/__init__.py index 5f8db646e..0f0c23fd0 100644 --- a/src/betterproto/__init__.py +++ b/src/betterproto/__init__.py @@ -1737,6 +1737,7 @@ def from_pydict(self: T, value: Mapping[str, Any]) -> T: elif meta.wraps: v = value[key] else: + raise NotImplementedError # NOTE: `from_pydict` mutates the underlying message, so no # assignment here is necessary. v.from_pydict(value[key]) From 1258390590e9a37d5068eaa1c8cd5a44d4e26bc6 Mon Sep 17 00:00:00 2001 From: Adrien Vannson Date: Tue, 12 Nov 2024 11:15:01 +0100 Subject: [PATCH 22/37] Fix to_dict / to_pydict test --- tests/test_features.py | 33 ++++----------------------------- 1 file changed, 4 insertions(+), 29 deletions(-) diff --git a/tests/test_features.py b/tests/test_features.py index 4946b3f97..dac2fd5cd 100644 --- a/tests/test_features.py +++ b/tests/test_features.py @@ -284,28 +284,7 @@ class TestMessage(betterproto.Message): some_bool: bool = betterproto.bool_field(4) # Empty dict - test = TestMessage().from_dict({}) - - assert test.to_dict(include_default_values=True) == { - "someInt": 0, - "someDouble": 0.0, - "someStr": "", - "someBool": False, - } - - test = TestMessage().from_pydict({}) - - assert test.to_pydict(include_default_values=True) == { - "someInt": 0, - "someDouble": 0.0, - "someStr": "", - "someBool": False, - } - - # All default values - test = TestMessage().from_dict( - {"someInt": 0, "someDouble": 0.0, "someStr": "", "someBool": False} - ) + test = TestMessage() assert test.to_dict(include_default_values=True) == { "someInt": 0, @@ -314,10 +293,6 @@ class TestMessage(betterproto.Message): "someBool": False, } - test = TestMessage().from_pydict( - {"someInt": 0, "someDouble": 0.0, "someStr": "", "someBool": False} - ) - assert test.to_pydict(include_default_values=True) == { "someInt": 0, "someDouble": 0.0, @@ -394,14 +369,14 @@ class TestChildMessage(betterproto.Message): class TestParentMessage(betterproto.Message): some_int: int = betterproto.int32_field(1) some_double: float = betterproto.double_field(2) - some_message: TestChildMessage = betterproto.message_field(3) + some_message: Optional[TestChildMessage] = betterproto.message_field(3) test = TestParentMessage().from_dict({"someInt": 0, "someDouble": 1.2}) assert test.to_dict(include_default_values=True) == { "someInt": 0, "someDouble": 1.2, - "someMessage": {"someOtherInt": 0}, + "someMessage": None, } test = TestParentMessage().from_pydict({"someInt": 0, "someDouble": 1.2}) @@ -409,7 +384,7 @@ class TestParentMessage(betterproto.Message): assert test.to_pydict(include_default_values=True) == { "someInt": 0, "someDouble": 1.2, - "someMessage": {"someOtherInt": 0}, + "someMessage": None, } From e09ec0c4afbc5bac7ee7c3aebe8b7139f98b7e4b Mon Sep 17 00:00:00 2001 From: Adrien Vannson Date: Tue, 12 Nov 2024 11:20:54 +0100 Subject: [PATCH 23/37] Don't include default value in __repr__ --- src/betterproto/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/betterproto/__init__.py b/src/betterproto/__init__.py index 0f0c23fd0..41d641cad 100644 --- a/src/betterproto/__init__.py +++ b/src/betterproto/__init__.py @@ -802,6 +802,7 @@ def __repr__(self) -> str: f"{field_name}={value!r}" for field_name in self._betterproto.sorted_field_names for value in (self.__raw_get(field_name),) + if value != self._get_field_default(field_name) ] return f"{self.__class__.__name__}({', '.join(parts)})" From a3d55cc04d3aef06d7dbc57d17312158134d2ec0 Mon Sep 17 00:00:00 2001 From: Adrien Vannson Date: Tue, 12 Nov 2024 11:46:44 +0100 Subject: [PATCH 24/37] Fix snake_case test --- tests/inputs/casing_inner_class/test_casing_inner_class.py | 2 +- tests/test_inputs.py | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/tests/inputs/casing_inner_class/test_casing_inner_class.py b/tests/inputs/casing_inner_class/test_casing_inner_class.py index 267b10560..50103c921 100644 --- a/tests/inputs/casing_inner_class/test_casing_inner_class.py +++ b/tests/inputs/casing_inner_class/test_casing_inner_class.py @@ -8,7 +8,7 @@ def test_message_casing_inner_class_name(): def test_message_casing_inner_class_attributes(): - message = casing_inner_class.Test() + message = casing_inner_class.Test(inner=casing_inner_class.TestInnerClass()) assert hasattr( message.inner, "old_exp" ), "Inline defined Message attribute is snake_case" diff --git a/tests/test_inputs.py b/tests/test_inputs.py index 2077fffd5..180b13bb2 100644 --- a/tests/test_inputs.py +++ b/tests/test_inputs.py @@ -185,7 +185,12 @@ def test_message_json(repeat, test_data: TestData) -> None: message: betterproto.Message = plugin_module.Test() message.from_json(sample.json) - message_json = message.to_json(0) + message_json = message.to_json(indent=0) + + + print(message) + print(message_json) + print(message.to_dict()) assert dict_replace_nans(json.loads(message_json)) == dict_replace_nans( json.loads(sample.json) From 2884b5a45c755c53b32042965134855f277d61f4 Mon Sep 17 00:00:00 2001 From: Adrien Vannson Date: Tue, 12 Nov 2024 12:00:17 +0100 Subject: [PATCH 25/37] Remove useless try / catch --- src/betterproto/__init__.py | 21 ++++----------------- 1 file changed, 4 insertions(+), 17 deletions(-) diff --git a/src/betterproto/__init__.py b/src/betterproto/__init__.py index 41d641cad..5214e237b 100644 --- a/src/betterproto/__init__.py +++ b/src/betterproto/__init__.py @@ -871,10 +871,7 @@ def dump(self, stream: "SupportsWrite[bytes]", delimit: bool = False) -> None: dump_varint(len(self), stream) for field_name, meta in self._betterproto.meta_by_field_name.items(): - try: - value = getattr(self, field_name) - except AttributeError: - continue + value = getattr(self, field_name) if value is None: # Optional items should be skipped. This is used for the Google @@ -978,10 +975,7 @@ def __len__(self) -> int: """ size = 0 for field_name, meta in self._betterproto.meta_by_field_name.items(): - try: - value = getattr(self, field_name) - except AttributeError: - continue + value = getattr(self, field_name) if value is None: # Optional items should be skipped. This is used for the Google @@ -1259,11 +1253,7 @@ def load( parsed.wire_type, meta, field_name, parsed.value ) - try: - current = getattr(self, field_name) - except AttributeError: - current = self._get_field_default(field_name) - setattr(self, field_name, current) + current = getattr(self, field_name) if meta.proto_type == TYPE_MAP: # Value represents a single key/value pair entry in the map. @@ -1363,10 +1353,7 @@ def to_dict( defaults = self._betterproto.default_gen for field_name, meta in self._betterproto.meta_by_field_name.items(): field_is_repeated = defaults[field_name] is list - try: - value = getattr(self, field_name) - except AttributeError: - value = self._get_field_default(field_name) + value = getattr(self, field_name) cased_name = casing(field_name).rstrip("_") # type: ignore if meta.proto_type == TYPE_MESSAGE: if isinstance(value, datetime): From ba940f5db3506eb73171c36318ac456dcc1260f4 Mon Sep 17 00:00:00 2001 From: Adrien Vannson Date: Tue, 12 Nov 2024 12:17:45 +0100 Subject: [PATCH 26/37] Manually add missing repeated parameters in compiled file --- .../lib/std/google/protobuf/compiler/__init__.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/betterproto/lib/std/google/protobuf/compiler/__init__.py b/src/betterproto/lib/std/google/protobuf/compiler/__init__.py index e720b1c09..d2bfa6146 100644 --- a/src/betterproto/lib/std/google/protobuf/compiler/__init__.py +++ b/src/betterproto/lib/std/google/protobuf/compiler/__init__.py @@ -36,7 +36,7 @@ class Version(betterproto.Message): class CodeGeneratorRequest(betterproto.Message): """An encoded CodeGeneratorRequest is written to the plugin's stdin.""" - file_to_generate: List[str] = betterproto.string_field(1) + file_to_generate: List[str] = betterproto.string_field(1, repeated=True) """ The .proto files that were explicitly listed on the command-line. The code generator should generate code only for these files. Each file's @@ -48,7 +48,7 @@ class CodeGeneratorRequest(betterproto.Message): proto_file: List[ "betterproto_lib_google_protobuf.FileDescriptorProto" - ] = betterproto.message_field(15) + ] = betterproto.message_field(15, repeated=True) """ FileDescriptorProtos for all files in files_to_generate and everything they import. The files will appear in topological order, so each file @@ -73,7 +73,7 @@ class CodeGeneratorRequest(betterproto.Message): source_file_descriptors: List[ "betterproto_lib_google_protobuf.FileDescriptorProto" - ] = betterproto.message_field(17) + ] = betterproto.message_field(17, repeated=True) """ File descriptors with all options, including source-retention options. These descriptors are only provided for the files listed in @@ -122,7 +122,7 @@ class CodeGeneratorResponse(betterproto.Message): effect for plugins that have FEATURE_SUPPORTS_EDITIONS set. """ - file: List["CodeGeneratorResponseFile"] = betterproto.message_field(15) + file: List["CodeGeneratorResponseFile"] = betterproto.message_field(15, repeated=True) @dataclass(eq=False, repr=False) From 8b7a9478ea2b97ec3cc77c06b9af4640eb7e58b1 Mon Sep 17 00:00:00 2001 From: Adrien Vannson Date: Tue, 12 Nov 2024 13:02:46 +0100 Subject: [PATCH 27/37] Fix compilation errors --- .../lib/std/google/protobuf/__init__.py | 5 +- src/betterproto/plugin/main.py | 4 +- src/betterproto/plugin/models.py | 46 ++++++++++--------- src/betterproto/plugin/parser.py | 2 +- src/betterproto/templates/template.py.j2 | 2 +- 5 files changed, 31 insertions(+), 28 deletions(-) diff --git a/src/betterproto/lib/std/google/protobuf/__init__.py b/src/betterproto/lib/std/google/protobuf/__init__.py index 1d0832b03..00a5e1146 100644 --- a/src/betterproto/lib/std/google/protobuf/__init__.py +++ b/src/betterproto/lib/std/google/protobuf/__init__.py @@ -74,7 +74,8 @@ from typing import ( Dict, List, - Mapping + Mapping, + Optional ) from typing_extensions import Self @@ -1029,7 +1030,7 @@ class FieldDescriptorProto(betterproto.Message): TODO(kenton): Base-64 encode? """ - oneof_index: int = betterproto.int32_field(9) + oneof_index: Optional[int] = betterproto.int32_field(9, optional=True) """ If set, gives the index of a oneof in the containing type's oneof_decl list. This field is a member of that oneof. diff --git a/src/betterproto/plugin/main.py b/src/betterproto/plugin/main.py index 62382e2e9..5fbeebc6d 100755 --- a/src/betterproto/plugin/main.py +++ b/src/betterproto/plugin/main.py @@ -7,7 +7,7 @@ CodeGeneratorRequest, CodeGeneratorResponse, ) -from betterproto.plugin.models import monkey_patch_oneof_index +# from betterproto.plugin.models import monkey_patch_oneof_index from betterproto.plugin.parser import generate_code @@ -17,7 +17,7 @@ def main() -> None: data = sys.stdin.buffer.read() # Apply Work around for proto2/3 difference in protoc messages - monkey_patch_oneof_index() + # monkey_patch_oneof_index() # Parse request request = CodeGeneratorRequest() diff --git a/src/betterproto/plugin/models.py b/src/betterproto/plugin/models.py index 3e249aae3..b8a4b588e 100644 --- a/src/betterproto/plugin/models.py +++ b/src/betterproto/plugin/models.py @@ -127,25 +127,26 @@ ) -def monkey_patch_oneof_index(): - """ - The compiler message types are written for proto2, but we read them as proto3. - For this to work in the case of the oneof_index fields, which depend on being able - to tell whether they were set, we have to treat them as oneof fields. This method - monkey patches the generated classes after the fact to force this behaviour. - """ - object.__setattr__( - FieldDescriptorProto.__dataclass_fields__["oneof_index"].metadata[ - "betterproto" - ], - "group", - "oneof_index", - ) - object.__setattr__( - Field.__dataclass_fields__["oneof_index"].metadata["betterproto"], - "group", - "oneof_index", - ) +# TODO patch again to make field optional +# def monkey_patch_oneof_index(): +# """ +# The compiler message types are written for proto2, but we read them as proto3. +# For this to work in the case of the oneof_index fields, which depend on being able +# to tell whether they were set, we have to treat them as oneof fields. This method +# monkey patches the generated classes after the fact to force this behaviour. +# """ +# object.__setattr__( +# FieldDescriptorProto.__dataclass_fields__["oneof_index"].metadata[ +# "betterproto" +# ], +# "group", +# "oneof_index", +# ) +# object.__setattr__( +# Field.__dataclass_fields__["oneof_index"].metadata["betterproto"], +# "group", +# "oneof_index", +# ) def get_comment( @@ -304,7 +305,7 @@ def python_module_imports(self) -> Set[str]: if any(x for x in self.messages if any(x.deprecated_fields)): has_deprecated = True if any( - any(m.proto_obj.options.deprecated for m in s.methods) + any(m.proto_obj.options and m.proto_obj.options.deprecated for m in s.methods) for s in self.services ): has_deprecated = True @@ -339,7 +340,7 @@ def __post_init__(self) -> None: self.output_file.enums.append(self) else: self.output_file.messages.append(self) - self.deprecated = self.proto_obj.options.deprecated + self.deprecated = self.proto_obj.options and self.proto_obj.options.deprecated super().__post_init__() @property @@ -401,6 +402,7 @@ def is_oneof(proto_field_obj: FieldDescriptorProto) -> bool: True if proto_field_obj is a OneOf, otherwise False. .. warning:: + TODO update comment Becuase the message from protoc is defined in proto2, and betterproto works with proto3, and interpreting the FieldDescriptorProto.oneof_index field requires distinguishing between default and unset values (which proto3 doesn't support), @@ -412,7 +414,7 @@ def is_oneof(proto_field_obj: FieldDescriptorProto) -> bool: return ( not proto_field_obj.proto3_optional - and which_one_of(proto_field_obj, "oneof_index")[0] == "oneof_index" + and proto_field_obj.oneof_index is not None ) diff --git a/src/betterproto/plugin/parser.py b/src/betterproto/plugin/parser.py index 5f7b72c40..4374f9c4e 100644 --- a/src/betterproto/plugin/parser.py +++ b/src/betterproto/plugin/parser.py @@ -205,7 +205,7 @@ def read_protobuf_type( output_package: OutputTemplate, ) -> None: if isinstance(item, DescriptorProto): - if item.options.map_entry: + if item.options and item.options.map_entry: # Skip generated map entry messages since we just use dicts return # Process Message diff --git a/src/betterproto/templates/template.py.j2 b/src/betterproto/templates/template.py.j2 index 4a252aec6..aff024c9b 100644 --- a/src/betterproto/templates/template.py.j2 +++ b/src/betterproto/templates/template.py.j2 @@ -89,7 +89,7 @@ class {{ service.py_name }}Stub(betterproto.ServiceStub): {{ method.comment }} {% endif %} - {% if method.proto_obj.options.deprecated %} + {% if method.proto_obj.options and method.proto_obj.options.deprecated %} warnings.warn("{{ service.py_name }}.{{ method.py_name }} is deprecated", DeprecationWarning) {% endif %} From fd0bf4c5f2c7bc0309d29d6e1c151f761e3d2032 Mon Sep 17 00:00:00 2001 From: Adrien Vannson Date: Tue, 12 Nov 2024 14:39:58 +0100 Subject: [PATCH 28/37] Fix enum compilation --- src/betterproto/plugin/models.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/betterproto/plugin/models.py b/src/betterproto/plugin/models.py index b8a4b588e..fefde9799 100644 --- a/src/betterproto/plugin/models.py +++ b/src/betterproto/plugin/models.py @@ -450,9 +450,11 @@ def betterproto_field_args(self) -> List[str]: if self.field_wraps: args.append(f"wraps={self.field_wraps}") if self.optional: - args.append(f"optional=True") + args.append("optional=True") if self.repeated: - args.append(f"repeated=True") + args.append("repeated=True") + if self.field_type == "enum": + args.append(f"enum_default_value=lambda: {self.py_type.strip('"')}.try_value(0)") return args @property From 5e65d4f52fb4c34fe516d84ca47e16220fe11d6c Mon Sep 17 00:00:00 2001 From: Adrien Vannson Date: Tue, 12 Nov 2024 15:28:26 +0100 Subject: [PATCH 29/37] Compile fields in oneof as optional --- src/betterproto/plugin/models.py | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/betterproto/plugin/models.py b/src/betterproto/plugin/models.py index fefde9799..71e45205d 100644 --- a/src/betterproto/plugin/models.py +++ b/src/betterproto/plugin/models.py @@ -569,6 +569,10 @@ def annotation(self) -> str: @dataclass class OneOfFieldCompiler(FieldCompiler): + @property + def optional(self) -> bool: + return True + @property def betterproto_field_args(self) -> List[str]: args = super().betterproto_field_args @@ -579,13 +583,6 @@ def betterproto_field_args(self) -> List[str]: @dataclass class PydanticOneOfFieldCompiler(OneOfFieldCompiler): - @property - def optional(self) -> bool: - # Force the optional to be True. This will allow the pydantic dataclass - # to validate the object correctly by allowing the field to be let empty. - # We add a pydantic validator later to ensure exactly one field is defined. - return True - @property def pydantic_imports(self) -> Set[str]: return {"model_validator"} From 3d44dc2772b2c8a50873ac4650e3acb46a51a5a5 Mon Sep 17 00:00:00 2001 From: Adrien Vannson Date: Tue, 12 Nov 2024 16:00:56 +0100 Subject: [PATCH 30/37] Fix from_pydict --- src/betterproto/__init__.py | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/betterproto/__init__.py b/src/betterproto/__init__.py index 5214e237b..3a113db81 100644 --- a/src/betterproto/__init__.py +++ b/src/betterproto/__init__.py @@ -1714,21 +1714,18 @@ def from_pydict(self: T, value: Mapping[str, Any]) -> T: if value[key] is not None: if meta.proto_type == TYPE_MESSAGE: v = getattr(self, field_name) - if isinstance(v, list): - cls = self._betterproto.cls_by_field[field_name] + cls = self._betterproto.cls_by_field[field_name] + if issubclass(cls, list): for item in value[key]: v.append(cls().from_pydict(item)) - elif isinstance(v, datetime): + elif issubclass(cls, datetime): v = value[key] - elif isinstance(v, timedelta): + elif issubclass(cls, timedelta): v = value[key] elif meta.wraps: v = value[key] else: - raise NotImplementedError - # NOTE: `from_pydict` mutates the underlying message, so no - # assignment here is necessary. - v.from_pydict(value[key]) + v = cls().from_pydict(value[key]) elif meta.map_types and meta.map_types[1] == TYPE_MESSAGE: v = getattr(self, field_name) cls = self._betterproto.cls_by_field[f"{field_name}.value"] From 1ed8da03be6fa3adb03add4947e1b1eb22ed8971 Mon Sep 17 00:00:00 2001 From: Adrien Vannson Date: Tue, 12 Nov 2024 16:13:27 +0100 Subject: [PATCH 31/37] Remove Rust codec --- src/betterproto/__init__.py | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/src/betterproto/__init__.py b/src/betterproto/__init__.py index 3a113db81..cd73f18c9 100644 --- a/src/betterproto/__init__.py +++ b/src/betterproto/__init__.py @@ -1786,23 +1786,6 @@ def _validate_field_groups(cls, values): Message.__annotations__ = {} # HACK to avoid typing.get_type_hints breaking :) -# monkey patch (de-)serialization functions of class `Message` -# with functions from `betterproto-rust-codec` if available -try: - import betterproto_rust_codec - - def __parse_patch(self: T, data: bytes) -> T: - betterproto_rust_codec.deserialize(self, data) - return self - - def __bytes_patch(self) -> bytes: - return betterproto_rust_codec.serialize(self) - - Message.parse = __parse_patch - Message.__bytes__ = __bytes_patch -except ModuleNotFoundError: - pass - def which_one_of(message: Message, group_name: str) -> Tuple[str, Optional[Any]]: """ From f5a5c8c42ef7b74e23c9493542d68d8587525c1d Mon Sep 17 00:00:00 2001 From: Adrien Vannson Date: Tue, 12 Nov 2024 18:01:26 +0100 Subject: [PATCH 32/37] Mark messages as optional --- src/betterproto/__init__.py | 8 ++++---- src/betterproto/plugin/models.py | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/betterproto/__init__.py b/src/betterproto/__init__.py index cd73f18c9..3217f4c57 100644 --- a/src/betterproto/__init__.py +++ b/src/betterproto/__init__.py @@ -204,12 +204,12 @@ def dataclass_field( repeated: bool = False, ) -> dataclasses.Field: """Creates a dataclass field with attached protobuf metadata.""" - if optional or group: - def default_factory(): - return None - elif repeated: + if repeated: def default_factory(): return [] + elif optional or group: + def default_factory(): + return None return dataclasses.field( default_factory=default_factory, diff --git a/src/betterproto/plugin/models.py b/src/betterproto/plugin/models.py index 71e45205d..e2b9d97a4 100644 --- a/src/betterproto/plugin/models.py +++ b/src/betterproto/plugin/models.py @@ -504,7 +504,7 @@ def repeated(self) -> bool: @property def optional(self) -> bool: - return self.proto_obj.proto3_optional + return self.proto_obj.proto3_optional or self.field_type == "message" @property def field_type(self) -> str: From d4bd5118f73ac343ab94a69d605e9c8440829701 Mon Sep 17 00:00:00 2001 From: Adrien Vannson Date: Tue, 12 Nov 2024 18:08:09 +0100 Subject: [PATCH 33/37] Format the code --- poetry.lock | 895 +++++++++--------- pyproject.toml | 4 +- src/betterproto/__init__.py | 246 ++++- .../lib/pydantic/google/protobuf/__init__.py | 110 ++- .../lib/std/google/protobuf/__init__.py | 60 +- .../std/google/protobuf/compiler/__init__.py | 4 +- src/betterproto/plugin/main.py | 1 + src/betterproto/plugin/models.py | 11 +- tests/test_features.py | 4 +- tests/test_inputs.py | 1 - tests/test_oneof_pattern_matching.py | 4 +- 11 files changed, 826 insertions(+), 514 deletions(-) diff --git a/poetry.lock b/poetry.lock index 8f6d6635b..7476ee80f 100644 --- a/poetry.lock +++ b/poetry.lock @@ -120,33 +120,36 @@ files = [ [[package]] name = "black" -version = "24.8.0" +version = "23.1.0" description = "The uncompromising code formatter." optional = true -python-versions = ">=3.8" +python-versions = ">=3.7" files = [ - {file = "black-24.8.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:09cdeb74d494ec023ded657f7092ba518e8cf78fa8386155e4a03fdcc44679e6"}, - {file = "black-24.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:81c6742da39f33b08e791da38410f32e27d632260e599df7245cccee2064afeb"}, - {file = "black-24.8.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:707a1ca89221bc8a1a64fb5e15ef39cd755633daa672a9db7498d1c19de66a42"}, - {file = "black-24.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:d6417535d99c37cee4091a2f24eb2b6d5ec42b144d50f1f2e436d9fe1916fe1a"}, - {file = "black-24.8.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:fb6e2c0b86bbd43dee042e48059c9ad7830abd5c94b0bc518c0eeec57c3eddc1"}, - {file = "black-24.8.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:837fd281f1908d0076844bc2b801ad2d369c78c45cf800cad7b61686051041af"}, - {file = "black-24.8.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:62e8730977f0b77998029da7971fa896ceefa2c4c4933fcd593fa599ecbf97a4"}, - {file = "black-24.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:72901b4913cbac8972ad911dc4098d5753704d1f3c56e44ae8dce99eecb0e3af"}, - {file = "black-24.8.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:7c046c1d1eeb7aea9335da62472481d3bbf3fd986e093cffd35f4385c94ae368"}, - {file = "black-24.8.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:649f6d84ccbae73ab767e206772cc2d7a393a001070a4c814a546afd0d423aed"}, - {file = "black-24.8.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2b59b250fdba5f9a9cd9d0ece6e6d993d91ce877d121d161e4698af3eb9c1018"}, - {file = "black-24.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:6e55d30d44bed36593c3163b9bc63bf58b3b30e4611e4d88a0c3c239930ed5b2"}, - {file = "black-24.8.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:505289f17ceda596658ae81b61ebbe2d9b25aa78067035184ed0a9d855d18afd"}, - {file = "black-24.8.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:b19c9ad992c7883ad84c9b22aaa73562a16b819c1d8db7a1a1a49fb7ec13c7d2"}, - {file = "black-24.8.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1f13f7f386f86f8121d76599114bb8c17b69d962137fc70efe56137727c7047e"}, - {file = "black-24.8.0-cp38-cp38-win_amd64.whl", hash = "sha256:f490dbd59680d809ca31efdae20e634f3fae27fba3ce0ba3208333b713bc3920"}, - {file = "black-24.8.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:eab4dd44ce80dea27dc69db40dab62d4ca96112f87996bca68cd75639aeb2e4c"}, - {file = "black-24.8.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3c4285573d4897a7610054af5a890bde7c65cb466040c5f0c8b732812d7f0e5e"}, - {file = "black-24.8.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9e84e33b37be070ba135176c123ae52a51f82306def9f7d063ee302ecab2cf47"}, - {file = "black-24.8.0-cp39-cp39-win_amd64.whl", hash = "sha256:73bbf84ed136e45d451a260c6b73ed674652f90a2b3211d6a35e78054563a9bb"}, - {file = "black-24.8.0-py3-none-any.whl", hash = "sha256:972085c618ee94f402da1af548a4f218c754ea7e5dc70acb168bfaca4c2542ed"}, - {file = "black-24.8.0.tar.gz", hash = "sha256:2500945420b6784c38b9ee885af039f5e7471ef284ab03fa35ecdde4688cd83f"}, + {file = "black-23.1.0-cp310-cp310-macosx_10_16_arm64.whl", hash = "sha256:b6a92a41ee34b883b359998f0c8e6eb8e99803aa8bf3123bf2b2e6fec505a221"}, + {file = "black-23.1.0-cp310-cp310-macosx_10_16_universal2.whl", hash = "sha256:57c18c5165c1dbe291d5306e53fb3988122890e57bd9b3dcb75f967f13411a26"}, + {file = "black-23.1.0-cp310-cp310-macosx_10_16_x86_64.whl", hash = "sha256:9880d7d419bb7e709b37e28deb5e68a49227713b623c72b2b931028ea65f619b"}, + {file = "black-23.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e6663f91b6feca5d06f2ccd49a10f254f9298cc1f7f49c46e498a0771b507104"}, + {file = "black-23.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:9afd3f493666a0cd8f8df9a0200c6359ac53940cbde049dcb1a7eb6ee2dd7074"}, + {file = "black-23.1.0-cp311-cp311-macosx_10_16_arm64.whl", hash = "sha256:bfffba28dc52a58f04492181392ee380e95262af14ee01d4bc7bb1b1c6ca8d27"}, + {file = "black-23.1.0-cp311-cp311-macosx_10_16_universal2.whl", hash = "sha256:c1c476bc7b7d021321e7d93dc2cbd78ce103b84d5a4cf97ed535fbc0d6660648"}, + {file = "black-23.1.0-cp311-cp311-macosx_10_16_x86_64.whl", hash = "sha256:382998821f58e5c8238d3166c492139573325287820963d2f7de4d518bd76958"}, + {file = "black-23.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bf649fda611c8550ca9d7592b69f0637218c2369b7744694c5e4902873b2f3a"}, + {file = "black-23.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:121ca7f10b4a01fd99951234abdbd97728e1240be89fde18480ffac16503d481"}, + {file = "black-23.1.0-cp37-cp37m-macosx_10_16_x86_64.whl", hash = "sha256:a8471939da5e824b891b25751955be52ee7f8a30a916d570a5ba8e0f2eb2ecad"}, + {file = "black-23.1.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8178318cb74f98bc571eef19068f6ab5613b3e59d4f47771582f04e175570ed8"}, + {file = "black-23.1.0-cp37-cp37m-win_amd64.whl", hash = "sha256:a436e7881d33acaf2536c46a454bb964a50eff59b21b51c6ccf5a40601fbef24"}, + {file = "black-23.1.0-cp38-cp38-macosx_10_16_arm64.whl", hash = "sha256:a59db0a2094d2259c554676403fa2fac3473ccf1354c1c63eccf7ae65aac8ab6"}, + {file = "black-23.1.0-cp38-cp38-macosx_10_16_universal2.whl", hash = "sha256:0052dba51dec07ed029ed61b18183942043e00008ec65d5028814afaab9a22fd"}, + {file = "black-23.1.0-cp38-cp38-macosx_10_16_x86_64.whl", hash = "sha256:49f7b39e30f326a34b5c9a4213213a6b221d7ae9d58ec70df1c4a307cf2a1580"}, + {file = "black-23.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:162e37d49e93bd6eb6f1afc3e17a3d23a823042530c37c3c42eeeaf026f38468"}, + {file = "black-23.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:8b70eb40a78dfac24842458476135f9b99ab952dd3f2dab738c1881a9b38b753"}, + {file = "black-23.1.0-cp39-cp39-macosx_10_16_arm64.whl", hash = "sha256:a29650759a6a0944e7cca036674655c2f0f63806ddecc45ed40b7b8aa314b651"}, + {file = "black-23.1.0-cp39-cp39-macosx_10_16_universal2.whl", hash = "sha256:bb460c8561c8c1bec7824ecbc3ce085eb50005883a6203dcfb0122e95797ee06"}, + {file = "black-23.1.0-cp39-cp39-macosx_10_16_x86_64.whl", hash = "sha256:c91dfc2c2a4e50df0026f88d2215e166616e0c80e86004d0003ece0488db2739"}, + {file = "black-23.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2a951cc83ab535d248c89f300eccbd625e80ab880fbcfb5ac8afb5f01a258ac9"}, + {file = "black-23.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:0680d4380db3719ebcfb2613f34e86c8e6d15ffeabcf8ec59355c5e7b85bb555"}, + {file = "black-23.1.0-py3-none-any.whl", hash = "sha256:7a0f701d314cfa0896b9001df70a530eb2472babb76086344e688829efd97d32"}, + {file = "black-23.1.0.tar.gz", hash = "sha256:b0bd97bea8903f5a2ba7219257a44e3f1f9d00073d6cc1add68f0beec69692ac"}, ] [package.dependencies] @@ -156,11 +159,11 @@ packaging = ">=22.0" pathspec = ">=0.9.0" platformdirs = ">=2" tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} -typing-extensions = {version = ">=4.0.1", markers = "python_version < \"3.11\""} +typing-extensions = {version = ">=3.10.0.0", markers = "python_version < \"3.10\""} [package.extras] colorama = ["colorama (>=0.4.3)"] -d = ["aiohttp (>=3.7.4)", "aiohttp (>=3.7.4,!=3.9.0)"] +d = ["aiohttp (>=3.7.4)"] jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] uvloop = ["uvloop (>=0.15.2)"] @@ -260,101 +263,116 @@ files = [ [[package]] name = "charset-normalizer" -version = "3.3.2" +version = "3.4.0" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." optional = false python-versions = ">=3.7.0" files = [ - {file = "charset-normalizer-3.3.2.tar.gz", hash = "sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-win32.whl", hash = "sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-win32.whl", hash = "sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-win32.whl", hash = "sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:95f2a5796329323b8f0512e09dbb7a1860c46a39da62ecb2324f116fa8fdc85c"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c002b4ffc0be611f0d9da932eb0f704fe2602a9a949d1f738e4c34c75b0863d5"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a981a536974bbc7a512cf44ed14938cf01030a99e9b3a06dd59578882f06f985"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3287761bc4ee9e33561a7e058c72ac0938c4f57fe49a09eae428fd88aafe7bb6"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42cb296636fcc8b0644486d15c12376cb9fa75443e00fb25de0b8602e64c1714"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a55554a2fa0d408816b3b5cedf0045f4b8e1a6065aec45849de2d6f3f8e9786"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:c083af607d2515612056a31f0a8d9e0fcb5876b7bfc0abad3ecd275bc4ebc2d5"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:87d1351268731db79e0f8e745d92493ee2841c974128ef629dc518b937d9194c"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:bd8f7df7d12c2db9fab40bdd87a7c09b1530128315d047a086fa3ae3435cb3a8"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:c180f51afb394e165eafe4ac2936a14bee3eb10debc9d9e4db8958fe36afe711"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:8c622a5fe39a48f78944a87d4fb8a53ee07344641b0562c540d840748571b811"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-win32.whl", hash = "sha256:db364eca23f876da6f9e16c9da0df51aa4f104a972735574842618b8c6d999d4"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-win_amd64.whl", hash = "sha256:86216b5cee4b06df986d214f664305142d9c76df9b6512be2738aa72a2048f99"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:6463effa3186ea09411d50efc7d85360b38d5f09b870c48e4600f63af490e56a"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6c4caeef8fa63d06bd437cd4bdcf3ffefe6738fb1b25951440d80dc7df8c03ac"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:37e55c8e51c236f95b033f6fb391d7d7970ba5fe7ff453dad675e88cf303377a"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb69256e180cb6c8a894fee62b3afebae785babc1ee98b81cdf68bbca1987f33"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ae5f4161f18c61806f411a13b0310bea87f987c7d2ecdbdaad0e94eb2e404238"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b2b0a0c0517616b6869869f8c581d4eb2dd83a4d79e0ebcb7d373ef9956aeb0a"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:45485e01ff4d3630ec0d9617310448a8702f70e9c01906b0d0118bdf9d124cf2"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eb00ed941194665c332bf8e078baf037d6c35d7c4f3102ea2d4f16ca94a26dc8"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:2127566c664442652f024c837091890cb1942c30937add288223dc895793f898"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a50aebfa173e157099939b17f18600f72f84eed3049e743b68ad15bd69b6bf99"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:4d0d1650369165a14e14e1e47b372cfcb31d6ab44e6e33cb2d4e57265290044d"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:923c0c831b7cfcb071580d3f46c4baf50f174be571576556269530f4bbd79d04"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-win32.whl", hash = "sha256:6ef1d82a3af9d3eecdba2321dc1b3c238245d890843e040e41e470ffa64c3e25"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-win_amd64.whl", hash = "sha256:eb8821e09e916165e160797a6c17edda0679379a4be5c716c260e836e122f54b"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c235ebd9baae02f1b77bcea61bce332cb4331dc3617d254df3323aa01ab47bd4"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5b4c145409bef602a690e7cfad0a15a55c13320ff7a3ad7ca59c13bb8ba4d45d"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:68d1f8a9e9e37c1223b656399be5d6b448dea850bed7d0f87a8311f1ff3dabb0"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22afcb9f253dac0696b5a4be4a1c0f8762f8239e21b99680099abd9b2b1b2269"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e27ad930a842b4c5eb8ac0016b0a54f5aebbe679340c26101df33424142c143c"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1f79682fbe303db92bc2b1136016a38a42e835d932bab5b3b1bfcfbf0640e519"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b261ccdec7821281dade748d088bb6e9b69e6d15b30652b74cbbac25e280b796"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:122c7fa62b130ed55f8f285bfd56d5f4b4a5b503609d181f9ad85e55c89f4185"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d0eccceffcb53201b5bfebb52600a5fb483a20b61da9dbc885f8b103cbe7598c"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9f96df6923e21816da7e0ad3fd47dd8f94b2a5ce594e00677c0013018b813458"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:7f04c839ed0b6b98b1a7501a002144b76c18fb1c1850c8b98d458ac269e26ed2"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:34d1c8da1e78d2e001f363791c98a272bb734000fcef47a491c1e3b0505657a8"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-win32.whl", hash = "sha256:aed38f6e4fb3f5d6bf81bfa990a07806be9d83cf7bacef998ab1a9bd660a581f"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d"}, - {file = "charset_normalizer-3.3.2-py3-none-any.whl", hash = "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:4f9fc98dad6c2eaa32fc3af1417d95b5e3d08aff968df0cd320066def971f9a6"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0de7b687289d3c1b3e8660d0741874abe7888100efe14bd0f9fd7141bcbda92b"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5ed2e36c3e9b4f21dd9422f6893dec0abf2cca553af509b10cd630f878d3eb99"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:40d3ff7fc90b98c637bda91c89d51264a3dcf210cade3a2c6f838c7268d7a4ca"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1110e22af8ca26b90bd6364fe4c763329b0ebf1ee213ba32b68c73de5752323d"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:86f4e8cca779080f66ff4f191a685ced73d2f72d50216f7112185dc02b90b9b7"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f683ddc7eedd742e2889d2bfb96d69573fde1d92fcb811979cdb7165bb9c7d3"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:27623ba66c183eca01bf9ff833875b459cad267aeeb044477fedac35e19ba907"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f606a1881d2663630ea5b8ce2efe2111740df4b687bd78b34a8131baa007f79b"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:0b309d1747110feb25d7ed6b01afdec269c647d382c857ef4663bbe6ad95a912"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:136815f06a3ae311fae551c3df1f998a1ebd01ddd424aa5603a4336997629e95"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:14215b71a762336254351b00ec720a8e85cada43b987da5a042e4ce3e82bd68e"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:79983512b108e4a164b9c8d34de3992f76d48cadc9554c9e60b43f308988aabe"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-win32.whl", hash = "sha256:c94057af19bc953643a33581844649a7fdab902624d2eb739738a30e2b3e60fc"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:55f56e2ebd4e3bc50442fbc0888c9d8c94e4e06a933804e2af3e89e2f9c1c749"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0d99dd8ff461990f12d6e42c7347fd9ab2532fb70e9621ba520f9e8637161d7c"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c57516e58fd17d03ebe67e181a4e4e2ccab1168f8c2976c6a334d4f819fe5944"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6dba5d19c4dfab08e58d5b36304b3f92f3bd5d42c1a3fa37b5ba5cdf6dfcbcee"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf4475b82be41b07cc5e5ff94810e6a01f276e37c2d55571e3fe175e467a1a1c"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ce031db0408e487fd2775d745ce30a7cd2923667cf3b69d48d219f1d8f5ddeb6"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8ff4e7cdfdb1ab5698e675ca622e72d58a6fa2a8aa58195de0c0061288e6e3ea"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3710a9751938947e6327ea9f3ea6332a09bf0ba0c09cae9cb1f250bd1f1549bc"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:82357d85de703176b5587dbe6ade8ff67f9f69a41c0733cf2425378b49954de5"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:47334db71978b23ebcf3c0f9f5ee98b8d65992b65c9c4f2d34c2eaf5bcaf0594"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:8ce7fd6767a1cc5a92a639b391891bf1c268b03ec7e021c7d6d902285259685c"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:f1a2f519ae173b5b6a2c9d5fa3116ce16e48b3462c8b96dfdded11055e3d6365"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:63bc5c4ae26e4bc6be6469943b8253c0fd4e4186c43ad46e713ea61a0ba49129"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:bcb4f8ea87d03bc51ad04add8ceaf9b0f085ac045ab4d74e73bbc2dc033f0236"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-win32.whl", hash = "sha256:9ae4ef0b3f6b41bad6366fb0ea4fc1d7ed051528e113a60fa2a65a9abb5b1d99"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:cee4373f4d3ad28f1ab6290684d8e2ebdb9e7a1b74fdc39e4c211995f77bec27"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0713f3adb9d03d49d365b70b84775d0a0d18e4ab08d12bc46baa6132ba78aaf6"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:de7376c29d95d6719048c194a9cf1a1b0393fbe8488a22008610b0361d834ecf"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4a51b48f42d9358460b78725283f04bddaf44a9358197b889657deba38f329db"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b295729485b06c1a0683af02a9e42d2caa9db04a373dc38a6a58cdd1e8abddf1"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ee803480535c44e7f5ad00788526da7d85525cfefaf8acf8ab9a310000be4b03"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3d59d125ffbd6d552765510e3f31ed75ebac2c7470c7274195b9161a32350284"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8cda06946eac330cbe6598f77bb54e690b4ca93f593dee1568ad22b04f347c15"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07afec21bbbbf8a5cc3651aa96b980afe2526e7f048fdfb7f1014d84acc8b6d8"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6b40e8d38afe634559e398cc32b1472f376a4099c75fe6299ae607e404c033b2"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b8dcd239c743aa2f9c22ce674a145e0a25cb1566c495928440a181ca1ccf6719"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:84450ba661fb96e9fd67629b93d2941c871ca86fc38d835d19d4225ff946a631"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:44aeb140295a2f0659e113b31cfe92c9061622cadbc9e2a2f7b8ef6b1e29ef4b"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1db4e7fefefd0f548d73e2e2e041f9df5c59e178b4c72fbac4cc6f535cfb1565"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-win32.whl", hash = "sha256:5726cf76c982532c1863fb64d8c6dd0e4c90b6ece9feb06c9f202417a31f7dd7"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:b197e7094f232959f8f20541ead1d9862ac5ebea1d58e9849c1bf979255dfac9"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:dd4eda173a9fcccb5f2e2bd2a9f423d180194b1bf17cf59e3269899235b2a114"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e9e3c4c9e1ed40ea53acf11e2a386383c3304212c965773704e4603d589343ed"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:92a7e36b000bf022ef3dbb9c46bfe2d52c047d5e3f3343f43204263c5addc250"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:54b6a92d009cbe2fb11054ba694bc9e284dad30a26757b1e372a1fdddaf21920"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ffd9493de4c922f2a38c2bf62b831dcec90ac673ed1ca182fe11b4d8e9f2a64"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:35c404d74c2926d0287fbd63ed5d27eb911eb9e4a3bb2c6d294f3cfd4a9e0c23"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4796efc4faf6b53a18e3d46343535caed491776a22af773f366534056c4e1fbc"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e7fdd52961feb4c96507aa649550ec2a0d527c086d284749b2f582f2d40a2e0d"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:92db3c28b5b2a273346bebb24857fda45601aef6ae1c011c0a997106581e8a88"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ab973df98fc99ab39080bfb0eb3a925181454d7c3ac8a1e695fddfae696d9e90"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:4b67fdab07fdd3c10bb21edab3cbfe8cf5696f453afce75d815d9d7223fbe88b"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:aa41e526a5d4a9dfcfbab0716c7e8a1b215abd3f3df5a45cf18a12721d31cb5d"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ffc519621dce0c767e96b9c53f09c5d215578e10b02c285809f76509a3931482"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-win32.whl", hash = "sha256:f19c1585933c82098c2a520f8ec1227f20e339e33aca8fa6f956f6691b784e67"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:707b82d19e65c9bd28b81dde95249b07bf9f5b90ebe1ef17d9b57473f8a64b7b"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:dbe03226baf438ac4fda9e2d0715022fd579cb641c4cf639fa40d53b2fe6f3e2"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dd9a8bd8900e65504a305bf8ae6fa9fbc66de94178c420791d0293702fce2df7"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b8831399554b92b72af5932cdbbd4ddc55c55f631bb13ff8fe4e6536a06c5c51"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a14969b8691f7998e74663b77b4c36c0337cb1df552da83d5c9004a93afdb574"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dcaf7c1524c0542ee2fc82cc8ec337f7a9f7edee2532421ab200d2b920fc97cf"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:425c5f215d0eecee9a56cdb703203dda90423247421bf0d67125add85d0c4455"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:d5b054862739d276e09928de37c79ddeec42a6e1bfc55863be96a36ba22926f6"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_i686.whl", hash = "sha256:f3e73a4255342d4eb26ef6df01e3962e73aa29baa3124a8e824c5d3364a65748"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_ppc64le.whl", hash = "sha256:2f6c34da58ea9c1a9515621f4d9ac379871a8f21168ba1b5e09d74250de5ad62"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_s390x.whl", hash = "sha256:f09cb5a7bbe1ecae6e87901a2eb23e0256bb524a79ccc53eb0b7629fbe7677c4"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:0099d79bdfcf5c1f0c2c72f91516702ebf8b0b8ddd8905f97a8aecf49712c621"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-win32.whl", hash = "sha256:9c98230f5042f4945f957d006edccc2af1e03ed5e37ce7c373f00a5a4daa6149"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-win_amd64.whl", hash = "sha256:62f60aebecfc7f4b82e3f639a7d1433a20ec32824db2199a11ad4f5e146ef5ee"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:af73657b7a68211996527dbfeffbb0864e043d270580c5aef06dc4b659a4b578"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:cab5d0b79d987c67f3b9e9c53f54a61360422a5a0bc075f43cab5621d530c3b6"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:9289fd5dddcf57bab41d044f1756550f9e7cf0c8e373b8cdf0ce8773dc4bd417"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6b493a043635eb376e50eedf7818f2f322eabbaa974e948bd8bdd29eb7ef2a51"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9fa2566ca27d67c86569e8c85297aaf413ffab85a8960500f12ea34ff98e4c41"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a8e538f46104c815be19c975572d74afb53f29650ea2025bbfaef359d2de2f7f"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6fd30dc99682dc2c603c2b315bded2799019cea829f8bf57dc6b61efde6611c8"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2006769bd1640bdf4d5641c69a3d63b71b81445473cac5ded39740a226fa88ab"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:dc15e99b2d8a656f8e666854404f1ba54765871104e50c8e9813af8a7db07f12"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:ab2e5bef076f5a235c3774b4f4028a680432cded7cad37bba0fd90d64b187d19"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:4ec9dd88a5b71abfc74e9df5ebe7921c35cbb3b641181a531ca65cdb5e8e4dea"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:43193c5cda5d612f247172016c4bb71251c784d7a4d9314677186a838ad34858"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:aa693779a8b50cd97570e5a0f343538a8dbd3e496fa5dcb87e29406ad0299654"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-win32.whl", hash = "sha256:7706f5850360ac01d80c89bcef1640683cc12ed87f42579dab6c5d3ed6888613"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:c3e446d253bd88f6377260d07c895816ebf33ffffd56c1c792b13bff9c3e1ade"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:980b4f289d1d90ca5efcf07958d3eb38ed9c0b7676bf2831a54d4f66f9c27dfa"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f28f891ccd15c514a0981f3b9db9aa23d62fe1a99997512b0491d2ed323d229a"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a8aacce6e2e1edcb6ac625fb0f8c3a9570ccc7bfba1f63419b3769ccf6a00ed0"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd7af3717683bea4c87acd8c0d3d5b44d56120b26fd3f8a692bdd2d5260c620a"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5ff2ed8194587faf56555927b3aa10e6fb69d931e33953943bc4f837dfee2242"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e91f541a85298cf35433bf66f3fab2a4a2cff05c127eeca4af174f6d497f0d4b"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:309a7de0a0ff3040acaebb35ec45d18db4b28232f21998851cfa709eeff49d62"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:285e96d9d53422efc0d7a17c60e59f37fbf3dfa942073f666db4ac71e8d726d0"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:5d447056e2ca60382d460a604b6302d8db69476fd2015c81e7c35417cfabe4cd"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:20587d20f557fe189b7947d8e7ec5afa110ccf72a3128d61a2a387c3313f46be"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:130272c698667a982a5d0e626851ceff662565379baf0ff2cc58067b81d4f11d"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:ab22fbd9765e6954bc0bcff24c25ff71dcbfdb185fcdaca49e81bac68fe724d3"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:7782afc9b6b42200f7362858f9e73b1f8316afb276d316336c0ec3bd73312742"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-win32.whl", hash = "sha256:2de62e8801ddfff069cd5c504ce3bc9672b23266597d4e4f50eda28846c322f2"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-win_amd64.whl", hash = "sha256:95c3c157765b031331dd4db3c775e58deaee050a3042fcad72cbc4189d7c8dca"}, + {file = "charset_normalizer-3.4.0-py3-none-any.whl", hash = "sha256:fe9f97feb71aa9896b81973a7bbada8c49501dc73e58a10fcef6663af95e5079"}, + {file = "charset_normalizer-3.4.0.tar.gz", hash = "sha256:223217c3d4f82c3ac5e29032b3f1c2eb0fb591b72161f86d93f5719079dae93e"}, ] [[package]] @@ -528,13 +546,13 @@ files = [ [[package]] name = "distlib" -version = "0.3.8" +version = "0.3.9" description = "Distribution utilities" optional = false python-versions = "*" files = [ - {file = "distlib-0.3.8-py2.py3-none-any.whl", hash = "sha256:034db59a0b96f8ca18035f36290806a9a6e6bd9d1ff91e45a7f172eb17e51784"}, - {file = "distlib-0.3.8.tar.gz", hash = "sha256:1530ea13e350031b6312d8580ddb6b27a104275a31106523b8f123787f494f64"}, + {file = "distlib-0.3.9-py2.py3-none-any.whl", hash = "sha256:47f8c22fd27c27e25a65601af709b38e4f0a45ea4fc2e710f65755fa8caaaf87"}, + {file = "distlib-0.3.9.tar.gz", hash = "sha256:a60f20dea646b8a33f3e7772f74dc0b2d0772d2837ee1342a00645c81edf9403"}, ] [[package]] @@ -547,93 +565,100 @@ files = [] [[package]] name = "filelock" -version = "3.16.0" +version = "3.16.1" description = "A platform independent file lock." optional = false python-versions = ">=3.8" files = [ - {file = "filelock-3.16.0-py3-none-any.whl", hash = "sha256:f6ed4c963184f4c84dd5557ce8fece759a3724b37b80c6c4f20a2f63a4dc6609"}, - {file = "filelock-3.16.0.tar.gz", hash = "sha256:81de9eb8453c769b63369f87f11131a7ab04e367f8d97ad39dc230daa07e3bec"}, + {file = "filelock-3.16.1-py3-none-any.whl", hash = "sha256:2082e5703d51fbf98ea75855d9d5527e33d8ff23099bec374a134febee6946b0"}, + {file = "filelock-3.16.1.tar.gz", hash = "sha256:c249fbfcd5db47e5e2d6d62198e565475ee65e4831e2561c8e313fa7eb961435"}, ] [package.extras] -docs = ["furo (>=2024.8.6)", "sphinx (>=8.0.2)", "sphinx-autodoc-typehints (>=2.4)"] -testing = ["covdefaults (>=2.3)", "coverage (>=7.6.1)", "diff-cover (>=9.1.1)", "pytest (>=8.3.2)", "pytest-asyncio (>=0.24)", "pytest-cov (>=5)", "pytest-mock (>=3.14)", "pytest-timeout (>=2.3.1)", "virtualenv (>=20.26.3)"] +docs = ["furo (>=2024.8.6)", "sphinx (>=8.0.2)", "sphinx-autodoc-typehints (>=2.4.1)"] +testing = ["covdefaults (>=2.3)", "coverage (>=7.6.1)", "diff-cover (>=9.2)", "pytest (>=8.3.3)", "pytest-asyncio (>=0.24)", "pytest-cov (>=5)", "pytest-mock (>=3.14)", "pytest-timeout (>=2.3.1)", "virtualenv (>=20.26.4)"] typing = ["typing-extensions (>=4.12.2)"] [[package]] name = "greenlet" -version = "3.1.0" +version = "3.1.1" description = "Lightweight in-process concurrent programming" optional = false python-versions = ">=3.7" files = [ - {file = "greenlet-3.1.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a814dc3100e8a046ff48faeaa909e80cdb358411a3d6dd5293158425c684eda8"}, - {file = "greenlet-3.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a771dc64fa44ebe58d65768d869fcfb9060169d203446c1d446e844b62bdfdca"}, - {file = "greenlet-3.1.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0e49a65d25d7350cca2da15aac31b6f67a43d867448babf997fe83c7505f57bc"}, - {file = "greenlet-3.1.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2cd8518eade968bc52262d8c46727cfc0826ff4d552cf0430b8d65aaf50bb91d"}, - {file = "greenlet-3.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:76dc19e660baea5c38e949455c1181bc018893f25372d10ffe24b3ed7341fb25"}, - {file = "greenlet-3.1.0-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c0a5b1c22c82831f56f2f7ad9bbe4948879762fe0d59833a4a71f16e5fa0f682"}, - {file = "greenlet-3.1.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:2651dfb006f391bcb240635079a68a261b227a10a08af6349cba834a2141efa1"}, - {file = "greenlet-3.1.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:3e7e6ef1737a819819b1163116ad4b48d06cfdd40352d813bb14436024fcda99"}, - {file = "greenlet-3.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:ffb08f2a1e59d38c7b8b9ac8083c9c8b9875f0955b1e9b9b9a965607a51f8e54"}, - {file = "greenlet-3.1.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9730929375021ec90f6447bff4f7f5508faef1c02f399a1953870cdb78e0c345"}, - {file = "greenlet-3.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:713d450cf8e61854de9420fb7eea8ad228df4e27e7d4ed465de98c955d2b3fa6"}, - {file = "greenlet-3.1.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4c3446937be153718250fe421da548f973124189f18fe4575a0510b5c928f0cc"}, - {file = "greenlet-3.1.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1ddc7bcedeb47187be74208bc652d63d6b20cb24f4e596bd356092d8000da6d6"}, - {file = "greenlet-3.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:44151d7b81b9391ed759a2f2865bbe623ef00d648fed59363be2bbbd5154656f"}, - {file = "greenlet-3.1.0-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6cea1cca3be76c9483282dc7760ea1cc08a6ecec1f0b6ca0a94ea0d17432da19"}, - {file = "greenlet-3.1.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:619935a44f414274a2c08c9e74611965650b730eb4efe4b2270f91df5e4adf9a"}, - {file = "greenlet-3.1.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:221169d31cada333a0c7fd087b957c8f431c1dba202c3a58cf5a3583ed973e9b"}, - {file = "greenlet-3.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:01059afb9b178606b4b6e92c3e710ea1635597c3537e44da69f4531e111dd5e9"}, - {file = "greenlet-3.1.0-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:24fc216ec7c8be9becba8b64a98a78f9cd057fd2dc75ae952ca94ed8a893bf27"}, - {file = "greenlet-3.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3d07c28b85b350564bdff9f51c1c5007dfb2f389385d1bc23288de51134ca303"}, - {file = "greenlet-3.1.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:243a223c96a4246f8a30ea470c440fe9db1f5e444941ee3c3cd79df119b8eebf"}, - {file = "greenlet-3.1.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:26811df4dc81271033a7836bc20d12cd30938e6bd2e9437f56fa03da81b0f8fc"}, - {file = "greenlet-3.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c9d86401550b09a55410f32ceb5fe7efcd998bd2dad9e82521713cb148a4a15f"}, - {file = "greenlet-3.1.0-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:26d9c1c4f1748ccac0bae1dbb465fb1a795a75aba8af8ca871503019f4285e2a"}, - {file = "greenlet-3.1.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:cd468ec62257bb4544989402b19d795d2305eccb06cde5da0eb739b63dc04665"}, - {file = "greenlet-3.1.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a53dfe8f82b715319e9953330fa5c8708b610d48b5c59f1316337302af5c0811"}, - {file = "greenlet-3.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:28fe80a3eb673b2d5cc3b12eea468a5e5f4603c26aa34d88bf61bba82ceb2f9b"}, - {file = "greenlet-3.1.0-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:76b3e3976d2a452cba7aa9e453498ac72240d43030fdc6d538a72b87eaff52fd"}, - {file = "greenlet-3.1.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:655b21ffd37a96b1e78cc48bf254f5ea4b5b85efaf9e9e2a526b3c9309d660ca"}, - {file = "greenlet-3.1.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c6f4c2027689093775fd58ca2388d58789009116844432d920e9147f91acbe64"}, - {file = "greenlet-3.1.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:76e5064fd8e94c3f74d9fd69b02d99e3cdb8fc286ed49a1f10b256e59d0d3a0b"}, - {file = "greenlet-3.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6a4bf607f690f7987ab3291406e012cd8591a4f77aa54f29b890f9c331e84989"}, - {file = "greenlet-3.1.0-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:037d9ac99540ace9424cb9ea89f0accfaff4316f149520b4ae293eebc5bded17"}, - {file = "greenlet-3.1.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:90b5bbf05fe3d3ef697103850c2ce3374558f6fe40fd57c9fac1bf14903f50a5"}, - {file = "greenlet-3.1.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:726377bd60081172685c0ff46afbc600d064f01053190e4450857483c4d44484"}, - {file = "greenlet-3.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:d46d5069e2eeda111d6f71970e341f4bd9aeeee92074e649ae263b834286ecc0"}, - {file = "greenlet-3.1.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:81eeec4403a7d7684b5812a8aaa626fa23b7d0848edb3a28d2eb3220daddcbd0"}, - {file = "greenlet-3.1.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4a3dae7492d16e85ea6045fd11cb8e782b63eac8c8d520c3a92c02ac4573b0a6"}, - {file = "greenlet-3.1.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4b5ea3664eed571779403858d7cd0a9b0ebf50d57d2cdeafc7748e09ef8cd81a"}, - {file = "greenlet-3.1.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a22f4e26400f7f48faef2d69c20dc055a1f3043d330923f9abe08ea0aecc44df"}, - {file = "greenlet-3.1.0-cp37-cp37m-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:13ff8c8e54a10472ce3b2a2da007f915175192f18e6495bad50486e87c7f6637"}, - {file = "greenlet-3.1.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:f9671e7282d8c6fcabc32c0fb8d7c0ea8894ae85cee89c9aadc2d7129e1a9954"}, - {file = "greenlet-3.1.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:184258372ae9e1e9bddce6f187967f2e08ecd16906557c4320e3ba88a93438c3"}, - {file = "greenlet-3.1.0-cp37-cp37m-win32.whl", hash = "sha256:a0409bc18a9f85321399c29baf93545152d74a49d92f2f55302f122007cfda00"}, - {file = "greenlet-3.1.0-cp37-cp37m-win_amd64.whl", hash = "sha256:9eb4a1d7399b9f3c7ac68ae6baa6be5f9195d1d08c9ddc45ad559aa6b556bce6"}, - {file = "greenlet-3.1.0-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:a8870983af660798dc1b529e1fd6f1cefd94e45135a32e58bd70edd694540f33"}, - {file = "greenlet-3.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cfcfb73aed40f550a57ea904629bdaf2e562c68fa1164fa4588e752af6efdc3f"}, - {file = "greenlet-3.1.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f9482c2ed414781c0af0b35d9d575226da6b728bd1a720668fa05837184965b7"}, - {file = "greenlet-3.1.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d58ec349e0c2c0bc6669bf2cd4982d2f93bf067860d23a0ea1fe677b0f0b1e09"}, - {file = "greenlet-3.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd65695a8df1233309b701dec2539cc4b11e97d4fcc0f4185b4a12ce54db0491"}, - {file = "greenlet-3.1.0-cp38-cp38-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:665b21e95bc0fce5cab03b2e1d90ba9c66c510f1bb5fdc864f3a377d0f553f6b"}, - {file = "greenlet-3.1.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:d3c59a06c2c28a81a026ff11fbf012081ea34fb9b7052f2ed0366e14896f0a1d"}, - {file = "greenlet-3.1.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:5415b9494ff6240b09af06b91a375731febe0090218e2898d2b85f9b92abcda0"}, - {file = "greenlet-3.1.0-cp38-cp38-win32.whl", hash = "sha256:1544b8dd090b494c55e60c4ff46e238be44fdc472d2589e943c241e0169bcea2"}, - {file = "greenlet-3.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:7f346d24d74c00b6730440f5eb8ec3fe5774ca8d1c9574e8e57c8671bb51b910"}, - {file = "greenlet-3.1.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:db1b3ccb93488328c74e97ff888604a8b95ae4f35f4f56677ca57a4fc3a4220b"}, - {file = "greenlet-3.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:44cd313629ded43bb3b98737bba2f3e2c2c8679b55ea29ed73daea6b755fe8e7"}, - {file = "greenlet-3.1.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fad7a051e07f64e297e6e8399b4d6a3bdcad3d7297409e9a06ef8cbccff4f501"}, - {file = "greenlet-3.1.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c3967dcc1cd2ea61b08b0b276659242cbce5caca39e7cbc02408222fb9e6ff39"}, - {file = "greenlet-3.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d45b75b0f3fd8d99f62eb7908cfa6d727b7ed190737dec7fe46d993da550b81a"}, - {file = "greenlet-3.1.0-cp39-cp39-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2d004db911ed7b6218ec5c5bfe4cf70ae8aa2223dffbb5b3c69e342bb253cb28"}, - {file = "greenlet-3.1.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b9505a0c8579899057cbefd4ec34d865ab99852baf1ff33a9481eb3924e2da0b"}, - {file = "greenlet-3.1.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5fd6e94593f6f9714dbad1aaba734b5ec04593374fa6638df61592055868f8b8"}, - {file = "greenlet-3.1.0-cp39-cp39-win32.whl", hash = "sha256:d0dd943282231480aad5f50f89bdf26690c995e8ff555f26d8a5b9887b559bcc"}, - {file = "greenlet-3.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:ac0adfdb3a21dc2a24ed728b61e72440d297d0fd3a577389df566651fcd08f97"}, - {file = "greenlet-3.1.0.tar.gz", hash = "sha256:b395121e9bbe8d02a750886f108d540abe66075e61e22f7353d9acb0b81be0f0"}, + {file = "greenlet-3.1.1-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:0bbae94a29c9e5c7e4a2b7f0aae5c17e8e90acbfd3bf6270eeba60c39fce3563"}, + {file = "greenlet-3.1.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0fde093fb93f35ca72a556cf72c92ea3ebfda3d79fc35bb19fbe685853869a83"}, + {file = "greenlet-3.1.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:36b89d13c49216cadb828db8dfa6ce86bbbc476a82d3a6c397f0efae0525bdd0"}, + {file = "greenlet-3.1.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:94b6150a85e1b33b40b1464a3f9988dcc5251d6ed06842abff82e42632fac120"}, + {file = "greenlet-3.1.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:93147c513fac16385d1036b7e5b102c7fbbdb163d556b791f0f11eada7ba65dc"}, + {file = "greenlet-3.1.1-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:da7a9bff22ce038e19bf62c4dd1ec8391062878710ded0a845bcf47cc0200617"}, + {file = "greenlet-3.1.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:b2795058c23988728eec1f36a4e5e4ebad22f8320c85f3587b539b9ac84128d7"}, + {file = "greenlet-3.1.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:ed10eac5830befbdd0c32f83e8aa6288361597550ba669b04c48f0f9a2c843c6"}, + {file = "greenlet-3.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:77c386de38a60d1dfb8e55b8c1101d68c79dfdd25c7095d51fec2dd800892b80"}, + {file = "greenlet-3.1.1-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:e4d333e558953648ca09d64f13e6d8f0523fa705f51cae3f03b5983489958c70"}, + {file = "greenlet-3.1.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:09fc016b73c94e98e29af67ab7b9a879c307c6731a2c9da0db5a7d9b7edd1159"}, + {file = "greenlet-3.1.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d5e975ca70269d66d17dd995dafc06f1b06e8cb1ec1e9ed54c1d1e4a7c4cf26e"}, + {file = "greenlet-3.1.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3b2813dc3de8c1ee3f924e4d4227999285fd335d1bcc0d2be6dc3f1f6a318ec1"}, + {file = "greenlet-3.1.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e347b3bfcf985a05e8c0b7d462ba6f15b1ee1c909e2dcad795e49e91b152c383"}, + {file = "greenlet-3.1.1-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9e8f8c9cb53cdac7ba9793c276acd90168f416b9ce36799b9b885790f8ad6c0a"}, + {file = "greenlet-3.1.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:62ee94988d6b4722ce0028644418d93a52429e977d742ca2ccbe1c4f4a792511"}, + {file = "greenlet-3.1.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:1776fd7f989fc6b8d8c8cb8da1f6b82c5814957264d1f6cf818d475ec2bf6395"}, + {file = "greenlet-3.1.1-cp311-cp311-win_amd64.whl", hash = "sha256:48ca08c771c268a768087b408658e216133aecd835c0ded47ce955381105ba39"}, + {file = "greenlet-3.1.1-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:4afe7ea89de619adc868e087b4d2359282058479d7cfb94970adf4b55284574d"}, + {file = "greenlet-3.1.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f406b22b7c9a9b4f8aa9d2ab13d6ae0ac3e85c9a809bd590ad53fed2bf70dc79"}, + {file = "greenlet-3.1.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c3a701fe5a9695b238503ce5bbe8218e03c3bcccf7e204e455e7462d770268aa"}, + {file = "greenlet-3.1.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2846930c65b47d70b9d178e89c7e1a69c95c1f68ea5aa0a58646b7a96df12441"}, + {file = "greenlet-3.1.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:99cfaa2110534e2cf3ba31a7abcac9d328d1d9f1b95beede58294a60348fba36"}, + {file = "greenlet-3.1.1-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1443279c19fca463fc33e65ef2a935a5b09bb90f978beab37729e1c3c6c25fe9"}, + {file = "greenlet-3.1.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:b7cede291382a78f7bb5f04a529cb18e068dd29e0fb27376074b6d0317bf4dd0"}, + {file = "greenlet-3.1.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:23f20bb60ae298d7d8656c6ec6db134bca379ecefadb0b19ce6f19d1f232a942"}, + {file = "greenlet-3.1.1-cp312-cp312-win_amd64.whl", hash = "sha256:7124e16b4c55d417577c2077be379514321916d5790fa287c9ed6f23bd2ffd01"}, + {file = "greenlet-3.1.1-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:05175c27cb459dcfc05d026c4232f9de8913ed006d42713cb8a5137bd49375f1"}, + {file = "greenlet-3.1.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:935e943ec47c4afab8965954bf49bfa639c05d4ccf9ef6e924188f762145c0ff"}, + {file = "greenlet-3.1.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:667a9706c970cb552ede35aee17339a18e8f2a87a51fba2ed39ceeeb1004798a"}, + {file = "greenlet-3.1.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b8a678974d1f3aa55f6cc34dc480169d58f2e6d8958895d68845fa4ab566509e"}, + {file = "greenlet-3.1.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:efc0f674aa41b92da8c49e0346318c6075d734994c3c4e4430b1c3f853e498e4"}, + {file = "greenlet-3.1.1-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0153404a4bb921f0ff1abeb5ce8a5131da56b953eda6e14b88dc6bbc04d2049e"}, + {file = "greenlet-3.1.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:275f72decf9932639c1c6dd1013a1bc266438eb32710016a1c742df5da6e60a1"}, + {file = "greenlet-3.1.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:c4aab7f6381f38a4b42f269057aee279ab0fc7bf2e929e3d4abfae97b682a12c"}, + {file = "greenlet-3.1.1-cp313-cp313-win_amd64.whl", hash = "sha256:b42703b1cf69f2aa1df7d1030b9d77d3e584a70755674d60e710f0af570f3761"}, + {file = "greenlet-3.1.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f1695e76146579f8c06c1509c7ce4dfe0706f49c6831a817ac04eebb2fd02011"}, + {file = "greenlet-3.1.1-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7876452af029456b3f3549b696bb36a06db7c90747740c5302f74a9e9fa14b13"}, + {file = "greenlet-3.1.1-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4ead44c85f8ab905852d3de8d86f6f8baf77109f9da589cb4fa142bd3b57b475"}, + {file = "greenlet-3.1.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8320f64b777d00dd7ccdade271eaf0cad6636343293a25074cc5566160e4de7b"}, + {file = "greenlet-3.1.1-cp313-cp313t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6510bf84a6b643dabba74d3049ead221257603a253d0a9873f55f6a59a65f822"}, + {file = "greenlet-3.1.1-cp313-cp313t-musllinux_1_1_aarch64.whl", hash = "sha256:04b013dc07c96f83134b1e99888e7a79979f1a247e2a9f59697fa14b5862ed01"}, + {file = "greenlet-3.1.1-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:411f015496fec93c1c8cd4e5238da364e1da7a124bcb293f085bf2860c32c6f6"}, + {file = "greenlet-3.1.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:47da355d8687fd65240c364c90a31569a133b7b60de111c255ef5b606f2ae291"}, + {file = "greenlet-3.1.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:98884ecf2ffb7d7fe6bd517e8eb99d31ff7855a840fa6d0d63cd07c037f6a981"}, + {file = "greenlet-3.1.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f1d4aeb8891338e60d1ab6127af1fe45def5259def8094b9c7e34690c8858803"}, + {file = "greenlet-3.1.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db32b5348615a04b82240cc67983cb315309e88d444a288934ee6ceaebcad6cc"}, + {file = "greenlet-3.1.1-cp37-cp37m-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:dcc62f31eae24de7f8dce72134c8651c58000d3b1868e01392baea7c32c247de"}, + {file = "greenlet-3.1.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:1d3755bcb2e02de341c55b4fca7a745a24a9e7212ac953f6b3a48d117d7257aa"}, + {file = "greenlet-3.1.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:b8da394b34370874b4572676f36acabac172602abf054cbc4ac910219f3340af"}, + {file = "greenlet-3.1.1-cp37-cp37m-win32.whl", hash = "sha256:a0dfc6c143b519113354e780a50381508139b07d2177cb6ad6a08278ec655798"}, + {file = "greenlet-3.1.1-cp37-cp37m-win_amd64.whl", hash = "sha256:54558ea205654b50c438029505def3834e80f0869a70fb15b871c29b4575ddef"}, + {file = "greenlet-3.1.1-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:346bed03fe47414091be4ad44786d1bd8bef0c3fcad6ed3dee074a032ab408a9"}, + {file = "greenlet-3.1.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dfc59d69fc48664bc693842bd57acfdd490acafda1ab52c7836e3fc75c90a111"}, + {file = "greenlet-3.1.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d21e10da6ec19b457b82636209cbe2331ff4306b54d06fa04b7c138ba18c8a81"}, + {file = "greenlet-3.1.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:37b9de5a96111fc15418819ab4c4432e4f3c2ede61e660b1e33971eba26ef9ba"}, + {file = "greenlet-3.1.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6ef9ea3f137e5711f0dbe5f9263e8c009b7069d8a1acea822bd5e9dae0ae49c8"}, + {file = "greenlet-3.1.1-cp38-cp38-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:85f3ff71e2e60bd4b4932a043fbbe0f499e263c628390b285cb599154a3b03b1"}, + {file = "greenlet-3.1.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:95ffcf719966dd7c453f908e208e14cde192e09fde6c7186c8f1896ef778d8cd"}, + {file = "greenlet-3.1.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:03a088b9de532cbfe2ba2034b2b85e82df37874681e8c470d6fb2f8c04d7e4b7"}, + {file = "greenlet-3.1.1-cp38-cp38-win32.whl", hash = "sha256:8b8b36671f10ba80e159378df9c4f15c14098c4fd73a36b9ad715f057272fbef"}, + {file = "greenlet-3.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:7017b2be767b9d43cc31416aba48aab0d2309ee31b4dbf10a1d38fb7972bdf9d"}, + {file = "greenlet-3.1.1-cp39-cp39-macosx_11_0_universal2.whl", hash = "sha256:396979749bd95f018296af156201d6211240e7a23090f50a8d5d18c370084dc3"}, + {file = "greenlet-3.1.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca9d0ff5ad43e785350894d97e13633a66e2b50000e8a183a50a88d834752d42"}, + {file = "greenlet-3.1.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f6ff3b14f2df4c41660a7dec01045a045653998784bf8cfcb5a525bdffffbc8f"}, + {file = "greenlet-3.1.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:94ebba31df2aa506d7b14866fed00ac141a867e63143fe5bca82a8e503b36437"}, + {file = "greenlet-3.1.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:73aaad12ac0ff500f62cebed98d8789198ea0e6f233421059fa68a5aa7220145"}, + {file = "greenlet-3.1.1-cp39-cp39-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:63e4844797b975b9af3a3fb8f7866ff08775f5426925e1e0bbcfe7932059a12c"}, + {file = "greenlet-3.1.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:7939aa3ca7d2a1593596e7ac6d59391ff30281ef280d8632fa03d81f7c5f955e"}, + {file = "greenlet-3.1.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d0028e725ee18175c6e422797c407874da24381ce0690d6b9396c204c7f7276e"}, + {file = "greenlet-3.1.1-cp39-cp39-win32.whl", hash = "sha256:5e06afd14cbaf9e00899fae69b24a32f2196c19de08fcb9f4779dd4f004e5e7c"}, + {file = "greenlet-3.1.1-cp39-cp39-win_amd64.whl", hash = "sha256:3319aa75e0e0639bc15ff54ca327e8dc7a6fe404003496e3c6925cd3142e0e22"}, + {file = "greenlet-3.1.1.tar.gz", hash = "sha256:4ce3ac6cdb6adf7946475d7ef31777c26d94bccc377e070a7986bd2d5c515467"}, ] [package.extras] @@ -642,61 +667,70 @@ test = ["objgraph", "psutil"] [[package]] name = "grpcio" -version = "1.66.1" +version = "1.67.1" description = "HTTP/2-based RPC framework" optional = false python-versions = ">=3.8" files = [ - {file = "grpcio-1.66.1-cp310-cp310-linux_armv7l.whl", hash = "sha256:4877ba180591acdf127afe21ec1c7ff8a5ecf0fe2600f0d3c50e8c4a1cbc6492"}, - {file = "grpcio-1.66.1-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:3750c5a00bd644c75f4507f77a804d0189d97a107eb1481945a0cf3af3e7a5ac"}, - {file = "grpcio-1.66.1-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:a013c5fbb12bfb5f927444b477a26f1080755a931d5d362e6a9a720ca7dbae60"}, - {file = "grpcio-1.66.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b1b24c23d51a1e8790b25514157d43f0a4dce1ac12b3f0b8e9f66a5e2c4c132f"}, - {file = "grpcio-1.66.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b7ffb8ea674d68de4cac6f57d2498fef477cef582f1fa849e9f844863af50083"}, - {file = "grpcio-1.66.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:307b1d538140f19ccbd3aed7a93d8f71103c5d525f3c96f8616111614b14bf2a"}, - {file = "grpcio-1.66.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:1c17ebcec157cfb8dd445890a03e20caf6209a5bd4ac5b040ae9dbc59eef091d"}, - {file = "grpcio-1.66.1-cp310-cp310-win32.whl", hash = "sha256:ef82d361ed5849d34cf09105d00b94b6728d289d6b9235513cb2fcc79f7c432c"}, - {file = "grpcio-1.66.1-cp310-cp310-win_amd64.whl", hash = "sha256:292a846b92cdcd40ecca46e694997dd6b9be6c4c01a94a0dfb3fcb75d20da858"}, - {file = "grpcio-1.66.1-cp311-cp311-linux_armv7l.whl", hash = "sha256:c30aeceeaff11cd5ddbc348f37c58bcb96da8d5aa93fed78ab329de5f37a0d7a"}, - {file = "grpcio-1.66.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:8a1e224ce6f740dbb6b24c58f885422deebd7eb724aff0671a847f8951857c26"}, - {file = "grpcio-1.66.1-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:a66fe4dc35d2330c185cfbb42959f57ad36f257e0cc4557d11d9f0a3f14311df"}, - {file = "grpcio-1.66.1-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e3ba04659e4fce609de2658fe4dbf7d6ed21987a94460f5f92df7579fd5d0e22"}, - {file = "grpcio-1.66.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4573608e23f7e091acfbe3e84ac2045680b69751d8d67685ffa193a4429fedb1"}, - {file = "grpcio-1.66.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:7e06aa1f764ec8265b19d8f00140b8c4b6ca179a6dc67aa9413867c47e1fb04e"}, - {file = "grpcio-1.66.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3885f037eb11f1cacc41f207b705f38a44b69478086f40608959bf5ad85826dd"}, - {file = "grpcio-1.66.1-cp311-cp311-win32.whl", hash = "sha256:97ae7edd3f3f91480e48ede5d3e7d431ad6005bfdbd65c1b56913799ec79e791"}, - {file = "grpcio-1.66.1-cp311-cp311-win_amd64.whl", hash = "sha256:cfd349de4158d797db2bd82d2020554a121674e98fbe6b15328456b3bf2495bb"}, - {file = "grpcio-1.66.1-cp312-cp312-linux_armv7l.whl", hash = "sha256:a92c4f58c01c77205df6ff999faa008540475c39b835277fb8883b11cada127a"}, - {file = "grpcio-1.66.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:fdb14bad0835914f325349ed34a51940bc2ad965142eb3090081593c6e347be9"}, - {file = "grpcio-1.66.1-cp312-cp312-manylinux_2_17_aarch64.whl", hash = "sha256:f03a5884c56256e08fd9e262e11b5cfacf1af96e2ce78dc095d2c41ccae2c80d"}, - {file = "grpcio-1.66.1-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2ca2559692d8e7e245d456877a85ee41525f3ed425aa97eb7a70fc9a79df91a0"}, - {file = "grpcio-1.66.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:84ca1be089fb4446490dd1135828bd42a7c7f8421e74fa581611f7afdf7ab761"}, - {file = "grpcio-1.66.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:d639c939ad7c440c7b2819a28d559179a4508783f7e5b991166f8d7a34b52815"}, - {file = "grpcio-1.66.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:b9feb4e5ec8dc2d15709f4d5fc367794d69277f5d680baf1910fc9915c633524"}, - {file = "grpcio-1.66.1-cp312-cp312-win32.whl", hash = "sha256:7101db1bd4cd9b880294dec41a93fcdce465bdbb602cd8dc5bd2d6362b618759"}, - {file = "grpcio-1.66.1-cp312-cp312-win_amd64.whl", hash = "sha256:b0aa03d240b5539648d996cc60438f128c7f46050989e35b25f5c18286c86734"}, - {file = "grpcio-1.66.1-cp38-cp38-linux_armv7l.whl", hash = "sha256:ecfe735e7a59e5a98208447293ff8580e9db1e890e232b8b292dc8bd15afc0d2"}, - {file = "grpcio-1.66.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:4825a3aa5648010842e1c9d35a082187746aa0cdbf1b7a2a930595a94fb10fce"}, - {file = "grpcio-1.66.1-cp38-cp38-manylinux_2_17_aarch64.whl", hash = "sha256:f517fd7259fe823ef3bd21e508b653d5492e706e9f0ef82c16ce3347a8a5620c"}, - {file = "grpcio-1.66.1-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f1fe60d0772831d96d263b53d83fb9a3d050a94b0e94b6d004a5ad111faa5b5b"}, - {file = "grpcio-1.66.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:31a049daa428f928f21090403e5d18ea02670e3d5d172581670be006100db9ef"}, - {file = "grpcio-1.66.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:6f914386e52cbdeb5d2a7ce3bf1fdfacbe9d818dd81b6099a05b741aaf3848bb"}, - {file = "grpcio-1.66.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:bff2096bdba686019fb32d2dde45b95981f0d1490e054400f70fc9a8af34b49d"}, - {file = "grpcio-1.66.1-cp38-cp38-win32.whl", hash = "sha256:aa8ba945c96e73de29d25331b26f3e416e0c0f621e984a3ebdb2d0d0b596a3b3"}, - {file = "grpcio-1.66.1-cp38-cp38-win_amd64.whl", hash = "sha256:161d5c535c2bdf61b95080e7f0f017a1dfcb812bf54093e71e5562b16225b4ce"}, - {file = "grpcio-1.66.1-cp39-cp39-linux_armv7l.whl", hash = "sha256:d0cd7050397b3609ea51727b1811e663ffda8bda39c6a5bb69525ef12414b503"}, - {file = "grpcio-1.66.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:0e6c9b42ded5d02b6b1fea3a25f036a2236eeb75d0579bfd43c0018c88bf0a3e"}, - {file = "grpcio-1.66.1-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:c9f80f9fad93a8cf71c7f161778ba47fd730d13a343a46258065c4deb4b550c0"}, - {file = "grpcio-1.66.1-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5dd67ed9da78e5121efc5c510f0122a972216808d6de70953a740560c572eb44"}, - {file = "grpcio-1.66.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:48b0d92d45ce3be2084b92fb5bae2f64c208fea8ceed7fccf6a7b524d3c4942e"}, - {file = "grpcio-1.66.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:4d813316d1a752be6f5c4360c49f55b06d4fe212d7df03253dfdae90c8a402bb"}, - {file = "grpcio-1.66.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:9c9bebc6627873ec27a70fc800f6083a13c70b23a5564788754b9ee52c5aef6c"}, - {file = "grpcio-1.66.1-cp39-cp39-win32.whl", hash = "sha256:30a1c2cf9390c894c90bbc70147f2372130ad189cffef161f0432d0157973f45"}, - {file = "grpcio-1.66.1-cp39-cp39-win_amd64.whl", hash = "sha256:17663598aadbedc3cacd7bbde432f541c8e07d2496564e22b214b22c7523dac8"}, - {file = "grpcio-1.66.1.tar.gz", hash = "sha256:35334f9c9745add3e357e3372756fd32d925bd52c41da97f4dfdafbde0bf0ee2"}, + {file = "grpcio-1.67.1-cp310-cp310-linux_armv7l.whl", hash = "sha256:8b0341d66a57f8a3119b77ab32207072be60c9bf79760fa609c5609f2deb1f3f"}, + {file = "grpcio-1.67.1-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:f5a27dddefe0e2357d3e617b9079b4bfdc91341a91565111a21ed6ebbc51b22d"}, + {file = "grpcio-1.67.1-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:43112046864317498a33bdc4797ae6a268c36345a910de9b9c17159d8346602f"}, + {file = "grpcio-1.67.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c9b929f13677b10f63124c1a410994a401cdd85214ad83ab67cc077fc7e480f0"}, + {file = "grpcio-1.67.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e7d1797a8a3845437d327145959a2c0c47c05947c9eef5ff1a4c80e499dcc6fa"}, + {file = "grpcio-1.67.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:0489063974d1452436139501bf6b180f63d4977223ee87488fe36858c5725292"}, + {file = "grpcio-1.67.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:9fd042de4a82e3e7aca44008ee2fb5da01b3e5adb316348c21980f7f58adc311"}, + {file = "grpcio-1.67.1-cp310-cp310-win32.whl", hash = "sha256:638354e698fd0c6c76b04540a850bf1db27b4d2515a19fcd5cf645c48d3eb1ed"}, + {file = "grpcio-1.67.1-cp310-cp310-win_amd64.whl", hash = "sha256:608d87d1bdabf9e2868b12338cd38a79969eaf920c89d698ead08f48de9c0f9e"}, + {file = "grpcio-1.67.1-cp311-cp311-linux_armv7l.whl", hash = "sha256:7818c0454027ae3384235a65210bbf5464bd715450e30a3d40385453a85a70cb"}, + {file = "grpcio-1.67.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:ea33986b70f83844cd00814cee4451055cd8cab36f00ac64a31f5bb09b31919e"}, + {file = "grpcio-1.67.1-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:c7a01337407dd89005527623a4a72c5c8e2894d22bead0895306b23c6695698f"}, + {file = "grpcio-1.67.1-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:80b866f73224b0634f4312a4674c1be21b2b4afa73cb20953cbbb73a6b36c3cc"}, + {file = "grpcio-1.67.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f9fff78ba10d4250bfc07a01bd6254a6d87dc67f9627adece85c0b2ed754fa96"}, + {file = "grpcio-1.67.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:8a23cbcc5bb11ea7dc6163078be36c065db68d915c24f5faa4f872c573bb400f"}, + {file = "grpcio-1.67.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:1a65b503d008f066e994f34f456e0647e5ceb34cfcec5ad180b1b44020ad4970"}, + {file = "grpcio-1.67.1-cp311-cp311-win32.whl", hash = "sha256:e29ca27bec8e163dca0c98084040edec3bc49afd10f18b412f483cc68c712744"}, + {file = "grpcio-1.67.1-cp311-cp311-win_amd64.whl", hash = "sha256:786a5b18544622bfb1e25cc08402bd44ea83edfb04b93798d85dca4d1a0b5be5"}, + {file = "grpcio-1.67.1-cp312-cp312-linux_armv7l.whl", hash = "sha256:267d1745894200e4c604958da5f856da6293f063327cb049a51fe67348e4f953"}, + {file = "grpcio-1.67.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:85f69fdc1d28ce7cff8de3f9c67db2b0ca9ba4449644488c1e0303c146135ddb"}, + {file = "grpcio-1.67.1-cp312-cp312-manylinux_2_17_aarch64.whl", hash = "sha256:f26b0b547eb8d00e195274cdfc63ce64c8fc2d3e2d00b12bf468ece41a0423a0"}, + {file = "grpcio-1.67.1-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4422581cdc628f77302270ff839a44f4c24fdc57887dc2a45b7e53d8fc2376af"}, + {file = "grpcio-1.67.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1d7616d2ded471231c701489190379e0c311ee0a6c756f3c03e6a62b95a7146e"}, + {file = "grpcio-1.67.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:8a00efecde9d6fcc3ab00c13f816313c040a28450e5e25739c24f432fc6d3c75"}, + {file = "grpcio-1.67.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:699e964923b70f3101393710793289e42845791ea07565654ada0969522d0a38"}, + {file = "grpcio-1.67.1-cp312-cp312-win32.whl", hash = "sha256:4e7b904484a634a0fff132958dabdb10d63e0927398273917da3ee103e8d1f78"}, + {file = "grpcio-1.67.1-cp312-cp312-win_amd64.whl", hash = "sha256:5721e66a594a6c4204458004852719b38f3d5522082be9061d6510b455c90afc"}, + {file = "grpcio-1.67.1-cp313-cp313-linux_armv7l.whl", hash = "sha256:aa0162e56fd10a5547fac8774c4899fc3e18c1aa4a4759d0ce2cd00d3696ea6b"}, + {file = "grpcio-1.67.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:beee96c8c0b1a75d556fe57b92b58b4347c77a65781ee2ac749d550f2a365dc1"}, + {file = "grpcio-1.67.1-cp313-cp313-manylinux_2_17_aarch64.whl", hash = "sha256:a93deda571a1bf94ec1f6fcda2872dad3ae538700d94dc283c672a3b508ba3af"}, + {file = "grpcio-1.67.1-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0e6f255980afef598a9e64a24efce87b625e3e3c80a45162d111a461a9f92955"}, + {file = "grpcio-1.67.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9e838cad2176ebd5d4a8bb03955138d6589ce9e2ce5d51c3ada34396dbd2dba8"}, + {file = "grpcio-1.67.1-cp313-cp313-musllinux_1_1_i686.whl", hash = "sha256:a6703916c43b1d468d0756c8077b12017a9fcb6a1ef13faf49e67d20d7ebda62"}, + {file = "grpcio-1.67.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:917e8d8994eed1d86b907ba2a61b9f0aef27a2155bca6cbb322430fc7135b7bb"}, + {file = "grpcio-1.67.1-cp313-cp313-win32.whl", hash = "sha256:e279330bef1744040db8fc432becc8a727b84f456ab62b744d3fdb83f327e121"}, + {file = "grpcio-1.67.1-cp313-cp313-win_amd64.whl", hash = "sha256:fa0c739ad8b1996bd24823950e3cb5152ae91fca1c09cc791190bf1627ffefba"}, + {file = "grpcio-1.67.1-cp38-cp38-linux_armv7l.whl", hash = "sha256:178f5db771c4f9a9facb2ab37a434c46cb9be1a75e820f187ee3d1e7805c4f65"}, + {file = "grpcio-1.67.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:0f3e49c738396e93b7ba9016e153eb09e0778e776df6090c1b8c91877cc1c426"}, + {file = "grpcio-1.67.1-cp38-cp38-manylinux_2_17_aarch64.whl", hash = "sha256:24e8a26dbfc5274d7474c27759b54486b8de23c709d76695237515bc8b5baeab"}, + {file = "grpcio-1.67.1-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3b6c16489326d79ead41689c4b84bc40d522c9a7617219f4ad94bc7f448c5085"}, + {file = "grpcio-1.67.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:60e6a4dcf5af7bbc36fd9f81c9f372e8ae580870a9e4b6eafe948cd334b81cf3"}, + {file = "grpcio-1.67.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:95b5f2b857856ed78d72da93cd7d09b6db8ef30102e5e7fe0961fe4d9f7d48e8"}, + {file = "grpcio-1.67.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b49359977c6ec9f5d0573ea4e0071ad278ef905aa74e420acc73fd28ce39e9ce"}, + {file = "grpcio-1.67.1-cp38-cp38-win32.whl", hash = "sha256:f5b76ff64aaac53fede0cc93abf57894ab2a7362986ba22243d06218b93efe46"}, + {file = "grpcio-1.67.1-cp38-cp38-win_amd64.whl", hash = "sha256:804c6457c3cd3ec04fe6006c739579b8d35c86ae3298ffca8de57b493524b771"}, + {file = "grpcio-1.67.1-cp39-cp39-linux_armv7l.whl", hash = "sha256:a25bdea92b13ff4d7790962190bf6bf5c4639876e01c0f3dda70fc2769616335"}, + {file = "grpcio-1.67.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:cdc491ae35a13535fd9196acb5afe1af37c8237df2e54427be3eecda3653127e"}, + {file = "grpcio-1.67.1-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:85f862069b86a305497e74d0dc43c02de3d1d184fc2c180993aa8aa86fbd19b8"}, + {file = "grpcio-1.67.1-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ec74ef02010186185de82cc594058a3ccd8d86821842bbac9873fd4a2cf8be8d"}, + {file = "grpcio-1.67.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:01f616a964e540638af5130469451cf580ba8c7329f45ca998ab66e0c7dcdb04"}, + {file = "grpcio-1.67.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:299b3d8c4f790c6bcca485f9963b4846dd92cf6f1b65d3697145d005c80f9fe8"}, + {file = "grpcio-1.67.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:60336bff760fbb47d7e86165408126f1dded184448e9a4c892189eb7c9d3f90f"}, + {file = "grpcio-1.67.1-cp39-cp39-win32.whl", hash = "sha256:5ed601c4c6008429e3d247ddb367fe8c7259c355757448d7c1ef7bd4a6739e8e"}, + {file = "grpcio-1.67.1-cp39-cp39-win_amd64.whl", hash = "sha256:5db70d32d6703b89912af16d6d45d78406374a8b8ef0d28140351dd0ec610e98"}, + {file = "grpcio-1.67.1.tar.gz", hash = "sha256:3dc2ed4cabea4dc14d5e708c2b426205956077cc5de419b4d4079315017e9732"}, ] [package.extras] -protobuf = ["grpcio-tools (>=1.66.1)"] +protobuf = ["grpcio-tools (>=1.67.1)"] [[package]] name = "grpcio-tools" @@ -816,13 +850,13 @@ files = [ [[package]] name = "identify" -version = "2.6.0" +version = "2.6.1" description = "File identification library for Python" optional = false python-versions = ">=3.8" files = [ - {file = "identify-2.6.0-py2.py3-none-any.whl", hash = "sha256:e79ae4406387a9d300332b5fd366d8994f1525e8414984e1a59e058b2eda2dd0"}, - {file = "identify-2.6.0.tar.gz", hash = "sha256:cb171c685bdc31bcc4c1734698736a7d5b6c8bf2e0c15117f4d469c8640ae5cf"}, + {file = "identify-2.6.1-py2.py3-none-any.whl", hash = "sha256:53863bcac7caf8d2ed85bd20312ea5dcfc22226800f6d6881f232d861db5a8f0"}, + {file = "identify-2.6.1.tar.gz", hash = "sha256:91478c5fb7c3aac5ff7bf9b4344f803843dc586832d5f110d672b19aa1984c98"}, ] [package.extras] @@ -830,15 +864,18 @@ license = ["ukkonen"] [[package]] name = "idna" -version = "3.8" +version = "3.10" description = "Internationalized Domain Names in Applications (IDNA)" optional = false python-versions = ">=3.6" files = [ - {file = "idna-3.8-py3-none-any.whl", hash = "sha256:050b4e5baadcd44d760cedbd2b8e639f2ff89bbc7a5730fcc662954303377aac"}, - {file = "idna-3.8.tar.gz", hash = "sha256:d838c2c0ed6fced7693d5e8ab8e734d5f8fda53a039c0164afb0b82e771e3603"}, + {file = "idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3"}, + {file = "idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9"}, ] +[package.extras] +all = ["flake8 (>=7.1.1)", "mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.6.2)"] + [[package]] name = "imagesize" version = "1.4.1" @@ -863,17 +900,20 @@ files = [ [[package]] name = "isort" -version = "5.13.2" +version = "5.11.5" description = "A Python utility / library to sort Python imports." optional = true -python-versions = ">=3.8.0" +python-versions = ">=3.7.0" files = [ - {file = "isort-5.13.2-py3-none-any.whl", hash = "sha256:8ca5e72a8d85860d5a3fa69b8745237f2939afe12dbf656afbcb47fe72d947a6"}, - {file = "isort-5.13.2.tar.gz", hash = "sha256:48fdfcb9face5d58a4f6dde2e72a1fb8dcaf8ab26f95ab49fab84c2ddefb0109"}, + {file = "isort-5.11.5-py3-none-any.whl", hash = "sha256:ba1d72fb2595a01c7895a5128f9585a5cc4b6d395f1c8d514989b9a7eb2a8746"}, + {file = "isort-5.11.5.tar.gz", hash = "sha256:6be1f76a507cb2ecf16c7cf14a37e41609ca082330be4e3436a18ef74add55db"}, ] [package.extras] -colors = ["colorama (>=0.4.6)"] +colors = ["colorama (>=0.4.3,<0.5.0)"] +pipfile-deprecated-finder = ["pip-shims (>=0.5.2)", "pipreqs", "requirementslib"] +plugins = ["setuptools"] +requirements-deprecated-finder = ["pip-api", "pipreqs"] [[package]] name = "jinja2" @@ -1081,38 +1121,43 @@ typing-extensions = {version = ">=4.1.0", markers = "python_version < \"3.11\""} [[package]] name = "mypy" -version = "1.11.2" +version = "1.13.0" description = "Optional static typing for Python" optional = false python-versions = ">=3.8" files = [ - {file = "mypy-1.11.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d42a6dd818ffce7be66cce644f1dff482f1d97c53ca70908dff0b9ddc120b77a"}, - {file = "mypy-1.11.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:801780c56d1cdb896eacd5619a83e427ce436d86a3bdf9112527f24a66618fef"}, - {file = "mypy-1.11.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:41ea707d036a5307ac674ea172875f40c9d55c5394f888b168033177fce47383"}, - {file = "mypy-1.11.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6e658bd2d20565ea86da7d91331b0eed6d2eee22dc031579e6297f3e12c758c8"}, - {file = "mypy-1.11.2-cp310-cp310-win_amd64.whl", hash = "sha256:478db5f5036817fe45adb7332d927daa62417159d49783041338921dcf646fc7"}, - {file = "mypy-1.11.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:75746e06d5fa1e91bfd5432448d00d34593b52e7e91a187d981d08d1f33d4385"}, - {file = "mypy-1.11.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a976775ab2256aadc6add633d44f100a2517d2388906ec4f13231fafbb0eccca"}, - {file = "mypy-1.11.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:cd953f221ac1379050a8a646585a29574488974f79d8082cedef62744f0a0104"}, - {file = "mypy-1.11.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:57555a7715c0a34421013144a33d280e73c08df70f3a18a552938587ce9274f4"}, - {file = "mypy-1.11.2-cp311-cp311-win_amd64.whl", hash = "sha256:36383a4fcbad95f2657642a07ba22ff797de26277158f1cc7bd234821468b1b6"}, - {file = "mypy-1.11.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:e8960dbbbf36906c5c0b7f4fbf2f0c7ffb20f4898e6a879fcf56a41a08b0d318"}, - {file = "mypy-1.11.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:06d26c277962f3fb50e13044674aa10553981ae514288cb7d0a738f495550b36"}, - {file = "mypy-1.11.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6e7184632d89d677973a14d00ae4d03214c8bc301ceefcdaf5c474866814c987"}, - {file = "mypy-1.11.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:3a66169b92452f72117e2da3a576087025449018afc2d8e9bfe5ffab865709ca"}, - {file = "mypy-1.11.2-cp312-cp312-win_amd64.whl", hash = "sha256:969ea3ef09617aff826885a22ece0ddef69d95852cdad2f60c8bb06bf1f71f70"}, - {file = "mypy-1.11.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:37c7fa6121c1cdfcaac97ce3d3b5588e847aa79b580c1e922bb5d5d2902df19b"}, - {file = "mypy-1.11.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4a8a53bc3ffbd161b5b2a4fff2f0f1e23a33b0168f1c0778ec70e1a3d66deb86"}, - {file = "mypy-1.11.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2ff93107f01968ed834f4256bc1fc4475e2fecf6c661260066a985b52741ddce"}, - {file = "mypy-1.11.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:edb91dded4df17eae4537668b23f0ff6baf3707683734b6a818d5b9d0c0c31a1"}, - {file = "mypy-1.11.2-cp38-cp38-win_amd64.whl", hash = "sha256:ee23de8530d99b6db0573c4ef4bd8f39a2a6f9b60655bf7a1357e585a3486f2b"}, - {file = "mypy-1.11.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:801ca29f43d5acce85f8e999b1e431fb479cb02d0e11deb7d2abb56bdaf24fd6"}, - {file = "mypy-1.11.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:af8d155170fcf87a2afb55b35dc1a0ac21df4431e7d96717621962e4b9192e70"}, - {file = "mypy-1.11.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f7821776e5c4286b6a13138cc935e2e9b6fde05e081bdebf5cdb2bb97c9df81d"}, - {file = "mypy-1.11.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:539c570477a96a4e6fb718b8d5c3e0c0eba1f485df13f86d2970c91f0673148d"}, - {file = "mypy-1.11.2-cp39-cp39-win_amd64.whl", hash = "sha256:3f14cd3d386ac4d05c5a39a51b84387403dadbd936e17cb35882134d4f8f0d24"}, - {file = "mypy-1.11.2-py3-none-any.whl", hash = "sha256:b499bc07dbdcd3de92b0a8b29fdf592c111276f6a12fe29c30f6c417dd546d12"}, - {file = "mypy-1.11.2.tar.gz", hash = "sha256:7f9993ad3e0ffdc95c2a14b66dee63729f021968bff8ad911867579c65d13a79"}, + {file = "mypy-1.13.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6607e0f1dd1fb7f0aca14d936d13fd19eba5e17e1cd2a14f808fa5f8f6d8f60a"}, + {file = "mypy-1.13.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8a21be69bd26fa81b1f80a61ee7ab05b076c674d9b18fb56239d72e21d9f4c80"}, + {file = "mypy-1.13.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7b2353a44d2179846a096e25691d54d59904559f4232519d420d64da6828a3a7"}, + {file = "mypy-1.13.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:0730d1c6a2739d4511dc4253f8274cdd140c55c32dfb0a4cf8b7a43f40abfa6f"}, + {file = "mypy-1.13.0-cp310-cp310-win_amd64.whl", hash = "sha256:c5fc54dbb712ff5e5a0fca797e6e0aa25726c7e72c6a5850cfd2adbc1eb0a372"}, + {file = "mypy-1.13.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:581665e6f3a8a9078f28d5502f4c334c0c8d802ef55ea0e7276a6e409bc0d82d"}, + {file = "mypy-1.13.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3ddb5b9bf82e05cc9a627e84707b528e5c7caaa1c55c69e175abb15a761cec2d"}, + {file = "mypy-1.13.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:20c7ee0bc0d5a9595c46f38beb04201f2620065a93755704e141fcac9f59db2b"}, + {file = "mypy-1.13.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3790ded76f0b34bc9c8ba4def8f919dd6a46db0f5a6610fb994fe8efdd447f73"}, + {file = "mypy-1.13.0-cp311-cp311-win_amd64.whl", hash = "sha256:51f869f4b6b538229c1d1bcc1dd7d119817206e2bc54e8e374b3dfa202defcca"}, + {file = "mypy-1.13.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:5c7051a3461ae84dfb5dd15eff5094640c61c5f22257c8b766794e6dd85e72d5"}, + {file = "mypy-1.13.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:39bb21c69a5d6342f4ce526e4584bc5c197fd20a60d14a8624d8743fffb9472e"}, + {file = "mypy-1.13.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:164f28cb9d6367439031f4c81e84d3ccaa1e19232d9d05d37cb0bd880d3f93c2"}, + {file = "mypy-1.13.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a4c1bfcdbce96ff5d96fc9b08e3831acb30dc44ab02671eca5953eadad07d6d0"}, + {file = "mypy-1.13.0-cp312-cp312-win_amd64.whl", hash = "sha256:a0affb3a79a256b4183ba09811e3577c5163ed06685e4d4b46429a271ba174d2"}, + {file = "mypy-1.13.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a7b44178c9760ce1a43f544e595d35ed61ac2c3de306599fa59b38a6048e1aa7"}, + {file = "mypy-1.13.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5d5092efb8516d08440e36626f0153b5006d4088c1d663d88bf79625af3d1d62"}, + {file = "mypy-1.13.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:de2904956dac40ced10931ac967ae63c5089bd498542194b436eb097a9f77bc8"}, + {file = "mypy-1.13.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:7bfd8836970d33c2105562650656b6846149374dc8ed77d98424b40b09340ba7"}, + {file = "mypy-1.13.0-cp313-cp313-win_amd64.whl", hash = "sha256:9f73dba9ec77acb86457a8fc04b5239822df0c14a082564737833d2963677dbc"}, + {file = "mypy-1.13.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:100fac22ce82925f676a734af0db922ecfea991e1d7ec0ceb1e115ebe501301a"}, + {file = "mypy-1.13.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7bcb0bb7f42a978bb323a7c88f1081d1b5dee77ca86f4100735a6f541299d8fb"}, + {file = "mypy-1.13.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bde31fc887c213e223bbfc34328070996061b0833b0a4cfec53745ed61f3519b"}, + {file = "mypy-1.13.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:07de989f89786f62b937851295ed62e51774722e5444a27cecca993fc3f9cd74"}, + {file = "mypy-1.13.0-cp38-cp38-win_amd64.whl", hash = "sha256:4bde84334fbe19bad704b3f5b78c4abd35ff1026f8ba72b29de70dda0916beb6"}, + {file = "mypy-1.13.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:0246bcb1b5de7f08f2826451abd947bf656945209b140d16ed317f65a17dc7dc"}, + {file = "mypy-1.13.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:7f5b7deae912cf8b77e990b9280f170381fdfbddf61b4ef80927edd813163732"}, + {file = "mypy-1.13.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7029881ec6ffb8bc233a4fa364736789582c738217b133f1b55967115288a2bc"}, + {file = "mypy-1.13.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:3e38b980e5681f28f033f3be86b099a247b13c491f14bb8b1e1e134d23bb599d"}, + {file = "mypy-1.13.0-cp39-cp39-win_amd64.whl", hash = "sha256:a6789be98a2017c912ae6ccb77ea553bbaf13d27605d2ca20a76dfbced631b24"}, + {file = "mypy-1.13.0-py3-none-any.whl", hash = "sha256:9c250883f9fd81d212e0952c92dbfcc96fc237f4b7c92f56ac81fd48460b3e5a"}, + {file = "mypy-1.13.0.tar.gz", hash = "sha256:0291a61b6fbf3e6673e3405cfcc0e7650bebc7939659fdca2702958038bd835e"}, ] [package.dependencies] @@ -1122,6 +1167,7 @@ typing-extensions = ">=4.6.0" [package.extras] dmypy = ["psutil (>=4.0)"] +faster-cache = ["orjson"] install-types = ["pip"] mypyc = ["setuptools (>=50)"] reports = ["lxml"] @@ -1150,13 +1196,13 @@ files = [ [[package]] name = "packaging" -version = "24.1" +version = "24.2" description = "Core utilities for Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "packaging-24.1-py3-none-any.whl", hash = "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124"}, - {file = "packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002"}, + {file = "packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759"}, + {file = "packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f"}, ] [[package]] @@ -1183,13 +1229,13 @@ files = [ [[package]] name = "platformdirs" -version = "4.3.2" +version = "4.3.6" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." optional = false python-versions = ">=3.8" files = [ - {file = "platformdirs-4.3.2-py3-none-any.whl", hash = "sha256:eb1c8582560b34ed4ba105009a4badf7f6f85768b30126f351328507b2beb617"}, - {file = "platformdirs-4.3.2.tar.gz", hash = "sha256:9e5e27a08aa095dd127b9f2e764d74254f482fef22b0970773bfba79d091ab8c"}, + {file = "platformdirs-4.3.6-py3-none-any.whl", hash = "sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb"}, + {file = "platformdirs-4.3.6.tar.gz", hash = "sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907"}, ] [package.extras] @@ -1214,18 +1260,19 @@ testing = ["pytest", "pytest-benchmark"] [[package]] name = "poethepoet" -version = "0.28.0" +version = "0.30.0" description = "A task runner that works well with poetry." optional = false python-versions = ">=3.8" files = [ - {file = "poethepoet-0.28.0-py3-none-any.whl", hash = "sha256:db6946ff39a1244235950cd720ee7182107f64126d3dcc64c9a996cc4d755404"}, - {file = "poethepoet-0.28.0.tar.gz", hash = "sha256:5dc3ee036ab0c93e918b5caed628274618b07d788e5cff6c4ae480913cbe009c"}, + {file = "poethepoet-0.30.0-py3-none-any.whl", hash = "sha256:bf875741407a98da9e96f2f2d0b2c4c34f56d89939a7f53a4b6b3a64b546ec4e"}, + {file = "poethepoet-0.30.0.tar.gz", hash = "sha256:9f7ccda2d6525616ce989ca8ef973739fd668f50bef0b9d3631421d504d9ae4a"}, ] [package.dependencies] pastel = ">=0.2.1,<0.3.0" -tomli = ">=1.2.2" +pyyaml = ">=6.0.2,<7.0.0" +tomli = {version = ">=1.2.2", markers = "python_version < \"3.11\""} [package.extras] poetry-plugin = ["poetry (>=1.0,<2.0)"] @@ -1250,22 +1297,22 @@ virtualenv = ">=20.10.0" [[package]] name = "protobuf" -version = "4.25.4" +version = "4.25.5" description = "" optional = false python-versions = ">=3.8" files = [ - {file = "protobuf-4.25.4-cp310-abi3-win32.whl", hash = "sha256:db9fd45183e1a67722cafa5c1da3e85c6492a5383f127c86c4c4aa4845867dc4"}, - {file = "protobuf-4.25.4-cp310-abi3-win_amd64.whl", hash = "sha256:ba3d8504116a921af46499471c63a85260c1a5fc23333154a427a310e015d26d"}, - {file = "protobuf-4.25.4-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:eecd41bfc0e4b1bd3fa7909ed93dd14dd5567b98c941d6c1ad08fdcab3d6884b"}, - {file = "protobuf-4.25.4-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:4c8a70fdcb995dcf6c8966cfa3a29101916f7225e9afe3ced4395359955d3835"}, - {file = "protobuf-4.25.4-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:3319e073562e2515c6ddc643eb92ce20809f5d8f10fead3332f71c63be6a7040"}, - {file = "protobuf-4.25.4-cp38-cp38-win32.whl", hash = "sha256:7e372cbbda66a63ebca18f8ffaa6948455dfecc4e9c1029312f6c2edcd86c4e1"}, - {file = "protobuf-4.25.4-cp38-cp38-win_amd64.whl", hash = "sha256:051e97ce9fa6067a4546e75cb14f90cf0232dcb3e3d508c448b8d0e4265b61c1"}, - {file = "protobuf-4.25.4-cp39-cp39-win32.whl", hash = "sha256:90bf6fd378494eb698805bbbe7afe6c5d12c8e17fca817a646cd6a1818c696ca"}, - {file = "protobuf-4.25.4-cp39-cp39-win_amd64.whl", hash = "sha256:ac79a48d6b99dfed2729ccccee547b34a1d3d63289c71cef056653a846a2240f"}, - {file = "protobuf-4.25.4-py3-none-any.whl", hash = "sha256:bfbebc1c8e4793cfd58589acfb8a1026be0003e852b9da7db5a4285bde996978"}, - {file = "protobuf-4.25.4.tar.gz", hash = "sha256:0dc4a62cc4052a036ee2204d26fe4d835c62827c855c8a03f29fe6da146b380d"}, + {file = "protobuf-4.25.5-cp310-abi3-win32.whl", hash = "sha256:5e61fd921603f58d2f5acb2806a929b4675f8874ff5f330b7d6f7e2e784bbcd8"}, + {file = "protobuf-4.25.5-cp310-abi3-win_amd64.whl", hash = "sha256:4be0571adcbe712b282a330c6e89eae24281344429ae95c6d85e79e84780f5ea"}, + {file = "protobuf-4.25.5-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:b2fde3d805354df675ea4c7c6338c1aecd254dfc9925e88c6d31a2bcb97eb173"}, + {file = "protobuf-4.25.5-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:919ad92d9b0310070f8356c24b855c98df2b8bd207ebc1c0c6fcc9ab1e007f3d"}, + {file = "protobuf-4.25.5-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:fe14e16c22be926d3abfcb500e60cab068baf10b542b8c858fa27e098123e331"}, + {file = "protobuf-4.25.5-cp38-cp38-win32.whl", hash = "sha256:98d8d8aa50de6a2747efd9cceba361c9034050ecce3e09136f90de37ddba66e1"}, + {file = "protobuf-4.25.5-cp38-cp38-win_amd64.whl", hash = "sha256:b0234dd5a03049e4ddd94b93400b67803c823cfc405689688f59b34e0742381a"}, + {file = "protobuf-4.25.5-cp39-cp39-win32.whl", hash = "sha256:abe32aad8561aa7cc94fc7ba4fdef646e576983edb94a73381b03c53728a626f"}, + {file = "protobuf-4.25.5-cp39-cp39-win_amd64.whl", hash = "sha256:7a183f592dc80aa7c8da7ad9e55091c4ffc9497b3054452d629bb85fa27c2a45"}, + {file = "protobuf-4.25.5-py3-none-any.whl", hash = "sha256:0aebecb809cae990f8129ada5ca273d9d670b76d9bfc9b1809f0a9c02b7dbf41"}, + {file = "protobuf-4.25.5.tar.gz", hash = "sha256:7f8249476b4a9473645db7f8ab42b02fe1488cbe5fb72fddd445e0665afd8584"}, ] [[package]] @@ -1281,18 +1328,18 @@ files = [ [[package]] name = "pydantic" -version = "2.9.1" +version = "2.9.2" description = "Data validation using Python type hints" optional = false python-versions = ">=3.8" files = [ - {file = "pydantic-2.9.1-py3-none-any.whl", hash = "sha256:7aff4db5fdf3cf573d4b3c30926a510a10e19a0774d38fc4967f78beb6deb612"}, - {file = "pydantic-2.9.1.tar.gz", hash = "sha256:1363c7d975c7036df0db2b4a61f2e062fbc0aa5ab5f2772e0ffc7191a4f4bce2"}, + {file = "pydantic-2.9.2-py3-none-any.whl", hash = "sha256:f048cec7b26778210e28a0459867920654d48e5e62db0958433636cde4254f12"}, + {file = "pydantic-2.9.2.tar.gz", hash = "sha256:d155cef71265d1e9807ed1c32b4c8deec042a44a50a4188b25ac67ecd81a9c0f"}, ] [package.dependencies] annotated-types = ">=0.6.0" -pydantic-core = "2.23.3" +pydantic-core = "2.23.4" typing-extensions = [ {version = ">=4.12.2", markers = "python_version >= \"3.13\""}, {version = ">=4.6.1", markers = "python_version < \"3.13\""}, @@ -1304,100 +1351,100 @@ timezone = ["tzdata"] [[package]] name = "pydantic-core" -version = "2.23.3" +version = "2.23.4" description = "Core functionality for Pydantic validation and serialization" optional = false python-versions = ">=3.8" files = [ - {file = "pydantic_core-2.23.3-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:7f10a5d1b9281392f1bf507d16ac720e78285dfd635b05737c3911637601bae6"}, - {file = "pydantic_core-2.23.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3c09a7885dd33ee8c65266e5aa7fb7e2f23d49d8043f089989726391dd7350c5"}, - {file = "pydantic_core-2.23.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6470b5a1ec4d1c2e9afe928c6cb37eb33381cab99292a708b8cb9aa89e62429b"}, - {file = "pydantic_core-2.23.3-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9172d2088e27d9a185ea0a6c8cebe227a9139fd90295221d7d495944d2367700"}, - {file = "pydantic_core-2.23.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:86fc6c762ca7ac8fbbdff80d61b2c59fb6b7d144aa46e2d54d9e1b7b0e780e01"}, - {file = "pydantic_core-2.23.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f0cb80fd5c2df4898693aa841425ea1727b1b6d2167448253077d2a49003e0ed"}, - {file = "pydantic_core-2.23.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:03667cec5daf43ac4995cefa8aaf58f99de036204a37b889c24a80927b629cec"}, - {file = "pydantic_core-2.23.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:047531242f8e9c2db733599f1c612925de095e93c9cc0e599e96cf536aaf56ba"}, - {file = "pydantic_core-2.23.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:5499798317fff7f25dbef9347f4451b91ac2a4330c6669821c8202fd354c7bee"}, - {file = "pydantic_core-2.23.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:bbb5e45eab7624440516ee3722a3044b83fff4c0372efe183fd6ba678ff681fe"}, - {file = "pydantic_core-2.23.3-cp310-none-win32.whl", hash = "sha256:8b5b3ed73abb147704a6e9f556d8c5cb078f8c095be4588e669d315e0d11893b"}, - {file = "pydantic_core-2.23.3-cp310-none-win_amd64.whl", hash = "sha256:2b603cde285322758a0279995b5796d64b63060bfbe214b50a3ca23b5cee3e83"}, - {file = "pydantic_core-2.23.3-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:c889fd87e1f1bbeb877c2ee56b63bb297de4636661cc9bbfcf4b34e5e925bc27"}, - {file = "pydantic_core-2.23.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ea85bda3189fb27503af4c45273735bcde3dd31c1ab17d11f37b04877859ef45"}, - {file = "pydantic_core-2.23.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a7f7f72f721223f33d3dc98a791666ebc6a91fa023ce63733709f4894a7dc611"}, - {file = "pydantic_core-2.23.3-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2b2b55b0448e9da68f56b696f313949cda1039e8ec7b5d294285335b53104b61"}, - {file = "pydantic_core-2.23.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c24574c7e92e2c56379706b9a3f07c1e0c7f2f87a41b6ee86653100c4ce343e5"}, - {file = "pydantic_core-2.23.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f2b05e6ccbee333a8f4b8f4d7c244fdb7a979e90977ad9c51ea31261e2085ce0"}, - {file = "pydantic_core-2.23.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e2c409ce1c219c091e47cb03feb3c4ed8c2b8e004efc940da0166aaee8f9d6c8"}, - {file = "pydantic_core-2.23.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d965e8b325f443ed3196db890d85dfebbb09f7384486a77461347f4adb1fa7f8"}, - {file = "pydantic_core-2.23.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:f56af3a420fb1ffaf43ece3ea09c2d27c444e7c40dcb7c6e7cf57aae764f2b48"}, - {file = "pydantic_core-2.23.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:5b01a078dd4f9a52494370af21aa52964e0a96d4862ac64ff7cea06e0f12d2c5"}, - {file = "pydantic_core-2.23.3-cp311-none-win32.whl", hash = "sha256:560e32f0df04ac69b3dd818f71339983f6d1f70eb99d4d1f8e9705fb6c34a5c1"}, - {file = "pydantic_core-2.23.3-cp311-none-win_amd64.whl", hash = "sha256:c744fa100fdea0d000d8bcddee95213d2de2e95b9c12be083370b2072333a0fa"}, - {file = "pydantic_core-2.23.3-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:e0ec50663feedf64d21bad0809f5857bac1ce91deded203efc4a84b31b2e4305"}, - {file = "pydantic_core-2.23.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:db6e6afcb95edbe6b357786684b71008499836e91f2a4a1e55b840955b341dbb"}, - {file = "pydantic_core-2.23.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:98ccd69edcf49f0875d86942f4418a4e83eb3047f20eb897bffa62a5d419c8fa"}, - {file = "pydantic_core-2.23.3-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a678c1ac5c5ec5685af0133262103defb427114e62eafeda12f1357a12140162"}, - {file = "pydantic_core-2.23.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:01491d8b4d8db9f3391d93b0df60701e644ff0894352947f31fff3e52bd5c801"}, - {file = "pydantic_core-2.23.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fcf31facf2796a2d3b7fe338fe8640aa0166e4e55b4cb108dbfd1058049bf4cb"}, - {file = "pydantic_core-2.23.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7200fd561fb3be06827340da066df4311d0b6b8eb0c2116a110be5245dceb326"}, - {file = "pydantic_core-2.23.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:dc1636770a809dee2bd44dd74b89cc80eb41172bcad8af75dd0bc182c2666d4c"}, - {file = "pydantic_core-2.23.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:67a5def279309f2e23014b608c4150b0c2d323bd7bccd27ff07b001c12c2415c"}, - {file = "pydantic_core-2.23.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:748bdf985014c6dd3e1e4cc3db90f1c3ecc7246ff5a3cd4ddab20c768b2f1dab"}, - {file = "pydantic_core-2.23.3-cp312-none-win32.whl", hash = "sha256:255ec6dcb899c115f1e2a64bc9ebc24cc0e3ab097775755244f77360d1f3c06c"}, - {file = "pydantic_core-2.23.3-cp312-none-win_amd64.whl", hash = "sha256:40b8441be16c1e940abebed83cd006ddb9e3737a279e339dbd6d31578b802f7b"}, - {file = "pydantic_core-2.23.3-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:6daaf5b1ba1369a22c8b050b643250e3e5efc6a78366d323294aee54953a4d5f"}, - {file = "pydantic_core-2.23.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d015e63b985a78a3d4ccffd3bdf22b7c20b3bbd4b8227809b3e8e75bc37f9cb2"}, - {file = "pydantic_core-2.23.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a3fc572d9b5b5cfe13f8e8a6e26271d5d13f80173724b738557a8c7f3a8a3791"}, - {file = "pydantic_core-2.23.3-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f6bd91345b5163ee7448bee201ed7dd601ca24f43f439109b0212e296eb5b423"}, - {file = "pydantic_core-2.23.3-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fc379c73fd66606628b866f661e8785088afe2adaba78e6bbe80796baf708a63"}, - {file = "pydantic_core-2.23.3-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fbdce4b47592f9e296e19ac31667daed8753c8367ebb34b9a9bd89dacaa299c9"}, - {file = "pydantic_core-2.23.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc3cf31edf405a161a0adad83246568647c54404739b614b1ff43dad2b02e6d5"}, - {file = "pydantic_core-2.23.3-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8e22b477bf90db71c156f89a55bfe4d25177b81fce4aa09294d9e805eec13855"}, - {file = "pydantic_core-2.23.3-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:0a0137ddf462575d9bce863c4c95bac3493ba8e22f8c28ca94634b4a1d3e2bb4"}, - {file = "pydantic_core-2.23.3-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:203171e48946c3164fe7691fc349c79241ff8f28306abd4cad5f4f75ed80bc8d"}, - {file = "pydantic_core-2.23.3-cp313-none-win32.whl", hash = "sha256:76bdab0de4acb3f119c2a4bff740e0c7dc2e6de7692774620f7452ce11ca76c8"}, - {file = "pydantic_core-2.23.3-cp313-none-win_amd64.whl", hash = "sha256:37ba321ac2a46100c578a92e9a6aa33afe9ec99ffa084424291d84e456f490c1"}, - {file = "pydantic_core-2.23.3-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:d063c6b9fed7d992bcbebfc9133f4c24b7a7f215d6b102f3e082b1117cddb72c"}, - {file = "pydantic_core-2.23.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:6cb968da9a0746a0cf521b2b5ef25fc5a0bee9b9a1a8214e0a1cfaea5be7e8a4"}, - {file = "pydantic_core-2.23.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:edbefe079a520c5984e30e1f1f29325054b59534729c25b874a16a5048028d16"}, - {file = "pydantic_core-2.23.3-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:cbaaf2ef20d282659093913da9d402108203f7cb5955020bd8d1ae5a2325d1c4"}, - {file = "pydantic_core-2.23.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fb539d7e5dc4aac345846f290cf504d2fd3c1be26ac4e8b5e4c2b688069ff4cf"}, - {file = "pydantic_core-2.23.3-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7e6f33503c5495059148cc486867e1d24ca35df5fc064686e631e314d959ad5b"}, - {file = "pydantic_core-2.23.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:04b07490bc2f6f2717b10c3969e1b830f5720b632f8ae2f3b8b1542394c47a8e"}, - {file = "pydantic_core-2.23.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:03795b9e8a5d7fda05f3873efc3f59105e2dcff14231680296b87b80bb327295"}, - {file = "pydantic_core-2.23.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:c483dab0f14b8d3f0df0c6c18d70b21b086f74c87ab03c59250dbf6d3c89baba"}, - {file = "pydantic_core-2.23.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8b2682038e255e94baf2c473dca914a7460069171ff5cdd4080be18ab8a7fd6e"}, - {file = "pydantic_core-2.23.3-cp38-none-win32.whl", hash = "sha256:f4a57db8966b3a1d1a350012839c6a0099f0898c56512dfade8a1fe5fb278710"}, - {file = "pydantic_core-2.23.3-cp38-none-win_amd64.whl", hash = "sha256:13dd45ba2561603681a2676ca56006d6dee94493f03d5cadc055d2055615c3ea"}, - {file = "pydantic_core-2.23.3-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:82da2f4703894134a9f000e24965df73cc103e31e8c31906cc1ee89fde72cbd8"}, - {file = "pydantic_core-2.23.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:dd9be0a42de08f4b58a3cc73a123f124f65c24698b95a54c1543065baca8cf0e"}, - {file = "pydantic_core-2.23.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:89b731f25c80830c76fdb13705c68fef6a2b6dc494402987c7ea9584fe189f5d"}, - {file = "pydantic_core-2.23.3-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c6de1ec30c4bb94f3a69c9f5f2182baeda5b809f806676675e9ef6b8dc936f28"}, - {file = "pydantic_core-2.23.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bb68b41c3fa64587412b104294b9cbb027509dc2f6958446c502638d481525ef"}, - {file = "pydantic_core-2.23.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1c3980f2843de5184656aab58698011b42763ccba11c4a8c35936c8dd6c7068c"}, - {file = "pydantic_core-2.23.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:94f85614f2cba13f62c3c6481716e4adeae48e1eaa7e8bac379b9d177d93947a"}, - {file = "pydantic_core-2.23.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:510b7fb0a86dc8f10a8bb43bd2f97beb63cffad1203071dc434dac26453955cd"}, - {file = "pydantic_core-2.23.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:1eba2f7ce3e30ee2170410e2171867ea73dbd692433b81a93758ab2de6c64835"}, - {file = "pydantic_core-2.23.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:4b259fd8409ab84b4041b7b3f24dcc41e4696f180b775961ca8142b5b21d0e70"}, - {file = "pydantic_core-2.23.3-cp39-none-win32.whl", hash = "sha256:40d9bd259538dba2f40963286009bf7caf18b5112b19d2b55b09c14dde6db6a7"}, - {file = "pydantic_core-2.23.3-cp39-none-win_amd64.whl", hash = "sha256:5a8cd3074a98ee70173a8633ad3c10e00dcb991ecec57263aacb4095c5efb958"}, - {file = "pydantic_core-2.23.3-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:f399e8657c67313476a121a6944311fab377085ca7f490648c9af97fc732732d"}, - {file = "pydantic_core-2.23.3-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:6b5547d098c76e1694ba85f05b595720d7c60d342f24d5aad32c3049131fa5c4"}, - {file = "pydantic_core-2.23.3-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0dda0290a6f608504882d9f7650975b4651ff91c85673341789a476b1159f211"}, - {file = "pydantic_core-2.23.3-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:65b6e5da855e9c55a0c67f4db8a492bf13d8d3316a59999cfbaf98cc6e401961"}, - {file = "pydantic_core-2.23.3-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:09e926397f392059ce0afdcac920df29d9c833256354d0c55f1584b0b70cf07e"}, - {file = "pydantic_core-2.23.3-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:87cfa0ed6b8c5bd6ae8b66de941cece179281239d482f363814d2b986b79cedc"}, - {file = "pydantic_core-2.23.3-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:e61328920154b6a44d98cabcb709f10e8b74276bc709c9a513a8c37a18786cc4"}, - {file = "pydantic_core-2.23.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:ce3317d155628301d649fe5e16a99528d5680af4ec7aa70b90b8dacd2d725c9b"}, - {file = "pydantic_core-2.23.3-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:e89513f014c6be0d17b00a9a7c81b1c426f4eb9224b15433f3d98c1a071f8433"}, - {file = "pydantic_core-2.23.3-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:4f62c1c953d7ee375df5eb2e44ad50ce2f5aff931723b398b8bc6f0ac159791a"}, - {file = "pydantic_core-2.23.3-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2718443bc671c7ac331de4eef9b673063b10af32a0bb385019ad61dcf2cc8f6c"}, - {file = "pydantic_core-2.23.3-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a0d90e08b2727c5d01af1b5ef4121d2f0c99fbee692c762f4d9d0409c9da6541"}, - {file = "pydantic_core-2.23.3-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2b676583fc459c64146debea14ba3af54e540b61762dfc0613dc4e98c3f66eeb"}, - {file = "pydantic_core-2.23.3-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:50e4661f3337977740fdbfbae084ae5693e505ca2b3130a6d4eb0f2281dc43b8"}, - {file = "pydantic_core-2.23.3-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:68f4cf373f0de6abfe599a38307f4417c1c867ca381c03df27c873a9069cda25"}, - {file = "pydantic_core-2.23.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:59d52cf01854cb26c46958552a21acb10dd78a52aa34c86f284e66b209db8cab"}, - {file = "pydantic_core-2.23.3.tar.gz", hash = "sha256:3cb0f65d8b4121c1b015c60104a685feb929a29d7cf204387c7f2688c7974690"}, + {file = "pydantic_core-2.23.4-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:b10bd51f823d891193d4717448fab065733958bdb6a6b351967bd349d48d5c9b"}, + {file = "pydantic_core-2.23.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4fc714bdbfb534f94034efaa6eadd74e5b93c8fa6315565a222f7b6f42ca1166"}, + {file = "pydantic_core-2.23.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:63e46b3169866bd62849936de036f901a9356e36376079b05efa83caeaa02ceb"}, + {file = "pydantic_core-2.23.4-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ed1a53de42fbe34853ba90513cea21673481cd81ed1be739f7f2efb931b24916"}, + {file = "pydantic_core-2.23.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cfdd16ab5e59fc31b5e906d1a3f666571abc367598e3e02c83403acabc092e07"}, + {file = "pydantic_core-2.23.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:255a8ef062cbf6674450e668482456abac99a5583bbafb73f9ad469540a3a232"}, + {file = "pydantic_core-2.23.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4a7cd62e831afe623fbb7aabbb4fe583212115b3ef38a9f6b71869ba644624a2"}, + {file = "pydantic_core-2.23.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f09e2ff1f17c2b51f2bc76d1cc33da96298f0a036a137f5440ab3ec5360b624f"}, + {file = "pydantic_core-2.23.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:e38e63e6f3d1cec5a27e0afe90a085af8b6806ee208b33030e65b6516353f1a3"}, + {file = "pydantic_core-2.23.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:0dbd8dbed2085ed23b5c04afa29d8fd2771674223135dc9bc937f3c09284d071"}, + {file = "pydantic_core-2.23.4-cp310-none-win32.whl", hash = "sha256:6531b7ca5f951d663c339002e91aaebda765ec7d61b7d1e3991051906ddde119"}, + {file = "pydantic_core-2.23.4-cp310-none-win_amd64.whl", hash = "sha256:7c9129eb40958b3d4500fa2467e6a83356b3b61bfff1b414c7361d9220f9ae8f"}, + {file = "pydantic_core-2.23.4-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:77733e3892bb0a7fa797826361ce8a9184d25c8dffaec60b7ffe928153680ba8"}, + {file = "pydantic_core-2.23.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1b84d168f6c48fabd1f2027a3d1bdfe62f92cade1fb273a5d68e621da0e44e6d"}, + {file = "pydantic_core-2.23.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:df49e7a0861a8c36d089c1ed57d308623d60416dab2647a4a17fe050ba85de0e"}, + {file = "pydantic_core-2.23.4-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ff02b6d461a6de369f07ec15e465a88895f3223eb75073ffea56b84d9331f607"}, + {file = "pydantic_core-2.23.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:996a38a83508c54c78a5f41456b0103c30508fed9abcad0a59b876d7398f25fd"}, + {file = "pydantic_core-2.23.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d97683ddee4723ae8c95d1eddac7c192e8c552da0c73a925a89fa8649bf13eea"}, + {file = "pydantic_core-2.23.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:216f9b2d7713eb98cb83c80b9c794de1f6b7e3145eef40400c62e86cee5f4e1e"}, + {file = "pydantic_core-2.23.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6f783e0ec4803c787bcea93e13e9932edab72068f68ecffdf86a99fd5918878b"}, + {file = "pydantic_core-2.23.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:d0776dea117cf5272382634bd2a5c1b6eb16767c223c6a5317cd3e2a757c61a0"}, + {file = "pydantic_core-2.23.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d5f7a395a8cf1621939692dba2a6b6a830efa6b3cee787d82c7de1ad2930de64"}, + {file = "pydantic_core-2.23.4-cp311-none-win32.whl", hash = "sha256:74b9127ffea03643e998e0c5ad9bd3811d3dac8c676e47db17b0ee7c3c3bf35f"}, + {file = "pydantic_core-2.23.4-cp311-none-win_amd64.whl", hash = "sha256:98d134c954828488b153d88ba1f34e14259284f256180ce659e8d83e9c05eaa3"}, + {file = "pydantic_core-2.23.4-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:f3e0da4ebaef65158d4dfd7d3678aad692f7666877df0002b8a522cdf088f231"}, + {file = "pydantic_core-2.23.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f69a8e0b033b747bb3e36a44e7732f0c99f7edd5cea723d45bc0d6e95377ffee"}, + {file = "pydantic_core-2.23.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:723314c1d51722ab28bfcd5240d858512ffd3116449c557a1336cbe3919beb87"}, + {file = "pydantic_core-2.23.4-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bb2802e667b7051a1bebbfe93684841cc9351004e2badbd6411bf357ab8d5ac8"}, + {file = "pydantic_core-2.23.4-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d18ca8148bebe1b0a382a27a8ee60350091a6ddaf475fa05ef50dc35b5df6327"}, + {file = "pydantic_core-2.23.4-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:33e3d65a85a2a4a0dc3b092b938a4062b1a05f3a9abde65ea93b233bca0e03f2"}, + {file = "pydantic_core-2.23.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:128585782e5bfa515c590ccee4b727fb76925dd04a98864182b22e89a4e6ed36"}, + {file = "pydantic_core-2.23.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:68665f4c17edcceecc112dfed5dbe6f92261fb9d6054b47d01bf6371a6196126"}, + {file = "pydantic_core-2.23.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:20152074317d9bed6b7a95ade3b7d6054845d70584216160860425f4fbd5ee9e"}, + {file = "pydantic_core-2.23.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:9261d3ce84fa1d38ed649c3638feefeae23d32ba9182963e465d58d62203bd24"}, + {file = "pydantic_core-2.23.4-cp312-none-win32.whl", hash = "sha256:4ba762ed58e8d68657fc1281e9bb72e1c3e79cc5d464be146e260c541ec12d84"}, + {file = "pydantic_core-2.23.4-cp312-none-win_amd64.whl", hash = "sha256:97df63000f4fea395b2824da80e169731088656d1818a11b95f3b173747b6cd9"}, + {file = "pydantic_core-2.23.4-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:7530e201d10d7d14abce4fb54cfe5b94a0aefc87da539d0346a484ead376c3cc"}, + {file = "pydantic_core-2.23.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:df933278128ea1cd77772673c73954e53a1c95a4fdf41eef97c2b779271bd0bd"}, + {file = "pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0cb3da3fd1b6a5d0279a01877713dbda118a2a4fc6f0d821a57da2e464793f05"}, + {file = "pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:42c6dcb030aefb668a2b7009c85b27f90e51e6a3b4d5c9bc4c57631292015b0d"}, + {file = "pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:696dd8d674d6ce621ab9d45b205df149399e4bb9aa34102c970b721554828510"}, + {file = "pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2971bb5ffe72cc0f555c13e19b23c85b654dd2a8f7ab493c262071377bfce9f6"}, + {file = "pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8394d940e5d400d04cad4f75c0598665cbb81aecefaca82ca85bd28264af7f9b"}, + {file = "pydantic_core-2.23.4-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:0dff76e0602ca7d4cdaacc1ac4c005e0ce0dcfe095d5b5259163a80d3a10d327"}, + {file = "pydantic_core-2.23.4-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:7d32706badfe136888bdea71c0def994644e09fff0bfe47441deaed8e96fdbc6"}, + {file = "pydantic_core-2.23.4-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ed541d70698978a20eb63d8c5d72f2cc6d7079d9d90f6b50bad07826f1320f5f"}, + {file = "pydantic_core-2.23.4-cp313-none-win32.whl", hash = "sha256:3d5639516376dce1940ea36edf408c554475369f5da2abd45d44621cb616f769"}, + {file = "pydantic_core-2.23.4-cp313-none-win_amd64.whl", hash = "sha256:5a1504ad17ba4210df3a045132a7baeeba5a200e930f57512ee02909fc5c4cb5"}, + {file = "pydantic_core-2.23.4-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:d4488a93b071c04dc20f5cecc3631fc78b9789dd72483ba15d423b5b3689b555"}, + {file = "pydantic_core-2.23.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:81965a16b675b35e1d09dd14df53f190f9129c0202356ed44ab2728b1c905658"}, + {file = "pydantic_core-2.23.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4ffa2ebd4c8530079140dd2d7f794a9d9a73cbb8e9d59ffe24c63436efa8f271"}, + {file = "pydantic_core-2.23.4-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:61817945f2fe7d166e75fbfb28004034b48e44878177fc54d81688e7b85a3665"}, + {file = "pydantic_core-2.23.4-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:29d2c342c4bc01b88402d60189f3df065fb0dda3654744d5a165a5288a657368"}, + {file = "pydantic_core-2.23.4-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5e11661ce0fd30a6790e8bcdf263b9ec5988e95e63cf901972107efc49218b13"}, + {file = "pydantic_core-2.23.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9d18368b137c6295db49ce7218b1a9ba15c5bc254c96d7c9f9e924a9bc7825ad"}, + {file = "pydantic_core-2.23.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ec4e55f79b1c4ffb2eecd8a0cfba9955a2588497d96851f4c8f99aa4a1d39b12"}, + {file = "pydantic_core-2.23.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:374a5e5049eda9e0a44c696c7ade3ff355f06b1fe0bb945ea3cac2bc336478a2"}, + {file = "pydantic_core-2.23.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:5c364564d17da23db1106787675fc7af45f2f7b58b4173bfdd105564e132e6fb"}, + {file = "pydantic_core-2.23.4-cp38-none-win32.whl", hash = "sha256:d7a80d21d613eec45e3d41eb22f8f94ddc758a6c4720842dc74c0581f54993d6"}, + {file = "pydantic_core-2.23.4-cp38-none-win_amd64.whl", hash = "sha256:5f5ff8d839f4566a474a969508fe1c5e59c31c80d9e140566f9a37bba7b8d556"}, + {file = "pydantic_core-2.23.4-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:a4fa4fc04dff799089689f4fd502ce7d59de529fc2f40a2c8836886c03e0175a"}, + {file = "pydantic_core-2.23.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0a7df63886be5e270da67e0966cf4afbae86069501d35c8c1b3b6c168f42cb36"}, + {file = "pydantic_core-2.23.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dcedcd19a557e182628afa1d553c3895a9f825b936415d0dbd3cd0bbcfd29b4b"}, + {file = "pydantic_core-2.23.4-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5f54b118ce5de9ac21c363d9b3caa6c800341e8c47a508787e5868c6b79c9323"}, + {file = "pydantic_core-2.23.4-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:86d2f57d3e1379a9525c5ab067b27dbb8a0642fb5d454e17a9ac434f9ce523e3"}, + {file = "pydantic_core-2.23.4-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:de6d1d1b9e5101508cb37ab0d972357cac5235f5c6533d1071964c47139257df"}, + {file = "pydantic_core-2.23.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1278e0d324f6908e872730c9102b0112477a7f7cf88b308e4fc36ce1bdb6d58c"}, + {file = "pydantic_core-2.23.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9a6b5099eeec78827553827f4c6b8615978bb4b6a88e5d9b93eddf8bb6790f55"}, + {file = "pydantic_core-2.23.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:e55541f756f9b3ee346b840103f32779c695a19826a4c442b7954550a0972040"}, + {file = "pydantic_core-2.23.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a5c7ba8ffb6d6f8f2ab08743be203654bb1aaa8c9dcb09f82ddd34eadb695605"}, + {file = "pydantic_core-2.23.4-cp39-none-win32.whl", hash = "sha256:37b0fe330e4a58d3c58b24d91d1eb102aeec675a3db4c292ec3928ecd892a9a6"}, + {file = "pydantic_core-2.23.4-cp39-none-win_amd64.whl", hash = "sha256:1498bec4c05c9c787bde9125cfdcc63a41004ff167f495063191b863399b1a29"}, + {file = "pydantic_core-2.23.4-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:f455ee30a9d61d3e1a15abd5068827773d6e4dc513e795f380cdd59932c782d5"}, + {file = "pydantic_core-2.23.4-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:1e90d2e3bd2c3863d48525d297cd143fe541be8bbf6f579504b9712cb6b643ec"}, + {file = "pydantic_core-2.23.4-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2e203fdf807ac7e12ab59ca2bfcabb38c7cf0b33c41efeb00f8e5da1d86af480"}, + {file = "pydantic_core-2.23.4-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e08277a400de01bc72436a0ccd02bdf596631411f592ad985dcee21445bd0068"}, + {file = "pydantic_core-2.23.4-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f220b0eea5965dec25480b6333c788fb72ce5f9129e8759ef876a1d805d00801"}, + {file = "pydantic_core-2.23.4-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:d06b0c8da4f16d1d1e352134427cb194a0a6e19ad5db9161bf32b2113409e728"}, + {file = "pydantic_core-2.23.4-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:ba1a0996f6c2773bd83e63f18914c1de3c9dd26d55f4ac302a7efe93fb8e7433"}, + {file = "pydantic_core-2.23.4-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:9a5bce9d23aac8f0cf0836ecfc033896aa8443b501c58d0602dbfd5bd5b37753"}, + {file = "pydantic_core-2.23.4-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:78ddaaa81421a29574a682b3179d4cf9e6d405a09b99d93ddcf7e5239c742e21"}, + {file = "pydantic_core-2.23.4-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:883a91b5dd7d26492ff2f04f40fbb652de40fcc0afe07e8129e8ae779c2110eb"}, + {file = "pydantic_core-2.23.4-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88ad334a15b32a791ea935af224b9de1bf99bcd62fabf745d5f3442199d86d59"}, + {file = "pydantic_core-2.23.4-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:233710f069d251feb12a56da21e14cca67994eab08362207785cf8c598e74577"}, + {file = "pydantic_core-2.23.4-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:19442362866a753485ba5e4be408964644dd6a09123d9416c54cd49171f50744"}, + {file = "pydantic_core-2.23.4-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:624e278a7d29b6445e4e813af92af37820fafb6dcc55c012c834f9e26f9aaaef"}, + {file = "pydantic_core-2.23.4-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f5ef8f42bec47f21d07668a043f077d507e5bf4e668d5c6dfe6aaba89de1a5b8"}, + {file = "pydantic_core-2.23.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:aea443fffa9fbe3af1a9ba721a87f926fe548d32cab71d188a6ede77d0ff244e"}, + {file = "pydantic_core-2.23.4.tar.gz", hash = "sha256:2584f7cf844ac4d970fba483a717dbe10c1c1c96a969bf65d61ffe94df1b2863"}, ] [package.dependencies] @@ -1419,13 +1466,13 @@ windows-terminal = ["colorama (>=0.4.6)"] [[package]] name = "pyproject-api" -version = "1.7.1" +version = "1.8.0" description = "API to interact with the python pyproject.toml based projects" optional = false python-versions = ">=3.8" files = [ - {file = "pyproject_api-1.7.1-py3-none-any.whl", hash = "sha256:2dc1654062c2b27733d8fd4cdda672b22fe8741ef1dde8e3a998a9547b071eeb"}, - {file = "pyproject_api-1.7.1.tar.gz", hash = "sha256:7ebc6cd10710f89f4cf2a2731710a98abce37ebff19427116ff2174c9236a827"}, + {file = "pyproject_api-1.8.0-py3-none-any.whl", hash = "sha256:3d7d347a047afe796fd5d1885b1e391ba29be7169bd2f102fcd378f04273d228"}, + {file = "pyproject_api-1.8.0.tar.gz", hash = "sha256:77b8049f2feb5d33eefcc21b57f1e279636277a8ac8ad6b5871037b243778496"}, ] [package.dependencies] @@ -1433,8 +1480,8 @@ packaging = ">=24.1" tomli = {version = ">=2.0.1", markers = "python_version < \"3.11\""} [package.extras] -docs = ["furo (>=2024.5.6)", "sphinx-autodoc-typehints (>=2.2.1)"] -testing = ["covdefaults (>=2.3)", "pytest (>=8.2.2)", "pytest-cov (>=5)", "pytest-mock (>=3.14)", "setuptools (>=70.1)"] +docs = ["furo (>=2024.8.6)", "sphinx-autodoc-typehints (>=2.4.1)"] +testing = ["covdefaults (>=2.3)", "pytest (>=8.3.3)", "pytest-cov (>=5)", "pytest-mock (>=3.14)", "setuptools (>=75.1)"] [[package]] name = "pytest" @@ -1622,23 +1669,23 @@ use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] [[package]] name = "setuptools" -version = "74.1.2" +version = "75.3.0" description = "Easily download, build, install, upgrade, and uninstall Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "setuptools-74.1.2-py3-none-any.whl", hash = "sha256:5f4c08aa4d3ebcb57a50c33b1b07e94315d7fc7230f7115e47fc99776c8ce308"}, - {file = "setuptools-74.1.2.tar.gz", hash = "sha256:95b40ed940a1c67eb70fc099094bd6e99c6ee7c23aa2306f4d2697ba7916f9c6"}, + {file = "setuptools-75.3.0-py3-none-any.whl", hash = "sha256:f2504966861356aa38616760c0f66568e535562374995367b4e69c7143cf6bcd"}, + {file = "setuptools-75.3.0.tar.gz", hash = "sha256:fba5dd4d766e97be1b1681d98712680ae8f2f26d7881245f2ce9e40714f1a686"}, ] [package.extras] check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)", "ruff (>=0.5.2)"] -core = ["importlib-metadata (>=6)", "importlib-resources (>=5.10.2)", "jaraco.text (>=3.7)", "more-itertools (>=8.8)", "packaging (>=24)", "platformdirs (>=2.6.2)", "tomli (>=2.0.1)", "wheel (>=0.43.0)"] +core = ["importlib-metadata (>=6)", "importlib-resources (>=5.10.2)", "jaraco.collections", "jaraco.functools", "jaraco.text (>=3.7)", "more-itertools", "more-itertools (>=8.8)", "packaging", "packaging (>=24)", "platformdirs (>=4.2.2)", "tomli (>=2.0.1)", "wheel (>=0.43.0)"] cover = ["pytest-cov"] doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "pyproject-hooks (!=1.1)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier", "towncrier (<24.7)"] enabler = ["pytest-enabler (>=2.2)"] -test = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "jaraco.test", "packaging (>=23.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.*)", "pytest-home (>=0.5)", "pytest-perf", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel (>=0.44.0)"] -type = ["importlib-metadata (>=7.0.2)", "jaraco.develop (>=7.21)", "mypy (==1.11.*)", "pytest-mypy"] +test = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "jaraco.test (>=5.5)", "packaging (>=23.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.*)", "pytest-home (>=0.5)", "pytest-perf", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel (>=0.44.0)"] +type = ["importlib-metadata (>=7.0.2)", "jaraco.develop (>=7.21)", "mypy (==1.12.*)", "pytest-mypy"] [[package]] name = "six" @@ -1816,13 +1863,13 @@ files = [ [[package]] name = "tomli" -version = "2.0.1" +version = "2.1.0" description = "A lil' TOML parser" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, - {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, + {file = "tomli-2.1.0-py3-none-any.whl", hash = "sha256:a5c57c3d1c56f5ccdf89f6523458f60ef716e210fc47c4cfb188c5ba473e0391"}, + {file = "tomli-2.1.0.tar.gz", hash = "sha256:3f646cae2aec94e17d04973e4249548320197cfabdf130015d023de4b74d8ab8"}, ] [[package]] @@ -1838,30 +1885,30 @@ files = [ [[package]] name = "tox" -version = "4.18.1" +version = "4.23.2" description = "tox is a generic virtualenv management and test command line tool" optional = false python-versions = ">=3.8" files = [ - {file = "tox-4.18.1-py3-none-any.whl", hash = "sha256:35d472032ee1f73fe20c3e0e73d7073a4e85075c86ff02c576f9fc7c6a15a578"}, - {file = "tox-4.18.1.tar.gz", hash = "sha256:3c0c96bc3a568a5c7e66387a4cfcf8c875b52e09f4d47c9f7a277ec82f1a0b11"}, + {file = "tox-4.23.2-py3-none-any.whl", hash = "sha256:452bc32bb031f2282881a2118923176445bac783ab97c874b8770ab4c3b76c38"}, + {file = "tox-4.23.2.tar.gz", hash = "sha256:86075e00e555df6e82e74cfc333917f91ecb47ffbc868dcafbd2672e332f4a2c"}, ] [package.dependencies] cachetools = ">=5.5" chardet = ">=5.2" colorama = ">=0.4.6" -filelock = ">=3.15.4" +filelock = ">=3.16.1" packaging = ">=24.1" -platformdirs = ">=4.2.2" +platformdirs = ">=4.3.6" pluggy = ">=1.5" -pyproject-api = ">=1.7.1" +pyproject-api = ">=1.8" tomli = {version = ">=2.0.1", markers = "python_version < \"3.11\""} -virtualenv = ">=20.26.3" +typing-extensions = {version = ">=4.12.2", markers = "python_version < \"3.11\""} +virtualenv = ">=20.26.6" [package.extras] -docs = ["furo (>=2024.8.6)", "sphinx (>=8.0.2)", "sphinx-argparse-cli (>=1.17)", "sphinx-autodoc-typehints (>=2.4)", "sphinx-copybutton (>=0.5.2)", "sphinx-inline-tabs (>=2023.4.21)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=24.8)"] -testing = ["build[virtualenv] (>=1.2.2)", "covdefaults (>=2.3)", "detect-test-pollution (>=1.2)", "devpi-process (>=1)", "diff-cover (>=9.1.1)", "distlib (>=0.3.8)", "flaky (>=3.8.1)", "hatch-vcs (>=0.4)", "hatchling (>=1.25)", "psutil (>=6)", "pytest (>=8.3.2)", "pytest-cov (>=5)", "pytest-mock (>=3.14)", "pytest-xdist (>=3.6.1)", "re-assert (>=1.1)", "setuptools (>=74.1.2)", "time-machine (>=2.15)", "wheel (>=0.44)"] +test = ["devpi-process (>=1.0.2)", "pytest (>=8.3.3)", "pytest-mock (>=3.14)"] [[package]] name = "typing-extensions" @@ -1893,13 +1940,13 @@ zstd = ["zstandard (>=0.18.0)"] [[package]] name = "virtualenv" -version = "20.26.4" +version = "20.27.1" description = "Virtual Python Environment builder" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "virtualenv-20.26.4-py3-none-any.whl", hash = "sha256:48f2695d9809277003f30776d155615ffc11328e6a0a8c1f0ec80188d7874a55"}, - {file = "virtualenv-20.26.4.tar.gz", hash = "sha256:c17f4e0f3e6036e9f26700446f85c76ab11df65ff6d8a9cbfad9f71aabfcf23c"}, + {file = "virtualenv-20.27.1-py3-none-any.whl", hash = "sha256:f11f1b8a29525562925f745563bfd48b189450f61fb34c4f9cc79dd5aa32a1f4"}, + {file = "virtualenv-20.27.1.tar.gz", hash = "sha256:142c6be10212543b32c6c45d3d3893dff89112cc588b7d0879ae5a1ec03a47ba"}, ] [package.dependencies] @@ -1929,4 +1976,4 @@ rust-codec = ["betterproto-rust-codec"] [metadata] lock-version = "2.0" python-versions = "^3.8" -content-hash = "fc54d22a1ce7a9f780642a5c52815dbde0fc0c6f83db19c8dd56a06471c8bd86" +content-hash = "b850ffa2bbe496b8debb553b4d3af07cf8524ea35f34e808f965c0947a6293f6" diff --git a/pyproject.toml b/pyproject.toml index 6a32086db..50c0107ca 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -13,11 +13,11 @@ packages = [ [tool.poetry.dependencies] python = "^3.8" -black = { version = ">=23.1.0", optional = true } +black = { version = "=23.1.0", optional = true } grpclib = "^0.4.1" jinja2 = { version = ">=3.0.3", optional = true } python-dateutil = "^2.8" -isort = { version = "^5.11.5", optional = true } +isort = { version = "=5.11.5", optional = true } typing-extensions = "^4.7.1" betterproto-rust-codec = { version = "0.1.1", optional = true } diff --git a/src/betterproto/__init__.py b/src/betterproto/__init__.py index 3217f4c57..6bd06d4b6 100644 --- a/src/betterproto/__init__.py +++ b/src/betterproto/__init__.py @@ -205,9 +205,12 @@ def dataclass_field( ) -> dataclasses.Field: """Creates a dataclass field with attached protobuf metadata.""" if repeated: + def default_factory(): return [] + elif optional or group: + def default_factory(): return None @@ -226,96 +229,251 @@ def default_factory(): # out at runtime. The generated dataclass variables are still typed correctly. -def enum_field(number: int, enum_default_value: Callable[[], Enum], group: Optional[str] = None, optional: bool = False, repeated: bool = False) -> Any: - return dataclass_field(number, TYPE_ENUM, enum_default_value, group=group, optional=optional, repeated=repeated) +def enum_field( + number: int, + enum_default_value: Callable[[], Enum], + group: Optional[str] = None, + optional: bool = False, + repeated: bool = False, +) -> Any: + return dataclass_field( + number, + TYPE_ENUM, + enum_default_value, + group=group, + optional=optional, + repeated=repeated, + ) -def bool_field(number: int, group: Optional[str] = None, optional: bool = False, repeated: bool = False) -> Any: - return dataclass_field(number, TYPE_BOOL, lambda: False, group=group, optional=optional, repeated=repeated) +def bool_field( + number: int, + group: Optional[str] = None, + optional: bool = False, + repeated: bool = False, +) -> Any: + return dataclass_field( + number, + TYPE_BOOL, + lambda: False, + group=group, + optional=optional, + repeated=repeated, + ) def int32_field( - number: int, group: Optional[str] = None, optional: bool = False, repeated: bool = False, + number: int, + group: Optional[str] = None, + optional: bool = False, + repeated: bool = False, ) -> Any: - return dataclass_field(number, TYPE_INT32, lambda: 0, group=group, optional=optional, repeated=repeated) + return dataclass_field( + number, TYPE_INT32, lambda: 0, group=group, optional=optional, repeated=repeated + ) def int64_field( - number: int, group: Optional[str] = None, optional: bool = False, repeated: bool = False, + number: int, + group: Optional[str] = None, + optional: bool = False, + repeated: bool = False, ) -> Any: - return dataclass_field(number, TYPE_INT64, lambda: 0, group=group, optional=optional, repeated=repeated) + return dataclass_field( + number, TYPE_INT64, lambda: 0, group=group, optional=optional, repeated=repeated + ) def uint32_field( - number: int, group: Optional[str] = None, optional: bool = False, repeated: bool = False, + number: int, + group: Optional[str] = None, + optional: bool = False, + repeated: bool = False, ) -> Any: - return dataclass_field(number, TYPE_UINT32, lambda: 0, group=group, optional=optional, repeated=repeated) + return dataclass_field( + number, + TYPE_UINT32, + lambda: 0, + group=group, + optional=optional, + repeated=repeated, + ) def uint64_field( - number: int, group: Optional[str] = None, optional: bool = False, repeated: bool = False, + number: int, + group: Optional[str] = None, + optional: bool = False, + repeated: bool = False, ) -> Any: - return dataclass_field(number, TYPE_UINT64, lambda: 0, group=group, optional=optional, repeated=repeated) + return dataclass_field( + number, + TYPE_UINT64, + lambda: 0, + group=group, + optional=optional, + repeated=repeated, + ) def sint32_field( - number: int, group: Optional[str] = None, optional: bool = False, repeated: bool = False, + number: int, + group: Optional[str] = None, + optional: bool = False, + repeated: bool = False, ) -> Any: - return dataclass_field(number, TYPE_SINT32, lambda: 0, group=group, optional=optional, repeated=repeated) + return dataclass_field( + number, + TYPE_SINT32, + lambda: 0, + group=group, + optional=optional, + repeated=repeated, + ) def sint64_field( - number: int, group: Optional[str] = None, optional: bool = False, repeated: bool = False, + number: int, + group: Optional[str] = None, + optional: bool = False, + repeated: bool = False, ) -> Any: - return dataclass_field(number, TYPE_SINT64, lambda: 0, group=group, optional=optional, repeated=repeated) + return dataclass_field( + number, + TYPE_SINT64, + lambda: 0, + group=group, + optional=optional, + repeated=repeated, + ) def float_field( - number: int, group: Optional[str] = None, optional: bool = False, repeated: bool = False, + number: int, + group: Optional[str] = None, + optional: bool = False, + repeated: bool = False, ) -> Any: - return dataclass_field(number, TYPE_FLOAT, lambda: 0., group=group, optional=optional, repeated=repeated) + return dataclass_field( + number, + TYPE_FLOAT, + lambda: 0.0, + group=group, + optional=optional, + repeated=repeated, + ) def double_field( - number: int, group: Optional[str] = None, optional: bool = False, repeated: bool = False, + number: int, + group: Optional[str] = None, + optional: bool = False, + repeated: bool = False, ) -> Any: - return dataclass_field(number, TYPE_DOUBLE, lambda: 0., group=group, optional=optional, repeated=repeated) + return dataclass_field( + number, + TYPE_DOUBLE, + lambda: 0.0, + group=group, + optional=optional, + repeated=repeated, + ) def fixed32_field( - number: int, group: Optional[str] = None, optional: bool = False, repeated: bool = False, + number: int, + group: Optional[str] = None, + optional: bool = False, + repeated: bool = False, ) -> Any: - return dataclass_field(number, TYPE_FIXED32, lambda: 0., group=group, optional=optional, repeated=repeated) + return dataclass_field( + number, + TYPE_FIXED32, + lambda: 0.0, + group=group, + optional=optional, + repeated=repeated, + ) def fixed64_field( - number: int, group: Optional[str] = None, optional: bool = False, repeated: bool = False, + number: int, + group: Optional[str] = None, + optional: bool = False, + repeated: bool = False, ) -> Any: - return dataclass_field(number, TYPE_FIXED64, lambda: 0., group=group, optional=optional, repeated=repeated) + return dataclass_field( + number, + TYPE_FIXED64, + lambda: 0.0, + group=group, + optional=optional, + repeated=repeated, + ) def sfixed32_field( - number: int, group: Optional[str] = None, optional: bool = False, repeated: bool = False, + number: int, + group: Optional[str] = None, + optional: bool = False, + repeated: bool = False, ) -> Any: - return dataclass_field(number, TYPE_SFIXED32, lambda: 0., group=group, optional=optional, repeated=repeated) + return dataclass_field( + number, + TYPE_SFIXED32, + lambda: 0.0, + group=group, + optional=optional, + repeated=repeated, + ) def sfixed64_field( - number: int, group: Optional[str] = None, optional: bool = False, repeated: bool = False, + number: int, + group: Optional[str] = None, + optional: bool = False, + repeated: bool = False, ) -> Any: - return dataclass_field(number, TYPE_SFIXED64, lambda: 0., group=group, optional=optional, repeated=repeated) + return dataclass_field( + number, + TYPE_SFIXED64, + lambda: 0.0, + group=group, + optional=optional, + repeated=repeated, + ) def string_field( - number: int, group: Optional[str] = None, optional: bool = False, repeated: bool = False, + number: int, + group: Optional[str] = None, + optional: bool = False, + repeated: bool = False, ) -> Any: - return dataclass_field(number, TYPE_STRING, lambda: "", group=group, optional=optional, repeated=repeated) + return dataclass_field( + number, + TYPE_STRING, + lambda: "", + group=group, + optional=optional, + repeated=repeated, + ) def bytes_field( - number: int, group: Optional[str] = None, optional: bool = False, repeated: bool = False, + number: int, + group: Optional[str] = None, + optional: bool = False, + repeated: bool = False, ) -> Any: - return dataclass_field(number, TYPE_BYTES, lambda: b"", group=group, optional=optional, repeated=repeated) + return dataclass_field( + number, + TYPE_BYTES, + lambda: b"", + group=group, + optional=optional, + repeated=repeated, + ) def message_field( @@ -326,7 +484,13 @@ def message_field( repeated: bool = False, ) -> Any: return dataclass_field( - number, TYPE_MESSAGE, lambda: None, group=group, wraps=wraps, optional=optional, repeated=repeated + number, + TYPE_MESSAGE, + lambda: None, + group=group, + wraps=wraps, + optional=optional, + repeated=repeated, ) @@ -719,8 +883,20 @@ def _get_cls_by_field( field_cls[field.name] = dataclasses.make_dataclass( "Entry", [ - ("key", kt, dataclass_field(1, meta.map_types[0], default_factory=lambda: kt())), - ("value", vt, dataclass_field(2, meta.map_types[1], default_factory=lambda: vt())), + ( + "key", + kt, + dataclass_field( + 1, meta.map_types[0], default_factory=lambda: kt() + ), + ), + ( + "value", + vt, + dataclass_field( + 2, meta.map_types[1], default_factory=lambda: vt() + ), + ), ], bases=(Message,), ) diff --git a/src/betterproto/lib/pydantic/google/protobuf/__init__.py b/src/betterproto/lib/pydantic/google/protobuf/__init__.py index 4e55e1d33..e1d32a37a 100644 --- a/src/betterproto/lib/pydantic/google/protobuf/__init__.py +++ b/src/betterproto/lib/pydantic/google/protobuf/__init__.py @@ -663,7 +663,9 @@ class Type(betterproto.Message): source_context: "SourceContext" = betterproto.message_field(5) """The source context.""" - syntax: "Syntax" = betterproto.enum_field(6, enum_default_value=lambda: Syntax.try_value(0)) + syntax: "Syntax" = betterproto.enum_field( + 6, enum_default_value=lambda: Syntax.try_value(0) + ) """The source syntax.""" edition: str = betterproto.string_field(7) @@ -676,10 +678,14 @@ class Type(betterproto.Message): class Field(betterproto.Message): """A single field of a message type.""" - kind: "FieldKind" = betterproto.enum_field(1, enum_default_value=lambda: FieldKind.try_value(0)) + kind: "FieldKind" = betterproto.enum_field( + 1, enum_default_value=lambda: FieldKind.try_value(0) + ) """The field type.""" - cardinality: "FieldCardinality" = betterproto.enum_field(2, enum_default_value=lambda: FieldCardinality.try_value(0)) + cardinality: "FieldCardinality" = betterproto.enum_field( + 2, enum_default_value=lambda: FieldCardinality.try_value(0) + ) """The field cardinality.""" number: int = betterproto.int32_field(3) @@ -733,7 +739,9 @@ class Enum(betterproto.Message): source_context: "SourceContext" = betterproto.message_field(4) """The source context.""" - syntax: "Syntax" = betterproto.enum_field(5, enum_default_value=lambda: Syntax.try_value(0)) + syntax: "Syntax" = betterproto.enum_field( + 5, enum_default_value=lambda: Syntax.try_value(0) + ) """The source syntax.""" edition: str = betterproto.string_field(6) @@ -838,7 +846,9 @@ class Api(betterproto.Message): mixins: List["Mixin"] = betterproto.message_field(6) """Included interfaces. See [Mixin][].""" - syntax: "Syntax" = betterproto.enum_field(7, enum_default_value=lambda: Syntax.try_value(0)) + syntax: "Syntax" = betterproto.enum_field( + 7, enum_default_value=lambda: Syntax.try_value(0) + ) """The source syntax of the service.""" @@ -864,7 +874,9 @@ class Method(betterproto.Message): options: List["Option"] = betterproto.message_field(6) """Any metadata attached to the method.""" - syntax: "Syntax" = betterproto.enum_field(7, enum_default_value=lambda: Syntax.try_value(0)) + syntax: "Syntax" = betterproto.enum_field( + 7, enum_default_value=lambda: Syntax.try_value(0) + ) """The source syntax of this method.""" @@ -1012,7 +1024,9 @@ class FileDescriptorProto(betterproto.Message): If `edition` is present, this value must be "editions". """ - edition: "Edition" = betterproto.enum_field(14, enum_default_value=lambda: Edition.try_value(0)) + edition: "Edition" = betterproto.enum_field( + 14, enum_default_value=lambda: Edition.try_value(0) + ) """The edition of the proto file.""" @@ -1072,7 +1086,10 @@ class ExtensionRangeOptions(betterproto.Message): features: "FeatureSet" = betterproto.message_field(50) """Any features defined in the specific edition.""" - verification: "ExtensionRangeOptionsVerificationState" = betterproto.enum_field(3, enum_default_value=lambda: ExtensionRangeOptionsVerificationState.try_value(0)) + verification: "ExtensionRangeOptionsVerificationState" = betterproto.enum_field( + 3, + enum_default_value=lambda: ExtensionRangeOptionsVerificationState.try_value(0), + ) """ The verification state of the range. TODO: flip the default to DECLARATION once all empty ranges @@ -1118,8 +1135,12 @@ class FieldDescriptorProto(betterproto.Message): name: str = betterproto.string_field(1) number: int = betterproto.int32_field(3) - label: "FieldDescriptorProtoLabel" = betterproto.enum_field(4, enum_default_value=lambda: FieldDescriptorProtoLabel.try_value(0)) - type: "FieldDescriptorProtoType" = betterproto.enum_field(5, enum_default_value=lambda: FieldDescriptorProtoType.try_value(0)) + label: "FieldDescriptorProtoLabel" = betterproto.enum_field( + 4, enum_default_value=lambda: FieldDescriptorProtoLabel.try_value(0) + ) + type: "FieldDescriptorProtoType" = betterproto.enum_field( + 5, enum_default_value=lambda: FieldDescriptorProtoType.try_value(0) + ) """ If type_name is set, this need not be set. If both this and type_name are set, this must be one of TYPE_ENUM, TYPE_MESSAGE or TYPE_GROUP. @@ -1315,7 +1336,9 @@ class FileOptions(betterproto.Message): This option has no effect on when used with the lite runtime. """ - optimize_for: "FileOptionsOptimizeMode" = betterproto.enum_field(9, enum_default_value=lambda: FileOptionsOptimizeMode.try_value(0)) + optimize_for: "FileOptionsOptimizeMode" = betterproto.enum_field( + 9, enum_default_value=lambda: FileOptionsOptimizeMode.try_value(0) + ) go_package: str = betterproto.string_field(11) """ Sets the Go package where structs generated from this .proto will be @@ -1512,7 +1535,9 @@ def __post_init__(self) -> None: @dataclass(eq=False, repr=False) class FieldOptions(betterproto.Message): - ctype: "FieldOptionsCType" = betterproto.enum_field(1, enum_default_value=lambda: FieldOptionsCType.try_value(0)) + ctype: "FieldOptionsCType" = betterproto.enum_field( + 1, enum_default_value=lambda: FieldOptionsCType.try_value(0) + ) """ The ctype option instructs the C++ code generator to use a different representation of the field than it normally would. See the specific @@ -1533,7 +1558,9 @@ class FieldOptions(betterproto.Message): the behavior. """ - jstype: "FieldOptionsJsType" = betterproto.enum_field(6, enum_default_value=lambda: FieldOptionsJsType.try_value(0)) + jstype: "FieldOptionsJsType" = betterproto.enum_field( + 6, enum_default_value=lambda: FieldOptionsJsType.try_value(0) + ) """ The jstype option determines the JavaScript type used for values of the field. The option is permitted only for 64 bit integral and fixed types @@ -1598,8 +1625,12 @@ class FieldOptions(betterproto.Message): formats, e.g. when the field contains sensitive credentials. """ - retention: "FieldOptionsOptionRetention" = betterproto.enum_field(17, enum_default_value=lambda: FieldOptionsOptionRetention.try_value(0)) - targets: List["FieldOptionsOptionTargetType"] = betterproto.enum_field(19, enum_default_value=lambda: FieldOptionsOptionTargetType.try_value(0)) + retention: "FieldOptionsOptionRetention" = betterproto.enum_field( + 17, enum_default_value=lambda: FieldOptionsOptionRetention.try_value(0) + ) + targets: List["FieldOptionsOptionTargetType"] = betterproto.enum_field( + 19, enum_default_value=lambda: FieldOptionsOptionTargetType.try_value(0) + ) edition_defaults: List["FieldOptionsEditionDefault"] = betterproto.message_field(20) features: "FeatureSet" = betterproto.message_field(21) """Any features defined in the specific edition.""" @@ -1610,7 +1641,9 @@ class FieldOptions(betterproto.Message): @dataclass(eq=False, repr=False) class FieldOptionsEditionDefault(betterproto.Message): - edition: "Edition" = betterproto.enum_field(3, enum_default_value=lambda: Edition.try_value(0)) + edition: "Edition" = betterproto.enum_field( + 3, enum_default_value=lambda: Edition.try_value(0) + ) value: str = betterproto.string_field(2) @@ -1715,7 +1748,9 @@ class MethodOptions(betterproto.Message): this is a formalization for deprecating methods. """ - idempotency_level: "MethodOptionsIdempotencyLevel" = betterproto.enum_field(34, enum_default_value=lambda: MethodOptionsIdempotencyLevel.try_value(0)) + idempotency_level: "MethodOptionsIdempotencyLevel" = betterproto.enum_field( + 34, enum_default_value=lambda: MethodOptionsIdempotencyLevel.try_value(0) + ) features: "FeatureSet" = betterproto.message_field(35) """Any features defined in the specific edition.""" @@ -1773,14 +1808,24 @@ class FeatureSet(betterproto.Message): conflict here. """ - field_presence: "FeatureSetFieldPresence" = betterproto.enum_field(1, enum_default_value=lambda: FeatureSetFieldPresence.try_value(0)) - enum_type: "FeatureSetEnumType" = betterproto.enum_field(2, enum_default_value=lambda: FeatureSetEnumType.try_value(0)) + field_presence: "FeatureSetFieldPresence" = betterproto.enum_field( + 1, enum_default_value=lambda: FeatureSetFieldPresence.try_value(0) + ) + enum_type: "FeatureSetEnumType" = betterproto.enum_field( + 2, enum_default_value=lambda: FeatureSetEnumType.try_value(0) + ) repeated_field_encoding: "FeatureSetRepeatedFieldEncoding" = betterproto.enum_field( 3, enum_default_value=lambda: FeatureSetRepeatedFieldEncoding.try_value(0) ) - utf8_validation: "FeatureSetUtf8Validation" = betterproto.enum_field(4, enum_default_value=lambda: FeatureSetUtf8Validation.try_value(0)) - message_encoding: "FeatureSetMessageEncoding" = betterproto.enum_field(5, enum_default_value=lambda: FeatureSetMessageEncoding.try_value(0)) - json_format: "FeatureSetJsonFormat" = betterproto.enum_field(6, enum_default_value=lambda: FeatureSetJsonFormat.try_value(0)) + utf8_validation: "FeatureSetUtf8Validation" = betterproto.enum_field( + 4, enum_default_value=lambda: FeatureSetUtf8Validation.try_value(0) + ) + message_encoding: "FeatureSetMessageEncoding" = betterproto.enum_field( + 5, enum_default_value=lambda: FeatureSetMessageEncoding.try_value(0) + ) + json_format: "FeatureSetJsonFormat" = betterproto.enum_field( + 6, enum_default_value=lambda: FeatureSetJsonFormat.try_value(0) + ) @dataclass(eq=False, repr=False) @@ -1795,13 +1840,17 @@ class FeatureSetDefaults(betterproto.Message): defaults: List[ "FeatureSetDefaultsFeatureSetEditionDefault" ] = betterproto.message_field(1) - minimum_edition: "Edition" = betterproto.enum_field(4, enum_default_value=lambda: Edition.try_value(0)) + minimum_edition: "Edition" = betterproto.enum_field( + 4, enum_default_value=lambda: Edition.try_value(0) + ) """ The minimum supported edition (inclusive) when this was constructed. Editions before this will not have defaults. """ - maximum_edition: "Edition" = betterproto.enum_field(5, enum_default_value=lambda: Edition.try_value(0)) + maximum_edition: "Edition" = betterproto.enum_field( + 5, enum_default_value=lambda: Edition.try_value(0) + ) """ The maximum known edition (inclusive) when this was constructed. Editions after this will not have reliable defaults. @@ -1817,7 +1866,9 @@ class FeatureSetDefaultsFeatureSetEditionDefault(betterproto.Message): be used. This field must be in strict ascending order by edition. """ - edition: "Edition" = betterproto.enum_field(3, enum_default_value=lambda: Edition.try_value(0)) + edition: "Edition" = betterproto.enum_field( + 3, enum_default_value=lambda: Edition.try_value(0) + ) features: "FeatureSet" = betterproto.message_field(2) @@ -2008,7 +2059,9 @@ class GeneratedCodeInfoAnnotation(betterproto.Message): the last relevant byte (so the length of the text = end - begin). """ - semantic: "GeneratedCodeInfoAnnotationSemantic" = betterproto.enum_field(5, enum_default_value=lambda: GeneratedCodeInfoAnnotationSemantic.try_value(0)) + semantic: "GeneratedCodeInfoAnnotationSemantic" = betterproto.enum_field( + 5, enum_default_value=lambda: GeneratedCodeInfoAnnotationSemantic.try_value(0) + ) @dataclass(eq=False, repr=False) @@ -2372,7 +2425,10 @@ class Value(betterproto.Message): """ null_value: Optional["NullValue"] = betterproto.enum_field( - 1, enum_default_value=lambda: NullValue.try_value(0), optional=True, group="kind" + 1, + enum_default_value=lambda: NullValue.try_value(0), + optional=True, + group="kind", ) """Represents a null value.""" diff --git a/src/betterproto/lib/std/google/protobuf/__init__.py b/src/betterproto/lib/std/google/protobuf/__init__.py index 00a5e1146..0f236fdaa 100644 --- a/src/betterproto/lib/std/google/protobuf/__init__.py +++ b/src/betterproto/lib/std/google/protobuf/__init__.py @@ -75,7 +75,7 @@ Dict, List, Mapping, - Optional + Optional, ) from typing_extensions import Self @@ -511,7 +511,9 @@ class Type(betterproto.Message): source_context: "SourceContext" = betterproto.message_field(5) """The source context.""" - syntax: "Syntax" = betterproto.enum_field(6, enum_default_value=lambda: Syntax.try_value(0)) + syntax: "Syntax" = betterproto.enum_field( + 6, enum_default_value=lambda: Syntax.try_value(0) + ) """The source syntax.""" @@ -519,10 +521,14 @@ class Type(betterproto.Message): class Field(betterproto.Message): """A single field of a message type.""" - kind: "FieldKind" = betterproto.enum_field(1, enum_default_value=lambda: FieldKind.try_value(0)) + kind: "FieldKind" = betterproto.enum_field( + 1, enum_default_value=lambda: FieldKind.try_value(0) + ) """The field type.""" - cardinality: "FieldCardinality" = betterproto.enum_field(2, enum_default_value=lambda: FieldCardinality.try_value(0)) + cardinality: "FieldCardinality" = betterproto.enum_field( + 2, enum_default_value=lambda: FieldCardinality.try_value(0) + ) """The field cardinality.""" number: int = betterproto.int32_field(3) @@ -576,7 +582,9 @@ class Enum(betterproto.Message): source_context: "SourceContext" = betterproto.message_field(4) """The source context.""" - syntax: "Syntax" = betterproto.enum_field(5, enum_default_value=lambda: Syntax.try_value(0)) + syntax: "Syntax" = betterproto.enum_field( + 5, enum_default_value=lambda: Syntax.try_value(0) + ) """The source syntax.""" @@ -676,7 +684,9 @@ class Api(betterproto.Message): mixins: List["Mixin"] = betterproto.message_field(6, repeated=True) """Included interfaces. See [Mixin][].""" - syntax: "Syntax" = betterproto.enum_field(7, enum_default_value=lambda: Syntax.try_value(0)) + syntax: "Syntax" = betterproto.enum_field( + 7, enum_default_value=lambda: Syntax.try_value(0) + ) """The source syntax of the service.""" @@ -702,7 +712,9 @@ class Method(betterproto.Message): options: List["Option"] = betterproto.message_field(6, repeated=True) """Any metadata attached to the method.""" - syntax: "Syntax" = betterproto.enum_field(7, enum_default_value=lambda: Syntax.try_value(0)) + syntax: "Syntax" = betterproto.enum_field( + 7, enum_default_value=lambda: Syntax.try_value(0) + ) """The source syntax of this method.""" @@ -995,12 +1007,16 @@ class FieldDescriptorProto(betterproto.Message): """ - label: "FieldDescriptorProtoLabel" = betterproto.enum_field(4, enum_default_value=lambda: FieldDescriptorProtoLabel.try_value(0)) + label: "FieldDescriptorProtoLabel" = betterproto.enum_field( + 4, enum_default_value=lambda: FieldDescriptorProtoLabel.try_value(0) + ) """ """ - type: "FieldDescriptorProtoType" = betterproto.enum_field(5, enum_default_value=lambda: FieldDescriptorProtoType.try_value(0)) + type: "FieldDescriptorProtoType" = betterproto.enum_field( + 5, enum_default_value=lambda: FieldDescriptorProtoType.try_value(0) + ) """ If type_name is set, this need not be set. If both this and type_name are set, this must be one of TYPE_ENUM, TYPE_MESSAGE or TYPE_GROUP. @@ -1111,9 +1127,9 @@ class EnumDescriptorProto(betterproto.Message): """ - reserved_range: List["EnumDescriptorProtoEnumReservedRange"] = ( - betterproto.message_field(4, repeated=True) - ) + reserved_range: List[ + "EnumDescriptorProtoEnumReservedRange" + ] = betterproto.message_field(4, repeated=True) """ Range of reserved numeric values. Reserved numeric values may not be used by enum values in the same enum declaration. Reserved ranges may not @@ -1293,7 +1309,9 @@ class FileOptions(betterproto.Message): This option has no effect on when used with the lite runtime. """ - optimize_for: "FileOptionsOptimizeMode" = betterproto.enum_field(9, enum_default_value=lambda: FileOptionsOptimizeMode.try_value(0)) + optimize_for: "FileOptionsOptimizeMode" = betterproto.enum_field( + 9, enum_default_value=lambda: FileOptionsOptimizeMode.try_value(0) + ) """ """ @@ -1487,7 +1505,9 @@ class MessageOptions(betterproto.Message): class FieldOptions(betterproto.Message): """ """ - ctype: "FieldOptionsCType" = betterproto.enum_field(1, enum_default_value=lambda: FieldOptionsCType.try_value(0)) + ctype: "FieldOptionsCType" = betterproto.enum_field( + 1, enum_default_value=lambda: FieldOptionsCType.try_value(0) + ) """ The ctype option instructs the C++ code generator to use a different representation of the field than it normally would. See the specific @@ -1504,7 +1524,9 @@ class FieldOptions(betterproto.Message): false will avoid using packed encoding. """ - jstype: "FieldOptionsJsType" = betterproto.enum_field(6, enum_default_value=lambda: FieldOptionsJsType.try_value(0)) + jstype: "FieldOptionsJsType" = betterproto.enum_field( + 6, enum_default_value=lambda: FieldOptionsJsType.try_value(0) + ) """ The jstype option determines the JavaScript type used for values of the field. The option is permitted only for 64 bit integral and fixed types @@ -1659,7 +1681,9 @@ class MethodOptions(betterproto.Message): this is a formalization for deprecating methods. """ - idempotency_level: "MethodOptionsIdempotencyLevel" = betterproto.enum_field(34, enum_default_value=lambda: MethodOptionsIdempotencyLevel.try_value(0)) + idempotency_level: "MethodOptionsIdempotencyLevel" = betterproto.enum_field( + 34, enum_default_value=lambda: MethodOptionsIdempotencyLevel.try_value(0) + ) """ """ @@ -2308,7 +2332,9 @@ class Value(betterproto.Message): The JSON representation for `Value` is JSON value. """ - null_value: "NullValue" = betterproto.enum_field(1, enum_default_value=lambda: NullValue.try_value(0), group="kind") + null_value: "NullValue" = betterproto.enum_field( + 1, enum_default_value=lambda: NullValue.try_value(0), group="kind" + ) """Represents a null value.""" number_value: float = betterproto.double_field(2, group="kind") diff --git a/src/betterproto/lib/std/google/protobuf/compiler/__init__.py b/src/betterproto/lib/std/google/protobuf/compiler/__init__.py index d2bfa6146..3eabfe712 100644 --- a/src/betterproto/lib/std/google/protobuf/compiler/__init__.py +++ b/src/betterproto/lib/std/google/protobuf/compiler/__init__.py @@ -122,7 +122,9 @@ class CodeGeneratorResponse(betterproto.Message): effect for plugins that have FEATURE_SUPPORTS_EDITIONS set. """ - file: List["CodeGeneratorResponseFile"] = betterproto.message_field(15, repeated=True) + file: List["CodeGeneratorResponseFile"] = betterproto.message_field( + 15, repeated=True + ) @dataclass(eq=False, repr=False) diff --git a/src/betterproto/plugin/main.py b/src/betterproto/plugin/main.py index 5fbeebc6d..29079204f 100755 --- a/src/betterproto/plugin/main.py +++ b/src/betterproto/plugin/main.py @@ -7,6 +7,7 @@ CodeGeneratorRequest, CodeGeneratorResponse, ) + # from betterproto.plugin.models import monkey_patch_oneof_index from betterproto.plugin.parser import generate_code diff --git a/src/betterproto/plugin/models.py b/src/betterproto/plugin/models.py index e2b9d97a4..0ac7fa1b6 100644 --- a/src/betterproto/plugin/models.py +++ b/src/betterproto/plugin/models.py @@ -305,7 +305,10 @@ def python_module_imports(self) -> Set[str]: if any(x for x in self.messages if any(x.deprecated_fields)): has_deprecated = True if any( - any(m.proto_obj.options and m.proto_obj.options.deprecated for m in s.methods) + any( + m.proto_obj.options and m.proto_obj.options.deprecated + for m in s.methods + ) for s in self.services ): has_deprecated = True @@ -413,8 +416,7 @@ def is_oneof(proto_field_obj: FieldDescriptorProto) -> bool: """ return ( - not proto_field_obj.proto3_optional - and proto_field_obj.oneof_index is not None + not proto_field_obj.proto3_optional and proto_field_obj.oneof_index is not None ) @@ -454,7 +456,8 @@ def betterproto_field_args(self) -> List[str]: if self.repeated: args.append("repeated=True") if self.field_type == "enum": - args.append(f"enum_default_value=lambda: {self.py_type.strip('"')}.try_value(0)") + t = self.py_type.strip('"') + args.append(f"enum_default_value=lambda: {t}.try_value(0)") return args @property diff --git a/tests/test_features.py b/tests/test_features.py index dac2fd5cd..95b182d69 100644 --- a/tests/test_features.py +++ b/tests/test_features.py @@ -48,7 +48,9 @@ class TestEnum(betterproto.Enum): @dataclass class Foo(betterproto.Message): - bar: TestEnum = betterproto.enum_field(1, enum_default_value=lambda: TestEnum.try_value(0)) + bar: TestEnum = betterproto.enum_field( + 1, enum_default_value=lambda: TestEnum.try_value(0) + ) # JSON strings are supported, but ints should still be supported too. foo = Foo().from_dict({"bar": 1}) diff --git a/tests/test_inputs.py b/tests/test_inputs.py index 180b13bb2..136427981 100644 --- a/tests/test_inputs.py +++ b/tests/test_inputs.py @@ -187,7 +187,6 @@ def test_message_json(repeat, test_data: TestData) -> None: message.from_json(sample.json) message_json = message.to_json(indent=0) - print(message) print(message_json) print(message.to_dict()) diff --git a/tests/test_oneof_pattern_matching.py b/tests/test_oneof_pattern_matching.py index 2bd07ab50..58e48fb0b 100644 --- a/tests/test_oneof_pattern_matching.py +++ b/tests/test_oneof_pattern_matching.py @@ -1,8 +1,8 @@ +import sys from dataclasses import dataclass +from typing import Optional import pytest -import sys -from typing import Optional import betterproto From 749d10659cd14068c238a490a708fbacf76c42cf Mon Sep 17 00:00:00 2001 From: Adrien Vannson Date: Tue, 12 Nov 2024 18:31:29 +0100 Subject: [PATCH 34/37] Move match test to other file --- tests/oneof_pattern_matching.py | 47 ++++++++++++++++++++++++++++ tests/test_oneof_pattern_matching.py | 43 ++----------------------- 2 files changed, 49 insertions(+), 41 deletions(-) create mode 100644 tests/oneof_pattern_matching.py diff --git a/tests/oneof_pattern_matching.py b/tests/oneof_pattern_matching.py new file mode 100644 index 000000000..4eab565a7 --- /dev/null +++ b/tests/oneof_pattern_matching.py @@ -0,0 +1,47 @@ +from dataclasses import dataclass +from typing import Optional + +import pytest + +import betterproto + + +def test_oneof_pattern_matching(): + @dataclass + class Sub(betterproto.Message): + val: int = betterproto.int32_field(1) + + @dataclass + class Foo(betterproto.Message): + bar: Optional[int] = betterproto.int32_field(1, group="group1") + baz: Optional[str] = betterproto.string_field(2, group="group1") + sub: Optional[Sub] = betterproto.message_field(3, group="group2") + abc: Optional[str] = betterproto.string_field(4, group="group2") + + foo = Foo(baz="test1", abc="test2") + + match foo: + case Foo(bar=int(_)): + pytest.fail("Matched 'bar' instead of 'baz'") + case Foo(baz=v): + assert v == "test1" + case _: + pytest.fail("Matched neither 'bar' nor 'baz'") + + match foo: + case Foo(sub=Sub(_)): + pytest.fail("Matched 'sub' instead of 'abc'") + case Foo(abc=v): + assert v == "test2" + case _: + pytest.fail("Matched neither 'sub' nor 'abc'") + + foo.sub = Sub(val=1) + + match foo: + case Foo(sub=Sub(val=v)): + assert v == 1 + case Foo(abc=str(v)): + pytest.fail("Matched 'abc' instead of 'sub'") + case _: + pytest.fail("Matched neither 'sub' nor 'abc'") diff --git a/tests/test_oneof_pattern_matching.py b/tests/test_oneof_pattern_matching.py index 58e48fb0b..186cfa3d9 100644 --- a/tests/test_oneof_pattern_matching.py +++ b/tests/test_oneof_pattern_matching.py @@ -1,52 +1,13 @@ import sys -from dataclasses import dataclass -from typing import Optional import pytest -import betterproto - @pytest.mark.skipif( sys.version_info < (3, 10), reason="pattern matching is only supported in python3.10+", ) def test_oneof_pattern_matching(): - @dataclass - class Sub(betterproto.Message): - val: int = betterproto.int32_field(1) - - @dataclass - class Foo(betterproto.Message): - bar: Optional[int] = betterproto.int32_field(1, group="group1") - baz: Optional[str] = betterproto.string_field(2, group="group1") - sub: Optional[Sub] = betterproto.message_field(3, group="group2") - abc: Optional[str] = betterproto.string_field(4, group="group2") - - foo = Foo(baz="test1", abc="test2") - - match foo: - case Foo(bar=int(_)): - pytest.fail("Matched 'bar' instead of 'baz'") - case Foo(baz=v): - assert v == "test1" - case _: - pytest.fail("Matched neither 'bar' nor 'baz'") - - match foo: - case Foo(sub=Sub(_)): - pytest.fail("Matched 'sub' instead of 'abc'") - case Foo(abc=v): - assert v == "test2" - case _: - pytest.fail("Matched neither 'sub' nor 'abc'") - - foo.sub = Sub(val=1) + from tests.oneof_pattern_matching import test_oneof_pattern_matching - match foo: - case Foo(sub=Sub(val=v)): - assert v == 1 - case Foo(abc=str(v)): - pytest.fail("Matched 'abc' instead of 'sub'") - case _: - pytest.fail("Matched neither 'sub' nor 'abc'") + test_oneof_pattern_matching() From f56f63d7a595f3b7da44d531884bf03a745a603f Mon Sep 17 00:00:00 2001 From: Adrien Vannson Date: Wed, 13 Nov 2024 11:02:15 +0100 Subject: [PATCH 35/37] Remoev useless prints --- tests/test_inputs.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/tests/test_inputs.py b/tests/test_inputs.py index 136427981..4257a2f21 100644 --- a/tests/test_inputs.py +++ b/tests/test_inputs.py @@ -187,10 +187,6 @@ def test_message_json(repeat, test_data: TestData) -> None: message.from_json(sample.json) message_json = message.to_json(indent=0) - print(message) - print(message_json) - print(message.to_dict()) - assert dict_replace_nans(json.loads(message_json)) == dict_replace_nans( json.loads(sample.json) ) From 64e6dc139b4a12f4468815436a41d73d105c6b83 Mon Sep 17 00:00:00 2001 From: Adrien Vannson Date: Wed, 13 Nov 2024 17:58:46 +0100 Subject: [PATCH 36/37] Remove serialized_on_wire from documentation --- README.md | 14 -------------- docs/migrating.rst | 24 ------------------------ 2 files changed, 38 deletions(-) diff --git a/README.md b/README.md index d0232f869..324264374 100644 --- a/README.md +++ b/README.md @@ -248,20 +248,6 @@ For compatibility the default is to convert field names to `camelCase`. You can MyMessage().to_dict(casing=betterproto.Casing.SNAKE) ``` -### Determining if a message was sent - -Sometimes it is useful to be able to determine whether a message has been sent on the wire. This is how the Google wrapper types work to let you know whether a value is unset, set as the default (zero value), or set as something else, for example. - -Use `betterproto.serialized_on_wire(message)` to determine if it was sent. This is a little bit different from the official Google generated Python code, and it lives outside the generated `Message` class to prevent name clashes. Note that it **only** supports Proto 3 and thus can **only** be used to check if `Message` fields are set. You cannot check if a scalar was sent on the wire. - -```py -# Old way (official Google Protobuf package) ->>> mymessage.HasField('myfield') - -# New way (this project) ->>> betterproto.serialized_on_wire(mymessage.myfield) -``` - ### One-of Support Protobuf supports grouping fields in a `oneof` clause. Only one of the fields in the group may be set at a given time. For example, given the proto: diff --git a/docs/migrating.rst b/docs/migrating.rst index 3d02650db..e455618e3 100644 --- a/docs/migrating.rst +++ b/docs/migrating.rst @@ -19,30 +19,6 @@ regenerating your protobufs of course) although there are some minor differences :meth:`betterproto.Message.__bytes__` respectively. -Determining if a message was sent -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Sometimes it is useful to be able to determine whether a message has been sent on -the wire. This is how the Google wrapper types work to let you know whether a value is -unset (set as the default/zero value), or set as something else, for example. - -Use ``betterproto.serialized_on_wire(message)`` to determine if it was sent. This is -a little bit different from the official Google generated Python code, and it lives -outside the generated ``Message`` class to prevent name clashes. Note that it only -supports Proto 3 and thus can only be used to check if ``Message`` fields are set. -You cannot check if a scalar was sent on the wire. - -.. code-block:: python - - # Old way (official Google Protobuf package) - >>> mymessage.HasField('myfield') - True - - # New way (this project) - >>> betterproto.serialized_on_wire(mymessage.myfield) - True - - One-of Support ~~~~~~~~~~~~~~ From df21b09418f0c99f91da651a723833b8c28aa133 Mon Sep 17 00:00:00 2001 From: Adrien Vannson Date: Fri, 15 Nov 2024 13:36:58 +0100 Subject: [PATCH 37/37] Simplify lambda functions --- src/betterproto/__init__.py | 50 ++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 29 deletions(-) diff --git a/src/betterproto/__init__.py b/src/betterproto/__init__.py index 6bd06d4b6..d146d60e0 100644 --- a/src/betterproto/__init__.py +++ b/src/betterproto/__init__.py @@ -205,14 +205,10 @@ def dataclass_field( ) -> dataclasses.Field: """Creates a dataclass field with attached protobuf metadata.""" if repeated: - - def default_factory(): - return [] + default_factory = list elif optional or group: - - def default_factory(): - return None + default_factory = type(None) return dataclasses.field( default_factory=default_factory, @@ -255,7 +251,7 @@ def bool_field( return dataclass_field( number, TYPE_BOOL, - lambda: False, + bool, group=group, optional=optional, repeated=repeated, @@ -269,7 +265,7 @@ def int32_field( repeated: bool = False, ) -> Any: return dataclass_field( - number, TYPE_INT32, lambda: 0, group=group, optional=optional, repeated=repeated + number, TYPE_INT32, int, group=group, optional=optional, repeated=repeated ) @@ -280,7 +276,7 @@ def int64_field( repeated: bool = False, ) -> Any: return dataclass_field( - number, TYPE_INT64, lambda: 0, group=group, optional=optional, repeated=repeated + number, TYPE_INT64, int, group=group, optional=optional, repeated=repeated ) @@ -293,7 +289,7 @@ def uint32_field( return dataclass_field( number, TYPE_UINT32, - lambda: 0, + int, group=group, optional=optional, repeated=repeated, @@ -309,7 +305,7 @@ def uint64_field( return dataclass_field( number, TYPE_UINT64, - lambda: 0, + int, group=group, optional=optional, repeated=repeated, @@ -325,7 +321,7 @@ def sint32_field( return dataclass_field( number, TYPE_SINT32, - lambda: 0, + int, group=group, optional=optional, repeated=repeated, @@ -341,7 +337,7 @@ def sint64_field( return dataclass_field( number, TYPE_SINT64, - lambda: 0, + int, group=group, optional=optional, repeated=repeated, @@ -357,7 +353,7 @@ def float_field( return dataclass_field( number, TYPE_FLOAT, - lambda: 0.0, + float, group=group, optional=optional, repeated=repeated, @@ -373,7 +369,7 @@ def double_field( return dataclass_field( number, TYPE_DOUBLE, - lambda: 0.0, + float, group=group, optional=optional, repeated=repeated, @@ -389,7 +385,7 @@ def fixed32_field( return dataclass_field( number, TYPE_FIXED32, - lambda: 0.0, + float, group=group, optional=optional, repeated=repeated, @@ -405,7 +401,7 @@ def fixed64_field( return dataclass_field( number, TYPE_FIXED64, - lambda: 0.0, + float, group=group, optional=optional, repeated=repeated, @@ -421,7 +417,7 @@ def sfixed32_field( return dataclass_field( number, TYPE_SFIXED32, - lambda: 0.0, + float, group=group, optional=optional, repeated=repeated, @@ -437,7 +433,7 @@ def sfixed64_field( return dataclass_field( number, TYPE_SFIXED64, - lambda: 0.0, + float, group=group, optional=optional, repeated=repeated, @@ -453,7 +449,7 @@ def string_field( return dataclass_field( number, TYPE_STRING, - lambda: "", + str, group=group, optional=optional, repeated=repeated, @@ -469,7 +465,7 @@ def bytes_field( return dataclass_field( number, TYPE_BYTES, - lambda: b"", + bytes, group=group, optional=optional, repeated=repeated, @@ -486,7 +482,7 @@ def message_field( return dataclass_field( number, TYPE_MESSAGE, - lambda: None, + type(None), group=group, wraps=wraps, optional=optional, @@ -498,7 +494,7 @@ def map_field( number: int, key_type: str, value_type: str, group: Optional[str] = None ) -> Any: return dataclass_field( - number, TYPE_MAP, lambda: dict(), map_types=(key_type, value_type), group=group + number, TYPE_MAP, dict, map_types=(key_type, value_type), group=group ) @@ -886,16 +882,12 @@ def _get_cls_by_field( ( "key", kt, - dataclass_field( - 1, meta.map_types[0], default_factory=lambda: kt() - ), + dataclass_field(1, meta.map_types[0], default_factory=kt), ), ( "value", vt, - dataclass_field( - 2, meta.map_types[1], default_factory=lambda: vt() - ), + dataclass_field(2, meta.map_types[1], default_factory=vt), ), ], bases=(Message,),