Merge branch 'refs/heads/master_gh'
# Conflicts: # pyproject.toml
This commit is contained in:
commit
85d2990ca1
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
@ -28,7 +28,7 @@ jobs:
|
||||
- name: Get full Python version
|
||||
id: full-python-version
|
||||
shell: bash
|
||||
run: echo ::set-output name=version::$(python -c "import sys; print('-'.join(str(v) for v in sys.version_info))")
|
||||
run: echo "version=$(python -c "import sys; print('-'.join(str(v) for v in sys.version_info))")" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Install poetry
|
||||
shell: bash
|
||||
|
23
README.md
23
README.md
@ -277,7 +277,22 @@ message Test {
|
||||
}
|
||||
```
|
||||
|
||||
You can use `betterproto.which_one_of(message, group_name)` to determine which of the fields was set. It returns a tuple of the field name and value, or a blank string and `None` if unset.
|
||||
On Python 3.10 and later, you can use a `match` statement to access the provided one-of field, which supports type-checking:
|
||||
|
||||
```py
|
||||
test = Test()
|
||||
match test:
|
||||
case Test(on=value):
|
||||
print(value) # value: bool
|
||||
case Test(count=value):
|
||||
print(value) # value: int
|
||||
case Test(name=value):
|
||||
print(value) # value: str
|
||||
case _:
|
||||
print("No value provided")
|
||||
```
|
||||
|
||||
You can also use `betterproto.which_one_of(message, group_name)` to determine which of the fields was set. It returns a tuple of the field name and value, or a blank string and `None` if unset.
|
||||
|
||||
```py
|
||||
>>> test = Test()
|
||||
@ -292,17 +307,11 @@ You can use `betterproto.which_one_of(message, group_name)` to determine which o
|
||||
>>> test.count = 57
|
||||
>>> betterproto.which_one_of(test, "foo")
|
||||
["count", 57]
|
||||
>>> test.on
|
||||
False
|
||||
|
||||
# Default (zero) values also work.
|
||||
>>> test.name = ""
|
||||
>>> betterproto.which_one_of(test, "foo")
|
||||
["name", ""]
|
||||
>>> test.count
|
||||
0
|
||||
>>> test.on
|
||||
False
|
||||
```
|
||||
|
||||
Again this is a little different than the official Google code generator:
|
||||
|
@ -85,17 +85,19 @@ wrappers used to provide optional zero value support. Each of these has a specia
|
||||
representation and is handled a little differently from normal messages. The Python
|
||||
mapping for these is as follows:
|
||||
|
||||
+-------------------------------+-----------------------------------------------+--------------------------+
|
||||
| ``Google Message`` | ``Python Type`` | ``Default`` |
|
||||
+===============================+===============================================+==========================+
|
||||
| ``google.protobuf.duration`` | :class:`datetime.timedelta` | ``0`` |
|
||||
+-------------------------------+-----------------------------------------------+--------------------------+
|
||||
| ``google.protobuf.timestamp`` | ``Timezone-aware`` :class:`datetime.datetime` | ``1970-01-01T00:00:00Z`` |
|
||||
+-------------------------------+-----------------------------------------------+--------------------------+
|
||||
| ``google.protobuf.*Value`` | ``Optional[...]``/``None`` | ``None`` |
|
||||
+-------------------------------+-----------------------------------------------+--------------------------+
|
||||
| ``google.protobuf.*`` | ``betterproto.lib.google.protobuf.*`` | ``None`` |
|
||||
+-------------------------------+-----------------------------------------------+--------------------------+
|
||||
+-------------------------------+-------------------------------------------------+--------------------------+
|
||||
| ``Google Message`` | ``Python Type`` | ``Default`` |
|
||||
+===============================+=================================================+==========================+
|
||||
| ``google.protobuf.duration`` | :class:`datetime.timedelta` | ``0`` |
|
||||
+-------------------------------+-------------------------------------------------+--------------------------+
|
||||
| ``google.protobuf.timestamp`` | ``Timezone-aware`` :class:`datetime.datetime` | ``1970-01-01T00:00:00Z`` |
|
||||
+-------------------------------+-------------------------------------------------+--------------------------+
|
||||
| ``google.protobuf.*Value`` | ``Optional[...]``/``None`` | ``None`` |
|
||||
+-------------------------------+-------------------------------------------------+--------------------------+
|
||||
| ``google.protobuf.*`` | ``betterproto.lib.std.google.protobuf.*`` | ``None`` |
|
||||
+-------------------------------+-------------------------------------------------+--------------------------+
|
||||
| ``google.protobuf.*`` | ``betterproto.lib.pydantic.google.protobuf.*`` | ``None`` |
|
||||
+-------------------------------+-------------------------------------------------+--------------------------+
|
||||
|
||||
|
||||
For the wrapper types, the Python type corresponds to the wrapped type, e.g.
|
||||
|
@ -95,11 +95,11 @@ cmd = """
|
||||
protoc
|
||||
--plugin=protoc-gen-custom=src/betterproto/plugin/main.py
|
||||
--custom_opt=INCLUDE_GOOGLE
|
||||
--custom_out=src/betterproto/lib
|
||||
--custom_out=src/betterproto/lib/std
|
||||
-I C:\\work\\include
|
||||
C:\\work\\include\\google\\protobuf\\**\\*.proto
|
||||
"""
|
||||
help = "Regenerate the types in betterproto.lib.google"
|
||||
help = "Regenerate the types in betterproto.lib.std.google"
|
||||
|
||||
# CI tasks
|
||||
|
||||
|
@ -749,7 +749,7 @@ class Message(ABC):
|
||||
group_current.setdefault(meta.group)
|
||||
|
||||
value = self.__raw_get(field_name)
|
||||
if value != PLACEHOLDER and not (meta.optional and value is None):
|
||||
if value is not PLACEHOLDER and not (meta.optional and value is None):
|
||||
# Found a non-sentinel value
|
||||
all_sentinel = False
|
||||
|
||||
|
@ -43,7 +43,12 @@ def parse_source_type_name(field_type_name: str) -> Tuple[str, str]:
|
||||
|
||||
|
||||
def get_type_reference(
|
||||
*, package: str, imports: set, source_type: str, unwrap: bool = True
|
||||
*,
|
||||
package: str,
|
||||
imports: set,
|
||||
source_type: str,
|
||||
unwrap: bool = True,
|
||||
pydantic: bool = False,
|
||||
) -> str:
|
||||
"""
|
||||
Return a Python type name for a proto type reference. Adds the import if
|
||||
@ -69,7 +74,9 @@ def get_type_reference(
|
||||
compiling_google_protobuf = current_package == ["google", "protobuf"]
|
||||
importing_google_protobuf = py_package == ["google", "protobuf"]
|
||||
if importing_google_protobuf and not compiling_google_protobuf:
|
||||
py_package = ["betterproto", "lib"] + py_package
|
||||
py_package = (
|
||||
["betterproto", "lib"] + (["pydantic"] if pydantic else []) + py_package
|
||||
)
|
||||
|
||||
if py_package[:1] == ["betterproto"]:
|
||||
return reference_absolute(imports, py_package, py_type)
|
||||
|
@ -156,6 +156,12 @@ class Enum(IntEnum if TYPE_CHECKING else int, metaclass=EnumType):
|
||||
f"{self.__class__.__name__} Cannot delete a member's attributes."
|
||||
)
|
||||
|
||||
def __copy__(self) -> Self:
|
||||
return self
|
||||
|
||||
def __deepcopy__(self, memo: Any) -> Self:
|
||||
return self
|
||||
|
||||
@classmethod
|
||||
def try_value(cls, value: int = 0) -> Self:
|
||||
"""Return the value which corresponds to the value.
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,152 +1 @@
|
||||
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
# sources: google/protobuf/compiler/plugin.proto
|
||||
# plugin: python-betterproto
|
||||
# This file has been @generated
|
||||
from dataclasses import dataclass
|
||||
from typing import List
|
||||
|
||||
import betterproto
|
||||
import betterproto.lib.google.protobuf as betterproto_lib_google_protobuf
|
||||
|
||||
|
||||
class CodeGeneratorResponseFeature(betterproto.Enum):
|
||||
"""Sync with code_generator.h."""
|
||||
|
||||
FEATURE_NONE = 0
|
||||
FEATURE_PROTO3_OPTIONAL = 1
|
||||
|
||||
|
||||
@dataclass(eq=False, repr=False)
|
||||
class Version(betterproto.Message):
|
||||
"""The version number of protocol compiler."""
|
||||
|
||||
major: int = betterproto.int32_field(1)
|
||||
minor: int = betterproto.int32_field(2)
|
||||
patch: int = betterproto.int32_field(3)
|
||||
suffix: str = betterproto.string_field(4)
|
||||
"""
|
||||
A suffix for alpha, beta or rc release, e.g., "alpha-1", "rc2". It should
|
||||
be empty for mainline stable releases.
|
||||
"""
|
||||
|
||||
|
||||
@dataclass(eq=False, repr=False)
|
||||
class CodeGeneratorRequest(betterproto.Message):
|
||||
"""An encoded CodeGeneratorRequest is written to the plugin's stdin."""
|
||||
|
||||
file_to_generate: List[str] = betterproto.string_field(1)
|
||||
"""
|
||||
The .proto files that were explicitly listed on the command-line. The code
|
||||
generator should generate code only for these files. Each file's
|
||||
descriptor will be included in proto_file, below.
|
||||
"""
|
||||
|
||||
parameter: str = betterproto.string_field(2)
|
||||
"""The generator parameter passed on the command-line."""
|
||||
|
||||
proto_file: List[
|
||||
"betterproto_lib_google_protobuf.FileDescriptorProto"
|
||||
] = betterproto.message_field(15)
|
||||
"""
|
||||
FileDescriptorProtos for all files in files_to_generate and everything they
|
||||
import. The files will appear in topological order, so each file appears
|
||||
before any file that imports it. protoc guarantees that all proto_files
|
||||
will be written after the fields above, even though this is not technically
|
||||
guaranteed by the protobuf wire format. This theoretically could allow a
|
||||
plugin to stream in the FileDescriptorProtos and handle them one by one
|
||||
rather than read the entire set into memory at once. However, as of this
|
||||
writing, this is not similarly optimized on protoc's end -- it will store
|
||||
all fields in memory at once before sending them to the plugin. Type names
|
||||
of fields and extensions in the FileDescriptorProto are always fully
|
||||
qualified.
|
||||
"""
|
||||
|
||||
compiler_version: "Version" = betterproto.message_field(3)
|
||||
"""The version number of protocol compiler."""
|
||||
|
||||
|
||||
@dataclass(eq=False, repr=False)
|
||||
class CodeGeneratorResponse(betterproto.Message):
|
||||
"""The plugin writes an encoded CodeGeneratorResponse to stdout."""
|
||||
|
||||
error: str = betterproto.string_field(1)
|
||||
"""
|
||||
Error message. If non-empty, code generation failed. The plugin process
|
||||
should exit with status code zero even if it reports an error in this way.
|
||||
This should be used to indicate errors in .proto files which prevent the
|
||||
code generator from generating correct code. Errors which indicate a
|
||||
problem in protoc itself -- such as the input CodeGeneratorRequest being
|
||||
unparseable -- should be reported by writing a message to stderr and
|
||||
exiting with a non-zero status code.
|
||||
"""
|
||||
|
||||
supported_features: int = betterproto.uint64_field(2)
|
||||
"""
|
||||
A bitmask of supported features that the code generator supports. This is a
|
||||
bitwise "or" of values from the Feature enum.
|
||||
"""
|
||||
|
||||
file: List["CodeGeneratorResponseFile"] = betterproto.message_field(15)
|
||||
|
||||
|
||||
@dataclass(eq=False, repr=False)
|
||||
class CodeGeneratorResponseFile(betterproto.Message):
|
||||
"""Represents a single generated file."""
|
||||
|
||||
name: str = betterproto.string_field(1)
|
||||
"""
|
||||
The file name, relative to the output directory. The name must not contain
|
||||
"." or ".." components and must be relative, not be absolute (so, the file
|
||||
cannot lie outside the output directory). "/" must be used as the path
|
||||
separator, not "\". If the name is omitted, the content will be appended to
|
||||
the previous file. This allows the generator to break large files into
|
||||
small chunks, and allows the generated text to be streamed back to protoc
|
||||
so that large files need not reside completely in memory at one time. Note
|
||||
that as of this writing protoc does not optimize for this -- it will read
|
||||
the entire CodeGeneratorResponse before writing files to disk.
|
||||
"""
|
||||
|
||||
insertion_point: str = betterproto.string_field(2)
|
||||
"""
|
||||
If non-empty, indicates that the named file should already exist, and the
|
||||
content here is to be inserted into that file at a defined insertion point.
|
||||
This feature allows a code generator to extend the output produced by
|
||||
another code generator. The original generator may provide insertion
|
||||
points by placing special annotations in the file that look like:
|
||||
@@protoc_insertion_point(NAME) The annotation can have arbitrary text
|
||||
before and after it on the line, which allows it to be placed in a comment.
|
||||
NAME should be replaced with an identifier naming the point -- this is what
|
||||
other generators will use as the insertion_point. Code inserted at this
|
||||
point will be placed immediately above the line containing the insertion
|
||||
point (thus multiple insertions to the same point will come out in the
|
||||
order they were added). The double-@ is intended to make it unlikely that
|
||||
the generated code could contain things that look like insertion points by
|
||||
accident. For example, the C++ code generator places the following line in
|
||||
the .pb.h files that it generates: //
|
||||
@@protoc_insertion_point(namespace_scope) This line appears within the
|
||||
scope of the file's package namespace, but outside of any particular class.
|
||||
Another plugin can then specify the insertion_point "namespace_scope" to
|
||||
generate additional classes or other declarations that should be placed in
|
||||
this scope. Note that if the line containing the insertion point begins
|
||||
with whitespace, the same whitespace will be added to every line of the
|
||||
inserted text. This is useful for languages like Python, where indentation
|
||||
matters. In these languages, the insertion point comment should be
|
||||
indented the same amount as any inserted code will need to be in order to
|
||||
work correctly in that context. The code generator that generates the
|
||||
initial file and the one which inserts into it must both run as part of a
|
||||
single invocation of protoc. Code generators are executed in the order in
|
||||
which they appear on the command line. If |insertion_point| is present,
|
||||
|name| must also be present.
|
||||
"""
|
||||
|
||||
content: str = betterproto.string_field(15)
|
||||
"""The file contents."""
|
||||
|
||||
generated_code_info: "betterproto_lib_google_protobuf.GeneratedCodeInfo" = (
|
||||
betterproto.message_field(16)
|
||||
)
|
||||
"""
|
||||
Information describing the file content being inserted. If an insertion
|
||||
point is used, this information will be appropriately offset and inserted
|
||||
into the code generation metadata for the generated files.
|
||||
"""
|
||||
from betterproto.lib.std.google.protobuf.compiler import *
|
||||
|
0
src/betterproto/lib/pydantic/__init__.py
Normal file
0
src/betterproto/lib/pydantic/__init__.py
Normal file
0
src/betterproto/lib/pydantic/google/__init__.py
Normal file
0
src/betterproto/lib/pydantic/google/__init__.py
Normal file
2589
src/betterproto/lib/pydantic/google/protobuf/__init__.py
Normal file
2589
src/betterproto/lib/pydantic/google/protobuf/__init__.py
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,210 @@
|
||||
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
# sources: google/protobuf/compiler/plugin.proto
|
||||
# plugin: python-betterproto
|
||||
# This file has been @generated
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from dataclasses import dataclass
|
||||
else:
|
||||
from pydantic.dataclasses import dataclass
|
||||
|
||||
from typing import List
|
||||
|
||||
import betterproto
|
||||
import betterproto.lib.pydantic.google.protobuf as betterproto_lib_pydantic_google_protobuf
|
||||
|
||||
|
||||
class CodeGeneratorResponseFeature(betterproto.Enum):
|
||||
"""Sync with code_generator.h."""
|
||||
|
||||
FEATURE_NONE = 0
|
||||
FEATURE_PROTO3_OPTIONAL = 1
|
||||
FEATURE_SUPPORTS_EDITIONS = 2
|
||||
|
||||
|
||||
@dataclass(eq=False, repr=False)
|
||||
class Version(betterproto.Message):
|
||||
"""The version number of protocol compiler."""
|
||||
|
||||
major: int = betterproto.int32_field(1)
|
||||
minor: int = betterproto.int32_field(2)
|
||||
patch: int = betterproto.int32_field(3)
|
||||
suffix: str = betterproto.string_field(4)
|
||||
"""
|
||||
A suffix for alpha, beta or rc release, e.g., "alpha-1", "rc2". It should
|
||||
be empty for mainline stable releases.
|
||||
"""
|
||||
|
||||
|
||||
@dataclass(eq=False, repr=False)
|
||||
class CodeGeneratorRequest(betterproto.Message):
|
||||
"""An encoded CodeGeneratorRequest is written to the plugin's stdin."""
|
||||
|
||||
file_to_generate: List[str] = betterproto.string_field(1)
|
||||
"""
|
||||
The .proto files that were explicitly listed on the command-line. The
|
||||
code generator should generate code only for these files. Each file's
|
||||
descriptor will be included in proto_file, below.
|
||||
"""
|
||||
|
||||
parameter: str = betterproto.string_field(2)
|
||||
"""The generator parameter passed on the command-line."""
|
||||
|
||||
proto_file: List[
|
||||
"betterproto_lib_pydantic_google_protobuf.FileDescriptorProto"
|
||||
] = betterproto.message_field(15)
|
||||
"""
|
||||
FileDescriptorProtos for all files in files_to_generate and everything
|
||||
they import. The files will appear in topological order, so each file
|
||||
appears before any file that imports it.
|
||||
|
||||
Note: the files listed in files_to_generate will include runtime-retention
|
||||
options only, but all other files will include source-retention options.
|
||||
The source_file_descriptors field below is available in case you need
|
||||
source-retention options for files_to_generate.
|
||||
|
||||
protoc guarantees that all proto_files will be written after
|
||||
the fields above, even though this is not technically guaranteed by the
|
||||
protobuf wire format. This theoretically could allow a plugin to stream
|
||||
in the FileDescriptorProtos and handle them one by one rather than read
|
||||
the entire set into memory at once. However, as of this writing, this
|
||||
is not similarly optimized on protoc's end -- it will store all fields in
|
||||
memory at once before sending them to the plugin.
|
||||
|
||||
Type names of fields and extensions in the FileDescriptorProto are always
|
||||
fully qualified.
|
||||
"""
|
||||
|
||||
source_file_descriptors: List[
|
||||
"betterproto_lib_pydantic_google_protobuf.FileDescriptorProto"
|
||||
] = betterproto.message_field(17)
|
||||
"""
|
||||
File descriptors with all options, including source-retention options.
|
||||
These descriptors are only provided for the files listed in
|
||||
files_to_generate.
|
||||
"""
|
||||
|
||||
compiler_version: "Version" = betterproto.message_field(3)
|
||||
"""The version number of protocol compiler."""
|
||||
|
||||
|
||||
@dataclass(eq=False, repr=False)
|
||||
class CodeGeneratorResponse(betterproto.Message):
|
||||
"""The plugin writes an encoded CodeGeneratorResponse to stdout."""
|
||||
|
||||
error: str = betterproto.string_field(1)
|
||||
"""
|
||||
Error message. If non-empty, code generation failed. The plugin process
|
||||
should exit with status code zero even if it reports an error in this way.
|
||||
|
||||
This should be used to indicate errors in .proto files which prevent the
|
||||
code generator from generating correct code. Errors which indicate a
|
||||
problem in protoc itself -- such as the input CodeGeneratorRequest being
|
||||
unparseable -- should be reported by writing a message to stderr and
|
||||
exiting with a non-zero status code.
|
||||
"""
|
||||
|
||||
supported_features: int = betterproto.uint64_field(2)
|
||||
"""
|
||||
A bitmask of supported features that the code generator supports.
|
||||
This is a bitwise "or" of values from the Feature enum.
|
||||
"""
|
||||
|
||||
minimum_edition: int = betterproto.int32_field(3)
|
||||
"""
|
||||
The minimum edition this plugin supports. This will be treated as an
|
||||
Edition enum, but we want to allow unknown values. It should be specified
|
||||
according the edition enum value, *not* the edition number. Only takes
|
||||
effect for plugins that have FEATURE_SUPPORTS_EDITIONS set.
|
||||
"""
|
||||
|
||||
maximum_edition: int = betterproto.int32_field(4)
|
||||
"""
|
||||
The maximum edition this plugin supports. This will be treated as an
|
||||
Edition enum, but we want to allow unknown values. It should be specified
|
||||
according the edition enum value, *not* the edition number. Only takes
|
||||
effect for plugins that have FEATURE_SUPPORTS_EDITIONS set.
|
||||
"""
|
||||
|
||||
file: List["CodeGeneratorResponseFile"] = betterproto.message_field(15)
|
||||
|
||||
|
||||
@dataclass(eq=False, repr=False)
|
||||
class CodeGeneratorResponseFile(betterproto.Message):
|
||||
"""Represents a single generated file."""
|
||||
|
||||
name: str = betterproto.string_field(1)
|
||||
"""
|
||||
The file name, relative to the output directory. The name must not
|
||||
contain "." or ".." components and must be relative, not be absolute (so,
|
||||
the file cannot lie outside the output directory). "/" must be used as
|
||||
the path separator, not "\".
|
||||
|
||||
If the name is omitted, the content will be appended to the previous
|
||||
file. This allows the generator to break large files into small chunks,
|
||||
and allows the generated text to be streamed back to protoc so that large
|
||||
files need not reside completely in memory at one time. Note that as of
|
||||
this writing protoc does not optimize for this -- it will read the entire
|
||||
CodeGeneratorResponse before writing files to disk.
|
||||
"""
|
||||
|
||||
insertion_point: str = betterproto.string_field(2)
|
||||
"""
|
||||
If non-empty, indicates that the named file should already exist, and the
|
||||
content here is to be inserted into that file at a defined insertion
|
||||
point. This feature allows a code generator to extend the output
|
||||
produced by another code generator. The original generator may provide
|
||||
insertion points by placing special annotations in the file that look
|
||||
like:
|
||||
@@protoc_insertion_point(NAME)
|
||||
The annotation can have arbitrary text before and after it on the line,
|
||||
which allows it to be placed in a comment. NAME should be replaced with
|
||||
an identifier naming the point -- this is what other generators will use
|
||||
as the insertion_point. Code inserted at this point will be placed
|
||||
immediately above the line containing the insertion point (thus multiple
|
||||
insertions to the same point will come out in the order they were added).
|
||||
The double-@ is intended to make it unlikely that the generated code
|
||||
could contain things that look like insertion points by accident.
|
||||
|
||||
For example, the C++ code generator places the following line in the
|
||||
.pb.h files that it generates:
|
||||
// @@protoc_insertion_point(namespace_scope)
|
||||
This line appears within the scope of the file's package namespace, but
|
||||
outside of any particular class. Another plugin can then specify the
|
||||
insertion_point "namespace_scope" to generate additional classes or
|
||||
other declarations that should be placed in this scope.
|
||||
|
||||
Note that if the line containing the insertion point begins with
|
||||
whitespace, the same whitespace will be added to every line of the
|
||||
inserted text. This is useful for languages like Python, where
|
||||
indentation matters. In these languages, the insertion point comment
|
||||
should be indented the same amount as any inserted code will need to be
|
||||
in order to work correctly in that context.
|
||||
|
||||
The code generator that generates the initial file and the one which
|
||||
inserts into it must both run as part of a single invocation of protoc.
|
||||
Code generators are executed in the order in which they appear on the
|
||||
command line.
|
||||
|
||||
If |insertion_point| is present, |name| must also be present.
|
||||
"""
|
||||
|
||||
content: str = betterproto.string_field(15)
|
||||
"""The file contents."""
|
||||
|
||||
generated_code_info: (
|
||||
"betterproto_lib_pydantic_google_protobuf.GeneratedCodeInfo"
|
||||
) = betterproto.message_field(16)
|
||||
"""
|
||||
Information describing the file content being inserted. If an insertion
|
||||
point is used, this information will be appropriately offset and inserted
|
||||
into the code generation metadata for the generated files.
|
||||
"""
|
||||
|
||||
|
||||
CodeGeneratorRequest.__pydantic_model__.update_forward_refs() # type: ignore
|
||||
CodeGeneratorResponse.__pydantic_model__.update_forward_refs() # type: ignore
|
||||
CodeGeneratorResponseFile.__pydantic_model__.update_forward_refs() # type: ignore
|
0
src/betterproto/lib/std/__init__.py
Normal file
0
src/betterproto/lib/std/__init__.py
Normal file
0
src/betterproto/lib/std/google/__init__.py
Normal file
0
src/betterproto/lib/std/google/__init__.py
Normal file
2526
src/betterproto/lib/std/google/protobuf/__init__.py
Normal file
2526
src/betterproto/lib/std/google/protobuf/__init__.py
Normal file
File diff suppressed because it is too large
Load Diff
198
src/betterproto/lib/std/google/protobuf/compiler/__init__.py
Normal file
198
src/betterproto/lib/std/google/protobuf/compiler/__init__.py
Normal file
@ -0,0 +1,198 @@
|
||||
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
# sources: google/protobuf/compiler/plugin.proto
|
||||
# plugin: python-betterproto
|
||||
# This file has been @generated
|
||||
|
||||
from dataclasses import dataclass
|
||||
from typing import List
|
||||
|
||||
import betterproto
|
||||
import betterproto.lib.google.protobuf as betterproto_lib_google_protobuf
|
||||
|
||||
|
||||
class CodeGeneratorResponseFeature(betterproto.Enum):
|
||||
"""Sync with code_generator.h."""
|
||||
|
||||
FEATURE_NONE = 0
|
||||
FEATURE_PROTO3_OPTIONAL = 1
|
||||
FEATURE_SUPPORTS_EDITIONS = 2
|
||||
|
||||
|
||||
@dataclass(eq=False, repr=False)
|
||||
class Version(betterproto.Message):
|
||||
"""The version number of protocol compiler."""
|
||||
|
||||
major: int = betterproto.int32_field(1)
|
||||
minor: int = betterproto.int32_field(2)
|
||||
patch: int = betterproto.int32_field(3)
|
||||
suffix: str = betterproto.string_field(4)
|
||||
"""
|
||||
A suffix for alpha, beta or rc release, e.g., "alpha-1", "rc2". It should
|
||||
be empty for mainline stable releases.
|
||||
"""
|
||||
|
||||
|
||||
@dataclass(eq=False, repr=False)
|
||||
class CodeGeneratorRequest(betterproto.Message):
|
||||
"""An encoded CodeGeneratorRequest is written to the plugin's stdin."""
|
||||
|
||||
file_to_generate: List[str] = betterproto.string_field(1)
|
||||
"""
|
||||
The .proto files that were explicitly listed on the command-line. The
|
||||
code generator should generate code only for these files. Each file's
|
||||
descriptor will be included in proto_file, below.
|
||||
"""
|
||||
|
||||
parameter: str = betterproto.string_field(2)
|
||||
"""The generator parameter passed on the command-line."""
|
||||
|
||||
proto_file: List[
|
||||
"betterproto_lib_google_protobuf.FileDescriptorProto"
|
||||
] = betterproto.message_field(15)
|
||||
"""
|
||||
FileDescriptorProtos for all files in files_to_generate and everything
|
||||
they import. The files will appear in topological order, so each file
|
||||
appears before any file that imports it.
|
||||
|
||||
Note: the files listed in files_to_generate will include runtime-retention
|
||||
options only, but all other files will include source-retention options.
|
||||
The source_file_descriptors field below is available in case you need
|
||||
source-retention options for files_to_generate.
|
||||
|
||||
protoc guarantees that all proto_files will be written after
|
||||
the fields above, even though this is not technically guaranteed by the
|
||||
protobuf wire format. This theoretically could allow a plugin to stream
|
||||
in the FileDescriptorProtos and handle them one by one rather than read
|
||||
the entire set into memory at once. However, as of this writing, this
|
||||
is not similarly optimized on protoc's end -- it will store all fields in
|
||||
memory at once before sending them to the plugin.
|
||||
|
||||
Type names of fields and extensions in the FileDescriptorProto are always
|
||||
fully qualified.
|
||||
"""
|
||||
|
||||
source_file_descriptors: List[
|
||||
"betterproto_lib_google_protobuf.FileDescriptorProto"
|
||||
] = betterproto.message_field(17)
|
||||
"""
|
||||
File descriptors with all options, including source-retention options.
|
||||
These descriptors are only provided for the files listed in
|
||||
files_to_generate.
|
||||
"""
|
||||
|
||||
compiler_version: "Version" = betterproto.message_field(3)
|
||||
"""The version number of protocol compiler."""
|
||||
|
||||
|
||||
@dataclass(eq=False, repr=False)
|
||||
class CodeGeneratorResponse(betterproto.Message):
|
||||
"""The plugin writes an encoded CodeGeneratorResponse to stdout."""
|
||||
|
||||
error: str = betterproto.string_field(1)
|
||||
"""
|
||||
Error message. If non-empty, code generation failed. The plugin process
|
||||
should exit with status code zero even if it reports an error in this way.
|
||||
|
||||
This should be used to indicate errors in .proto files which prevent the
|
||||
code generator from generating correct code. Errors which indicate a
|
||||
problem in protoc itself -- such as the input CodeGeneratorRequest being
|
||||
unparseable -- should be reported by writing a message to stderr and
|
||||
exiting with a non-zero status code.
|
||||
"""
|
||||
|
||||
supported_features: int = betterproto.uint64_field(2)
|
||||
"""
|
||||
A bitmask of supported features that the code generator supports.
|
||||
This is a bitwise "or" of values from the Feature enum.
|
||||
"""
|
||||
|
||||
minimum_edition: int = betterproto.int32_field(3)
|
||||
"""
|
||||
The minimum edition this plugin supports. This will be treated as an
|
||||
Edition enum, but we want to allow unknown values. It should be specified
|
||||
according the edition enum value, *not* the edition number. Only takes
|
||||
effect for plugins that have FEATURE_SUPPORTS_EDITIONS set.
|
||||
"""
|
||||
|
||||
maximum_edition: int = betterproto.int32_field(4)
|
||||
"""
|
||||
The maximum edition this plugin supports. This will be treated as an
|
||||
Edition enum, but we want to allow unknown values. It should be specified
|
||||
according the edition enum value, *not* the edition number. Only takes
|
||||
effect for plugins that have FEATURE_SUPPORTS_EDITIONS set.
|
||||
"""
|
||||
|
||||
file: List["CodeGeneratorResponseFile"] = betterproto.message_field(15)
|
||||
|
||||
|
||||
@dataclass(eq=False, repr=False)
|
||||
class CodeGeneratorResponseFile(betterproto.Message):
|
||||
"""Represents a single generated file."""
|
||||
|
||||
name: str = betterproto.string_field(1)
|
||||
"""
|
||||
The file name, relative to the output directory. The name must not
|
||||
contain "." or ".." components and must be relative, not be absolute (so,
|
||||
the file cannot lie outside the output directory). "/" must be used as
|
||||
the path separator, not "\".
|
||||
|
||||
If the name is omitted, the content will be appended to the previous
|
||||
file. This allows the generator to break large files into small chunks,
|
||||
and allows the generated text to be streamed back to protoc so that large
|
||||
files need not reside completely in memory at one time. Note that as of
|
||||
this writing protoc does not optimize for this -- it will read the entire
|
||||
CodeGeneratorResponse before writing files to disk.
|
||||
"""
|
||||
|
||||
insertion_point: str = betterproto.string_field(2)
|
||||
"""
|
||||
If non-empty, indicates that the named file should already exist, and the
|
||||
content here is to be inserted into that file at a defined insertion
|
||||
point. This feature allows a code generator to extend the output
|
||||
produced by another code generator. The original generator may provide
|
||||
insertion points by placing special annotations in the file that look
|
||||
like:
|
||||
@@protoc_insertion_point(NAME)
|
||||
The annotation can have arbitrary text before and after it on the line,
|
||||
which allows it to be placed in a comment. NAME should be replaced with
|
||||
an identifier naming the point -- this is what other generators will use
|
||||
as the insertion_point. Code inserted at this point will be placed
|
||||
immediately above the line containing the insertion point (thus multiple
|
||||
insertions to the same point will come out in the order they were added).
|
||||
The double-@ is intended to make it unlikely that the generated code
|
||||
could contain things that look like insertion points by accident.
|
||||
|
||||
For example, the C++ code generator places the following line in the
|
||||
.pb.h files that it generates:
|
||||
// @@protoc_insertion_point(namespace_scope)
|
||||
This line appears within the scope of the file's package namespace, but
|
||||
outside of any particular class. Another plugin can then specify the
|
||||
insertion_point "namespace_scope" to generate additional classes or
|
||||
other declarations that should be placed in this scope.
|
||||
|
||||
Note that if the line containing the insertion point begins with
|
||||
whitespace, the same whitespace will be added to every line of the
|
||||
inserted text. This is useful for languages like Python, where
|
||||
indentation matters. In these languages, the insertion point comment
|
||||
should be indented the same amount as any inserted code will need to be
|
||||
in order to work correctly in that context.
|
||||
|
||||
The code generator that generates the initial file and the one which
|
||||
inserts into it must both run as part of a single invocation of protoc.
|
||||
Code generators are executed in the order in which they appear on the
|
||||
command line.
|
||||
|
||||
If |insertion_point| is present, |name| must also be present.
|
||||
"""
|
||||
|
||||
content: str = betterproto.string_field(15)
|
||||
"""The file contents."""
|
||||
|
||||
generated_code_info: "betterproto_lib_google_protobuf.GeneratedCodeInfo" = (
|
||||
betterproto.message_field(16)
|
||||
)
|
||||
"""
|
||||
Information describing the file content being inserted. If an insertion
|
||||
point is used, this information will be appropriately offset and inserted
|
||||
into the code generation metadata for the generated files.
|
||||
"""
|
@ -562,6 +562,7 @@ class FieldCompiler(MessageCompiler):
|
||||
package=self.output_file.package,
|
||||
imports=self.output_file.imports,
|
||||
source_type=self.proto_obj.type_name,
|
||||
pydantic=self.output_file.pydantic_dataclasses,
|
||||
)
|
||||
else:
|
||||
raise NotImplementedError(f"Unknown type {self.proto_obj.type}")
|
||||
@ -806,6 +807,7 @@ class ServiceMethodCompiler(ProtoContentBase):
|
||||
imports=self.output_file.imports,
|
||||
source_type=self.proto_obj.input_type,
|
||||
unwrap=False,
|
||||
pydantic=self.output_file.pydantic_dataclasses,
|
||||
).strip('"')
|
||||
|
||||
@property
|
||||
@ -834,6 +836,7 @@ class ServiceMethodCompiler(ProtoContentBase):
|
||||
imports=self.output_file.imports,
|
||||
source_type=self.proto_obj.output_type,
|
||||
unwrap=False,
|
||||
pydantic=self.output_file.pydantic_dataclasses,
|
||||
).strip('"')
|
||||
|
||||
@property
|
||||
|
@ -35,7 +35,48 @@ def test_reference_google_wellknown_types_non_wrappers(
|
||||
google_type: str, expected_name: str, expected_import: str
|
||||
):
|
||||
imports = set()
|
||||
name = get_type_reference(package="", imports=imports, source_type=google_type)
|
||||
name = get_type_reference(
|
||||
package="", imports=imports, source_type=google_type, pydantic=False
|
||||
)
|
||||
|
||||
assert name == expected_name
|
||||
assert imports.__contains__(
|
||||
expected_import
|
||||
), f"{expected_import} not found in {imports}"
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
["google_type", "expected_name", "expected_import"],
|
||||
[
|
||||
(
|
||||
".google.protobuf.Empty",
|
||||
'"betterproto_lib_pydantic_google_protobuf.Empty"',
|
||||
"import betterproto.lib.pydantic.google.protobuf as betterproto_lib_pydantic_google_protobuf",
|
||||
),
|
||||
(
|
||||
".google.protobuf.Struct",
|
||||
'"betterproto_lib_pydantic_google_protobuf.Struct"',
|
||||
"import betterproto.lib.pydantic.google.protobuf as betterproto_lib_pydantic_google_protobuf",
|
||||
),
|
||||
(
|
||||
".google.protobuf.ListValue",
|
||||
'"betterproto_lib_pydantic_google_protobuf.ListValue"',
|
||||
"import betterproto.lib.pydantic.google.protobuf as betterproto_lib_pydantic_google_protobuf",
|
||||
),
|
||||
(
|
||||
".google.protobuf.Value",
|
||||
'"betterproto_lib_pydantic_google_protobuf.Value"',
|
||||
"import betterproto.lib.pydantic.google.protobuf as betterproto_lib_pydantic_google_protobuf",
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_reference_google_wellknown_types_non_wrappers_pydantic(
|
||||
google_type: str, expected_name: str, expected_import: str
|
||||
):
|
||||
imports = set()
|
||||
name = get_type_reference(
|
||||
package="", imports=imports, source_type=google_type, pydantic=True
|
||||
)
|
||||
|
||||
assert name == expected_name
|
||||
assert imports.__contains__(
|
||||
|
@ -1,6 +1,7 @@
|
||||
import json
|
||||
|
||||
from betterproto.lib.google.protobuf import Struct
|
||||
from betterproto.lib.pydantic.google.protobuf import Struct as StructPydantic
|
||||
|
||||
|
||||
def test_struct_roundtrip():
|
||||
@ -22,3 +23,14 @@ def test_struct_roundtrip():
|
||||
assert struct_from_json.to_dict() == data
|
||||
assert struct_from_json == struct_from_dict
|
||||
assert struct_from_json.to_json() == data_json
|
||||
|
||||
struct_pyd_from_dict = StructPydantic(fields={}).from_dict(data)
|
||||
assert struct_pyd_from_dict.fields == data
|
||||
assert struct_pyd_from_dict.to_dict() == data
|
||||
assert struct_pyd_from_dict.to_json() == data_json
|
||||
|
||||
struct_pyd_from_dict = StructPydantic(fields={}).from_json(data_json)
|
||||
assert struct_pyd_from_dict.fields == data
|
||||
assert struct_pyd_from_dict.to_dict() == data
|
||||
assert struct_pyd_from_dict == struct_pyd_from_dict
|
||||
assert struct_pyd_from_dict.to_json() == data_json
|
||||
|
Loading…
x
Reference in New Issue
Block a user