betterproto2-compiler 0.5.1__py3-none-any.whl → 0.7.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- betterproto2_compiler/compile/importing.py +62 -30
- betterproto2_compiler/lib/google/protobuf/__init__.py +1 -1
- betterproto2_compiler/lib/google/protobuf/compiler/__init__.py +1 -1
- betterproto2_compiler/plugin/compiler.py +14 -4
- betterproto2_compiler/plugin/models.py +89 -4
- betterproto2_compiler/plugin/parser.py +23 -8
- betterproto2_compiler/settings.py +1 -0
- betterproto2_compiler/templates/header.py.j2 +12 -10
- betterproto2_compiler/templates/service_stub.py.j2 +1 -1
- betterproto2_compiler/templates/template.py.j2 +27 -4
- betterproto2_compiler-0.7.0.dist-info/METADATA +15 -0
- {betterproto2_compiler-0.5.1.dist-info → betterproto2_compiler-0.7.0.dist-info}/RECORD +16 -17
- {betterproto2_compiler-0.5.1.dist-info → betterproto2_compiler-0.7.0.dist-info}/WHEEL +1 -1
- betterproto2_compiler-0.7.0.dist-info/entry_points.txt +2 -0
- betterproto2_compiler-0.5.1.dist-info/LICENSE.md +0 -22
- betterproto2_compiler-0.5.1.dist-info/METADATA +0 -36
- betterproto2_compiler-0.5.1.dist-info/entry_points.txt +0 -3
@@ -55,6 +55,32 @@ def parse_source_type_name(field_type_name: str, request: PluginRequestCompiler)
|
|
55
55
|
raise ValueError(f"can't find type name: {field_type_name}")
|
56
56
|
|
57
57
|
|
58
|
+
def get_symbol_reference(
|
59
|
+
*,
|
60
|
+
package: str,
|
61
|
+
imports: set,
|
62
|
+
source_package: str,
|
63
|
+
symbol: str,
|
64
|
+
) -> tuple[str, str | None]:
|
65
|
+
"""
|
66
|
+
Return a Python symbol within a proto package. Adds the import if
|
67
|
+
necessary and returns it as well for usage. Unwraps well known type if required.
|
68
|
+
"""
|
69
|
+
current_package: list[str] = package.split(".") if package else []
|
70
|
+
py_package: list[str] = source_package.split(".") if source_package else []
|
71
|
+
|
72
|
+
if py_package == current_package:
|
73
|
+
return (reference_sibling(symbol), None)
|
74
|
+
|
75
|
+
if py_package[: len(current_package)] == current_package:
|
76
|
+
return reference_descendent(current_package, imports, py_package, symbol)
|
77
|
+
|
78
|
+
if current_package[: len(py_package)] == py_package:
|
79
|
+
return reference_ancestor(current_package, imports, py_package, symbol)
|
80
|
+
|
81
|
+
return reference_cousin(current_package, imports, py_package, symbol)
|
82
|
+
|
83
|
+
|
58
84
|
def get_type_reference(
|
59
85
|
*,
|
60
86
|
package: str,
|
@@ -73,30 +99,25 @@ def get_type_reference(
|
|
73
99
|
if wrap and (source_package, source_type) in WRAPPED_TYPES:
|
74
100
|
return WRAPPED_TYPES[(source_package, source_type)]
|
75
101
|
|
76
|
-
current_package: list[str] = package.split(".") if package else []
|
77
|
-
py_package: list[str] = source_package.split(".") if source_package else []
|
78
102
|
py_type: str = pythonize_class_name(source_type)
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
if current_package[: len(py_package)] == py_package:
|
87
|
-
return reference_ancestor(current_package, imports, py_package, py_type)
|
88
|
-
|
89
|
-
return reference_cousin(current_package, imports, py_package, py_type)
|
103
|
+
(ref, _) = get_symbol_reference(
|
104
|
+
package=package,
|
105
|
+
imports=imports,
|
106
|
+
source_package=source_package,
|
107
|
+
symbol=py_type,
|
108
|
+
)
|
109
|
+
return ref
|
90
110
|
|
91
111
|
|
92
|
-
def reference_absolute(imports: set[str], py_package: list[str], py_type: str) -> str:
|
112
|
+
def reference_absolute(imports: set[str], py_package: list[str], py_type: str) -> tuple[str, str]:
|
93
113
|
"""
|
94
114
|
Returns a reference to a python type located in the root, i.e. sys.path.
|
95
115
|
"""
|
96
116
|
string_import = ".".join(py_package)
|
97
117
|
string_alias = "__".join([safe_snake_case(name) for name in py_package])
|
98
|
-
|
99
|
-
|
118
|
+
import_to_add = f"import {string_import} as {string_alias}"
|
119
|
+
imports.add(import_to_add)
|
120
|
+
return (f"{string_alias}.{py_type}", import_to_add)
|
100
121
|
|
101
122
|
|
102
123
|
def reference_sibling(py_type: str) -> str:
|
@@ -106,7 +127,9 @@ def reference_sibling(py_type: str) -> str:
|
|
106
127
|
return f"{py_type}"
|
107
128
|
|
108
129
|
|
109
|
-
def reference_descendent(
|
130
|
+
def reference_descendent(
|
131
|
+
current_package: list[str], imports: set[str], py_package: list[str], py_type: str
|
132
|
+
) -> tuple[str, str]:
|
110
133
|
"""
|
111
134
|
Returns a reference to a python type in a package that is a descendent of the
|
112
135
|
current package, and adds the required import that is aliased to avoid name
|
@@ -116,15 +139,19 @@ def reference_descendent(current_package: list[str], imports: set[str], py_packa
|
|
116
139
|
string_from = ".".join(importing_descendent[:-1])
|
117
140
|
string_import = importing_descendent[-1]
|
118
141
|
if string_from:
|
119
|
-
string_alias = "_
|
120
|
-
|
121
|
-
|
142
|
+
string_alias = f"{'_'.join(importing_descendent)}"
|
143
|
+
import_to_add = f"from .{string_from} import {string_import} as {string_alias}"
|
144
|
+
imports.add(import_to_add)
|
145
|
+
return (f"{string_alias}.{py_type}", import_to_add)
|
122
146
|
else:
|
123
|
-
|
124
|
-
|
147
|
+
import_to_add = f"from . import {string_import}"
|
148
|
+
imports.add(import_to_add)
|
149
|
+
return (f"{string_import}.{py_type}", import_to_add)
|
125
150
|
|
126
151
|
|
127
|
-
def reference_ancestor(
|
152
|
+
def reference_ancestor(
|
153
|
+
current_package: list[str], imports: set[str], py_package: list[str], py_type: str
|
154
|
+
) -> tuple[str, str]:
|
128
155
|
"""
|
129
156
|
Returns a reference to a python type in a package which is an ancestor to the
|
130
157
|
current package, and adds the required import that is aliased (if possible) to avoid
|
@@ -137,15 +164,19 @@ def reference_ancestor(current_package: list[str], imports: set[str], py_package
|
|
137
164
|
string_import = py_package[-1]
|
138
165
|
string_alias = f"_{'_' * distance_up}{string_import}__"
|
139
166
|
string_from = f"..{'.' * distance_up}"
|
140
|
-
|
141
|
-
|
167
|
+
import_to_add = f"from {string_from} import {string_import} as {string_alias}"
|
168
|
+
imports.add(import_to_add)
|
169
|
+
return (f"{string_alias}.{py_type}", import_to_add)
|
142
170
|
else:
|
143
171
|
string_alias = f"{'_' * distance_up}{py_type}__"
|
144
|
-
|
145
|
-
|
172
|
+
import_to_add = f"from .{'.' * distance_up} import {py_type} as {string_alias}"
|
173
|
+
imports.add(import_to_add)
|
174
|
+
return (string_alias, import_to_add)
|
146
175
|
|
147
176
|
|
148
|
-
def reference_cousin(
|
177
|
+
def reference_cousin(
|
178
|
+
current_package: list[str], imports: set[str], py_package: list[str], py_type: str
|
179
|
+
) -> tuple[str, str]:
|
149
180
|
"""
|
150
181
|
Returns a reference to a python type in a package that is not descendent, ancestor
|
151
182
|
or sibling, and adds the required import that is aliased to avoid name conflicts.
|
@@ -161,5 +192,6 @@ def reference_cousin(current_package: list[str], imports: set[str], py_package:
|
|
161
192
|
+ "__".join([safe_snake_case(name) for name in py_package[len(shared_ancestry) :]])
|
162
193
|
+ "__"
|
163
194
|
)
|
164
|
-
|
165
|
-
|
195
|
+
import_to_add = f"from {string_from} import {string_import} as {string_alias}"
|
196
|
+
imports.add(import_to_add)
|
197
|
+
return (f"{string_alias}.{py_type}", import_to_add)
|
@@ -33,17 +33,27 @@ def outputfile_compiler(output_file: OutputTemplate) -> str:
|
|
33
33
|
loader=jinja2.FileSystemLoader(templates_folder),
|
34
34
|
undefined=jinja2.StrictUndefined,
|
35
35
|
)
|
36
|
-
|
36
|
+
|
37
|
+
# List of the symbols that should appear in the `__all__` variable of the file
|
38
|
+
all: list[str] = []
|
39
|
+
|
40
|
+
def add_to_all(name: str) -> str:
|
41
|
+
all.append(name)
|
42
|
+
return name
|
43
|
+
|
44
|
+
env.filters["add_to_all"] = add_to_all
|
45
|
+
|
37
46
|
body_template = env.get_template("template.py.j2")
|
38
47
|
header_template = env.get_template("header.py.j2")
|
39
48
|
|
49
|
+
# Load the body first do know the symbols defined in the file
|
40
50
|
code = body_template.render(output_file=output_file)
|
41
|
-
code = header_template.render(output_file=output_file, version=version) + "\n" + code
|
51
|
+
code = header_template.render(output_file=output_file, version=version, all=all) + "\n" + code
|
42
52
|
|
43
53
|
try:
|
44
|
-
# Sort imports, delete unused ones
|
54
|
+
# Sort imports, delete unused ones, sort __all__
|
45
55
|
code = subprocess.check_output(
|
46
|
-
["ruff", "check", "--select", "I,F401,
|
56
|
+
["ruff", "check", "--select", "I,F401,TC005,RUF022", "--fix", "--silent", "-"],
|
47
57
|
input=code,
|
48
58
|
encoding="utf-8",
|
49
59
|
)
|
@@ -53,6 +53,7 @@ from betterproto2_compiler.lib.google.protobuf import (
|
|
53
53
|
MethodDescriptorProto,
|
54
54
|
OneofDescriptorProto,
|
55
55
|
ServiceDescriptorProto,
|
56
|
+
SourceCodeInfo,
|
56
57
|
)
|
57
58
|
from betterproto2_compiler.lib.google.protobuf.compiler import CodeGeneratorRequest
|
58
59
|
from betterproto2_compiler.settings import Settings
|
@@ -216,6 +217,33 @@ class OutputTemplate:
|
|
216
217
|
"""
|
217
218
|
return sorted([f.name for f in self.input_files])
|
218
219
|
|
220
|
+
def get_descriptor_name(self, source_file: FileDescriptorProto):
|
221
|
+
return f"{source_file.name.replace('/', '_').replace('.', '_').upper()}_DESCRIPTOR"
|
222
|
+
|
223
|
+
@property
|
224
|
+
def descriptors(self):
|
225
|
+
"""Google protobuf library descriptors.
|
226
|
+
|
227
|
+
Returns
|
228
|
+
-------
|
229
|
+
str
|
230
|
+
A list of pool registrations for proto descriptors.
|
231
|
+
"""
|
232
|
+
descriptors: list[str] = []
|
233
|
+
|
234
|
+
for f in self.input_files:
|
235
|
+
# Remove the source_code_info field since it is not needed at runtime.
|
236
|
+
source_code_info: SourceCodeInfo | None = f.source_code_info
|
237
|
+
f.source_code_info = None
|
238
|
+
|
239
|
+
descriptors.append(
|
240
|
+
f"{self.get_descriptor_name(f)} = default_google_proto_descriptor_pool.AddSerializedFile({bytes(f)})"
|
241
|
+
)
|
242
|
+
|
243
|
+
f.source_code_info = source_code_info
|
244
|
+
|
245
|
+
return "\n".join(descriptors)
|
246
|
+
|
219
247
|
|
220
248
|
@dataclass(kw_only=True)
|
221
249
|
class MessageCompiler(ProtoContentBase):
|
@@ -223,6 +251,7 @@ class MessageCompiler(ProtoContentBase):
|
|
223
251
|
|
224
252
|
output_file: OutputTemplate
|
225
253
|
proto_obj: DescriptorProto
|
254
|
+
prefixed_proto_name: str
|
226
255
|
fields: list["FieldCompiler"] = field(default_factory=list)
|
227
256
|
oneofs: list["OneofCompiler"] = field(default_factory=list)
|
228
257
|
builtins_types: set[str] = field(default_factory=set)
|
@@ -233,7 +262,7 @@ class MessageCompiler(ProtoContentBase):
|
|
233
262
|
|
234
263
|
@property
|
235
264
|
def py_name(self) -> str:
|
236
|
-
return pythonize_class_name(self.
|
265
|
+
return pythonize_class_name(self.prefixed_proto_name)
|
237
266
|
|
238
267
|
@property
|
239
268
|
def deprecated(self) -> bool:
|
@@ -266,6 +295,17 @@ class MessageCompiler(ProtoContentBase):
|
|
266
295
|
|
267
296
|
return methods_source
|
268
297
|
|
298
|
+
@property
|
299
|
+
def descriptor_name(self) -> str:
|
300
|
+
"""Google protobuf library descriptor name.
|
301
|
+
|
302
|
+
Returns
|
303
|
+
-------
|
304
|
+
str
|
305
|
+
The Python name of the descriptor to reference.
|
306
|
+
"""
|
307
|
+
return self.output_file.get_descriptor_name(self.source_file)
|
308
|
+
|
269
309
|
|
270
310
|
def is_map(proto_field_obj: FieldDescriptorProto, parent_message: DescriptorProto) -> bool:
|
271
311
|
"""True if proto_field_obj is a map, otherwise False."""
|
@@ -353,8 +393,7 @@ class FieldCompiler(ProtoContentBase):
|
|
353
393
|
|
354
394
|
@property
|
355
395
|
def field_type(self) -> FieldType:
|
356
|
-
|
357
|
-
return FieldType(self.proto_obj.type)
|
396
|
+
return self.proto_obj.type
|
358
397
|
|
359
398
|
@property
|
360
399
|
def packed(self) -> bool:
|
@@ -411,12 +450,46 @@ class FieldCompiler(ProtoContentBase):
|
|
411
450
|
def unwrapped_py_type(self) -> str:
|
412
451
|
return self._py_type(wrap=False)
|
413
452
|
|
453
|
+
@property
|
454
|
+
def annotations(self) -> list[str]:
|
455
|
+
"""List of the Pydantic annotation to add to the field."""
|
456
|
+
assert self.output_file.settings.pydantic_dataclasses
|
457
|
+
|
458
|
+
annotations = []
|
459
|
+
|
460
|
+
if self.proto_obj.type in (FieldType.TYPE_INT32, FieldType.TYPE_SFIXED32, FieldType.TYPE_SINT32):
|
461
|
+
annotations.append("pydantic.Field(ge=-2**31, le=2**31 - 1)")
|
462
|
+
|
463
|
+
elif self.proto_obj.type in (FieldType.TYPE_UINT32, FieldType.TYPE_FIXED32):
|
464
|
+
annotations.append("pydantic.Field(ge=0, le=2**32 - 1)")
|
465
|
+
|
466
|
+
elif self.proto_obj.type in (FieldType.TYPE_INT64, FieldType.TYPE_SFIXED64, FieldType.TYPE_SINT64):
|
467
|
+
annotations.append("pydantic.Field(ge=-2**63, le=2**63 - 1)")
|
468
|
+
|
469
|
+
elif self.proto_obj.type in (FieldType.TYPE_UINT64, FieldType.TYPE_FIXED64):
|
470
|
+
annotations.append("pydantic.Field(ge=0, le=2**64 - 1)")
|
471
|
+
|
472
|
+
elif self.proto_obj.type == FieldType.TYPE_FLOAT:
|
473
|
+
annotations.append("pydantic.AfterValidator(betterproto2.validators.validate_float32)")
|
474
|
+
|
475
|
+
elif self.proto_obj.type == FieldType.TYPE_STRING:
|
476
|
+
annotations.append("pydantic.AfterValidator(betterproto2.validators.validate_string)")
|
477
|
+
|
478
|
+
return annotations
|
479
|
+
|
414
480
|
@property
|
415
481
|
def annotation(self) -> str:
|
416
482
|
py_type = self.py_type
|
417
483
|
|
418
484
|
if self.use_builtins:
|
419
485
|
py_type = f"builtins.{py_type}"
|
486
|
+
|
487
|
+
# Add the pydantic annotation if needed
|
488
|
+
if self.output_file.settings.pydantic_dataclasses:
|
489
|
+
annotations = self.annotations
|
490
|
+
if annotations:
|
491
|
+
py_type = f"typing.Annotated[{py_type}, {', '.join(annotations)}]"
|
492
|
+
|
420
493
|
if self.repeated:
|
421
494
|
return f"list[{py_type}]"
|
422
495
|
if self.optional:
|
@@ -529,6 +602,7 @@ class EnumDefinitionCompiler(ProtoContentBase):
|
|
529
602
|
|
530
603
|
output_file: OutputTemplate
|
531
604
|
proto_obj: EnumDescriptorProto
|
605
|
+
prefixed_proto_name: str
|
532
606
|
entries: list["EnumDefinitionCompiler.EnumEntry"] = field(default_factory=list)
|
533
607
|
|
534
608
|
@dataclass(unsafe_hash=True, kw_only=True)
|
@@ -556,12 +630,23 @@ class EnumDefinitionCompiler(ProtoContentBase):
|
|
556
630
|
|
557
631
|
@property
|
558
632
|
def py_name(self) -> str:
|
559
|
-
return pythonize_class_name(self.
|
633
|
+
return pythonize_class_name(self.prefixed_proto_name)
|
560
634
|
|
561
635
|
@property
|
562
636
|
def deprecated(self) -> bool:
|
563
637
|
return bool(self.proto_obj.options and self.proto_obj.options.deprecated)
|
564
638
|
|
639
|
+
@property
|
640
|
+
def descriptor_name(self) -> str:
|
641
|
+
"""Google protobuf library descriptor name.
|
642
|
+
|
643
|
+
Returns
|
644
|
+
-------
|
645
|
+
str
|
646
|
+
The Python name of the descriptor to reference.
|
647
|
+
"""
|
648
|
+
return self.output_file.get_descriptor_name(self.source_file)
|
649
|
+
|
565
650
|
|
566
651
|
@dataclass(kw_only=True)
|
567
652
|
class ServiceCompiler(ProtoContentBase):
|
@@ -35,20 +35,21 @@ from .models import (
|
|
35
35
|
|
36
36
|
def traverse(
|
37
37
|
proto_file: FileDescriptorProto,
|
38
|
-
) -> Generator[tuple[EnumDescriptorProto | DescriptorProto, list[int]], None, None]:
|
38
|
+
) -> Generator[tuple[EnumDescriptorProto | DescriptorProto, list[int], str], None, None]:
|
39
39
|
# Todo: Keep information about nested hierarchy
|
40
40
|
def _traverse(
|
41
41
|
path: list[int],
|
42
42
|
items: list[EnumDescriptorProto] | list[DescriptorProto],
|
43
43
|
prefix: str = "",
|
44
|
-
) -> Generator[tuple[EnumDescriptorProto | DescriptorProto, list[int]], None, None]:
|
44
|
+
) -> Generator[tuple[EnumDescriptorProto | DescriptorProto, list[int], str], None, None]:
|
45
45
|
for i, item in enumerate(items):
|
46
46
|
# Adjust the name since we flatten the hierarchy.
|
47
|
-
# Todo: don't change the name, but include full name in returned tuple
|
48
47
|
should_rename = not isinstance(item, DescriptorProto) or not item.options or not item.options.map_entry
|
49
48
|
|
50
|
-
|
51
|
-
|
49
|
+
# Record prefixed name but *do not* mutate original file.
|
50
|
+
# We use this prefixed name to create pythonized names.
|
51
|
+
prefixed_name = next_prefix = f"{prefix}.{item.name}" if prefix and should_rename else item.name
|
52
|
+
yield item, [*path, i], prefixed_name
|
52
53
|
|
53
54
|
if isinstance(item, DescriptorProto):
|
54
55
|
# Get nested types.
|
@@ -81,6 +82,7 @@ def get_settings(plugin_options: list[str]) -> Settings:
|
|
81
82
|
|
82
83
|
return Settings(
|
83
84
|
pydantic_dataclasses="pydantic_dataclasses" in plugin_options,
|
85
|
+
google_protobuf_descriptors="google_protobuf_descriptors" in plugin_options,
|
84
86
|
client_generation=client_generation,
|
85
87
|
server_generation=server_generation,
|
86
88
|
)
|
@@ -109,12 +111,13 @@ def generate_code(request: CodeGeneratorRequest) -> CodeGeneratorResponse:
|
|
109
111
|
# get the references to input/output messages for each service
|
110
112
|
for output_package_name, output_package in request_data.output_packages.items():
|
111
113
|
for proto_input_file in output_package.input_files:
|
112
|
-
for item, path in traverse(proto_input_file):
|
114
|
+
for item, path, prefixed_proto_name in traverse(proto_input_file):
|
113
115
|
read_protobuf_type(
|
114
116
|
source_file=proto_input_file,
|
115
117
|
item=item,
|
116
118
|
path=path,
|
117
119
|
output_package=output_package,
|
120
|
+
prefixed_proto_name=prefixed_proto_name,
|
118
121
|
)
|
119
122
|
|
120
123
|
# Read Services
|
@@ -168,6 +171,15 @@ def generate_code(request: CodeGeneratorRequest) -> CodeGeneratorResponse:
|
|
168
171
|
)
|
169
172
|
)
|
170
173
|
|
174
|
+
if settings.google_protobuf_descriptors:
|
175
|
+
response.file.append(
|
176
|
+
CodeGeneratorResponseFile(
|
177
|
+
name="google_proto_descriptor_pool.py",
|
178
|
+
content="from google.protobuf import descriptor_pool\n\n"
|
179
|
+
+ "default_google_proto_descriptor_pool = descriptor_pool.DescriptorPool()\n",
|
180
|
+
)
|
181
|
+
)
|
182
|
+
|
171
183
|
for output_package_name in sorted(output_paths.union(init_files)):
|
172
184
|
print(f"Writing {output_package_name}", file=sys.stderr)
|
173
185
|
|
@@ -179,6 +191,7 @@ def read_protobuf_type(
|
|
179
191
|
path: list[int],
|
180
192
|
source_file: "FileDescriptorProto",
|
181
193
|
output_package: OutputTemplate,
|
194
|
+
prefixed_proto_name: str,
|
182
195
|
) -> None:
|
183
196
|
if isinstance(item, DescriptorProto):
|
184
197
|
if item.options and item.options.map_entry:
|
@@ -188,10 +201,11 @@ def read_protobuf_type(
|
|
188
201
|
message_data = MessageCompiler(
|
189
202
|
source_file=source_file,
|
190
203
|
output_file=output_package,
|
204
|
+
prefixed_proto_name=prefixed_proto_name,
|
191
205
|
proto_obj=item,
|
192
206
|
path=path,
|
193
207
|
)
|
194
|
-
output_package.messages[message_data.
|
208
|
+
output_package.messages[message_data.prefixed_proto_name] = message_data
|
195
209
|
|
196
210
|
for index, field in enumerate(item.field):
|
197
211
|
if is_map(field, item):
|
@@ -243,10 +257,11 @@ def read_protobuf_type(
|
|
243
257
|
enum = EnumDefinitionCompiler(
|
244
258
|
source_file=source_file,
|
245
259
|
output_file=output_package,
|
260
|
+
prefixed_proto_name=prefixed_proto_name,
|
246
261
|
proto_obj=item,
|
247
262
|
path=path,
|
248
263
|
)
|
249
|
-
output_package.enums[enum.
|
264
|
+
output_package.enums[enum.prefixed_proto_name] = enum
|
250
265
|
|
251
266
|
|
252
267
|
def read_protobuf_service(
|
@@ -6,15 +6,8 @@
|
|
6
6
|
# This file has been @generated
|
7
7
|
|
8
8
|
__all__ = (
|
9
|
-
{
|
10
|
-
|
11
|
-
{%- endfor -%}
|
12
|
-
{% for _, message in output_file.messages|dictsort(by="key") %}
|
13
|
-
"{{ message.py_name }}",
|
14
|
-
{%- endfor -%}
|
15
|
-
{% for _, service in output_file.services|dictsort(by="key") %}
|
16
|
-
"{{ service.py_name }}Stub",
|
17
|
-
"{{ service.py_name }}Base",
|
9
|
+
{%- for name in all -%}
|
10
|
+
"{{ name }}",
|
18
11
|
{%- endfor -%}
|
19
12
|
)
|
20
13
|
|
@@ -28,6 +21,7 @@ import typing
|
|
28
21
|
from typing import TYPE_CHECKING
|
29
22
|
|
30
23
|
{% if output_file.settings.pydantic_dataclasses %}
|
24
|
+
import pydantic
|
31
25
|
from pydantic.dataclasses import dataclass
|
32
26
|
from pydantic import model_validator
|
33
27
|
{%- else -%}
|
@@ -38,12 +32,19 @@ import betterproto2
|
|
38
32
|
from betterproto2.grpc.grpclib_server import ServiceBase
|
39
33
|
import grpc
|
40
34
|
import grpclib
|
35
|
+
from google.protobuf.descriptor import Descriptor, EnumDescriptor
|
41
36
|
|
42
37
|
{# Import the message pool of the generated code. #}
|
43
38
|
{% if output_file.package %}
|
44
39
|
from {{ "." * output_file.package.count(".") }}..message_pool import default_message_pool
|
40
|
+
{% if output_file.settings.google_protobuf_descriptors %}
|
41
|
+
from {{ "." * output_file.package.count(".") }}..google_proto_descriptor_pool import default_google_proto_descriptor_pool
|
42
|
+
{% endif %}
|
45
43
|
{% else %}
|
46
44
|
from .message_pool import default_message_pool
|
45
|
+
{% if output_file.settings.google_protobuf_descriptors %}
|
46
|
+
from .google_proto_descriptor_pool import default_google_proto_descriptor_pool
|
47
|
+
{% endif %}
|
47
48
|
{% endif %}
|
48
49
|
|
49
50
|
if TYPE_CHECKING:
|
@@ -51,4 +52,5 @@ if TYPE_CHECKING:
|
|
51
52
|
from betterproto2.grpc.grpclib_client import MetadataLike
|
52
53
|
from grpclib.metadata import Deadline
|
53
54
|
|
54
|
-
|
55
|
+
_COMPILER_VERSION="{{ version }}"
|
56
|
+
betterproto2.check_compiler_version(_COMPILER_VERSION)
|
@@ -1,4 +1,4 @@
|
|
1
|
-
class {% block class_name %}{% endblock %}({% block inherit_from %}{% endblock %}):
|
1
|
+
class {% filter add_to_all %}{% block class_name %}{% endblock %}{% endfilter %}({% block inherit_from %}{% endblock %}):
|
2
2
|
{% block service_docstring scoped %}
|
3
3
|
{% if service.comment %}
|
4
4
|
"""
|
@@ -1,11 +1,18 @@
|
|
1
1
|
{% for _, enum in output_file.enums|dictsort(by="key") %}
|
2
|
-
class {{ enum.py_name }}(betterproto2.Enum):
|
2
|
+
class {{ enum.py_name | add_to_all }}(betterproto2.Enum):
|
3
3
|
{% if enum.comment %}
|
4
4
|
"""
|
5
5
|
{{ enum.comment | indent(4) }}
|
6
6
|
"""
|
7
7
|
{% endif %}
|
8
8
|
|
9
|
+
{% if output_file.settings.google_protobuf_descriptors %}
|
10
|
+
{# Add descriptor class property to be more drop-in compatible with other libraries. #}
|
11
|
+
@betterproto2.classproperty
|
12
|
+
def DESCRIPTOR(self) -> EnumDescriptor:
|
13
|
+
return {{ enum.descriptor_name }}.enum_types_by_name['{{ enum.prefixed_proto_name }}']
|
14
|
+
{% endif %}
|
15
|
+
|
9
16
|
{% for entry in enum.entries %}
|
10
17
|
{{ entry.name }} = {{ entry.value }}
|
11
18
|
{% if entry.comment %}
|
@@ -31,7 +38,7 @@ class {{ enum.py_name }}(betterproto2.Enum):
|
|
31
38
|
{% else %}
|
32
39
|
@dataclass(eq=False, repr=False)
|
33
40
|
{% endif %}
|
34
|
-
class {{ message.py_name }}(betterproto2.Message):
|
41
|
+
class {{ message.py_name | add_to_all }}(betterproto2.Message):
|
35
42
|
{% if message.comment or message.oneofs %}
|
36
43
|
"""
|
37
44
|
{{ message.comment | indent(4) }}
|
@@ -45,6 +52,13 @@ class {{ message.py_name }}(betterproto2.Message):
|
|
45
52
|
"""
|
46
53
|
{% endif %}
|
47
54
|
|
55
|
+
{% if output_file.settings.google_protobuf_descriptors %}
|
56
|
+
{# Add descriptor class property to be more drop-in compatible with other libraries. #}
|
57
|
+
@betterproto2.classproperty
|
58
|
+
def DESCRIPTOR(self) -> Descriptor:
|
59
|
+
return {{ message.descriptor_name }}.message_types_by_name['{{ message.prefixed_proto_name }}']
|
60
|
+
{% endif %}
|
61
|
+
|
48
62
|
{% for field in message.fields %}
|
49
63
|
{{ field.get_field_string() }}
|
50
64
|
{% if field.comment %}
|
@@ -81,7 +95,7 @@ class {{ message.py_name }}(betterproto2.Message):
|
|
81
95
|
{{ method_source }}
|
82
96
|
{% endfor %}
|
83
97
|
|
84
|
-
default_message_pool.register_message("{{ output_file.package }}", "{{ message.
|
98
|
+
default_message_pool.register_message("{{ output_file.package }}", "{{ message.prefixed_proto_name }}", {{ message.py_name }})
|
85
99
|
|
86
100
|
|
87
101
|
{% endfor %}
|
@@ -102,9 +116,14 @@ default_message_pool.register_message("{{ output_file.package }}", "{{ message.p
|
|
102
116
|
{{ i }}
|
103
117
|
{% endfor %}
|
104
118
|
|
119
|
+
{% if output_file.settings.google_protobuf_descriptors %}
|
120
|
+
{# Add descriptors to Google protobuf's default pool to be more drop-in compatible with other libraries. #}
|
121
|
+
{{ output_file.descriptors }}
|
122
|
+
{% endif %}
|
123
|
+
|
105
124
|
{% if output_file.settings.server_generation == "async" %}
|
106
125
|
{% for _, service in output_file.services|dictsort(by="key") %}
|
107
|
-
class {{ service.py_name }}
|
126
|
+
class {{ (service.py_name + "Base") | add_to_all }}(ServiceBase):
|
108
127
|
{% if service.comment %}
|
109
128
|
"""
|
110
129
|
{{ service.comment | indent(4) }}
|
@@ -127,6 +146,10 @@ class {{ service.py_name }}Base(ServiceBase):
|
|
127
146
|
{% endif %}
|
128
147
|
|
129
148
|
raise grpclib.GRPCError(grpclib.const.Status.UNIMPLEMENTED)
|
149
|
+
{% if method.server_streaming %}
|
150
|
+
{# yielding here changes the return type from a coroutine to an async_generator #}
|
151
|
+
yield {{ method.py_output_message_type }}()
|
152
|
+
{% endif %}
|
130
153
|
|
131
154
|
{% endfor %}
|
132
155
|
|
@@ -0,0 +1,15 @@
|
|
1
|
+
Metadata-Version: 2.4
|
2
|
+
Name: betterproto2_compiler
|
3
|
+
Version: 0.7.0
|
4
|
+
Summary: Compiler for betterproto2
|
5
|
+
Project-URL: Documentation, https://betterproto.github.io/python-betterproto2/
|
6
|
+
Project-URL: Repository, https://github.com/betterproto/python-betterproto2
|
7
|
+
Author-email: Adrien Vannson <adrien.vannson@protonmail.com>, "Daniel G. Taylor" <danielgtaylor@gmail.com>
|
8
|
+
License-Expression: MIT
|
9
|
+
Keywords: compiler,gRPC,protobuf
|
10
|
+
Requires-Python: <4.0,>=3.10
|
11
|
+
Requires-Dist: betterproto2[grpclib]<0.8,>=0.7.0
|
12
|
+
Requires-Dist: jinja2>=3.0.3
|
13
|
+
Requires-Dist: ruff~=0.9.3
|
14
|
+
Requires-Dist: strenum<0.5,>=0.4.15; python_version == '3.10'
|
15
|
+
Requires-Dist: typing-extensions<5,>=4.7.1
|
@@ -1,7 +1,9 @@
|
|
1
1
|
betterproto2_compiler/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
2
2
|
betterproto2_compiler/casing.py,sha256=HSXLXAOqZzEnu-tC1SZjpW0LIjzdPqUNJEwy1BHzfgg,3056
|
3
|
+
betterproto2_compiler/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
4
|
+
betterproto2_compiler/settings.py,sha256=Y867wBQad2EunzlsZEd0OjPaXGwzqcBmPKYMG9Q_2Dw,2014
|
3
5
|
betterproto2_compiler/compile/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
4
|
-
betterproto2_compiler/compile/importing.py,sha256=
|
6
|
+
betterproto2_compiler/compile/importing.py,sha256=yfIJ7oEXR1Ghe5meGzOE0ORf1Sr7Xa2Pr_slOw-rT3s,7137
|
5
7
|
betterproto2_compiler/compile/naming.py,sha256=zf0VOmNojzyv33upOGelGxjZTEDE8JULEEED5_3inHg,562
|
6
8
|
betterproto2_compiler/known_types/__init__.py,sha256=nrWckuv4hGhL8-tW7V5TD5qXs1Sa5vC7zMusGnz7jsE,3485
|
7
9
|
betterproto2_compiler/known_types/any.py,sha256=E3OoAoUU9xrGHmYEvF0YnrwQdTUuY4h54XbKU0eGxQ8,1897
|
@@ -9,27 +11,24 @@ betterproto2_compiler/known_types/duration.py,sha256=M-qsFeiHsw5Z_AoSata1ZUjfkho
|
|
9
11
|
betterproto2_compiler/known_types/google_values.py,sha256=7JoPXVs6cVg_ihIWlWIDElSSuW0BymRnPHerz1bFuH4,6688
|
10
12
|
betterproto2_compiler/known_types/timestamp.py,sha256=y1sNWG2Q0FWv6nIte1UTifFVCsryp7T8foXZqp4qhQQ,3409
|
11
13
|
betterproto2_compiler/lib/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
12
|
-
betterproto2_compiler/lib/google/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
13
|
-
betterproto2_compiler/lib/google/protobuf/__init__.py,sha256=yC7k_A1XA9-CPzhIaJfWJSIBpqyaLx7IVVuvXrqD-iQ,102114
|
14
|
-
betterproto2_compiler/lib/google/protobuf/compiler/__init__.py,sha256=IriT5naeEkcxA-R2EpzOGBMLVGgVO6CXqvrR8HVaR28,9600
|
15
14
|
betterproto2_compiler/lib/message_pool.py,sha256=4-cRhhiM6bmfpUJZ8qxc8LEyqHBHpLCcotjbyZxl7JM,71
|
15
|
+
betterproto2_compiler/lib/google/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
16
|
+
betterproto2_compiler/lib/google/protobuf/__init__.py,sha256=r5R69Q9iYg8FZX6J6pCY6xnOTxgl_-zz2Xwn4uGGPyw,102114
|
17
|
+
betterproto2_compiler/lib/google/protobuf/compiler/__init__.py,sha256=SaJT2xsLVFPvTd12R2V2wjEWeP4JewKMPJlIKeyZ2Mk,9600
|
16
18
|
betterproto2_compiler/plugin/__init__.py,sha256=L3pW0b4CvkM5x53x_sYt1kYiSFPO0_vaeH6EQPq9FAM,43
|
17
19
|
betterproto2_compiler/plugin/__main__.py,sha256=vBQ82334kX06ImDbFlPFgiBRiLIinwNk3z8Khs6hd74,31
|
18
|
-
betterproto2_compiler/plugin/compiler.py,sha256=
|
20
|
+
betterproto2_compiler/plugin/compiler.py,sha256=9jZcNlwxWLUQlZyCLKG33P2xCoJgqaIQHIgcZM40JGY,2730
|
19
21
|
betterproto2_compiler/plugin/main.py,sha256=b1jDEdG1Iau-4cPq89uSjU0SHwC278SxqwiuFwIF8fA,1288
|
20
|
-
betterproto2_compiler/plugin/models.py,sha256=
|
22
|
+
betterproto2_compiler/plugin/models.py,sha256=gZ0nIvZbmHJ6OKyQ0gEsbZ1DRicABIOLMge1nyFkOCY,25212
|
21
23
|
betterproto2_compiler/plugin/module_validation.py,sha256=JnP8dSN83eJJVDP_UPJsHzq7E7Md3lah0PnKXDbFW5Q,4808
|
22
|
-
betterproto2_compiler/plugin/parser.py,sha256=
|
24
|
+
betterproto2_compiler/plugin/parser.py,sha256=GHVZGpC_lxvQRGgDaJTCS4ab9sUST7XAef2wj2UKqOg,10966
|
23
25
|
betterproto2_compiler/plugin/plugin.bat,sha256=lfLT1WguAXqyerLLsRL6BfHA0RqUE6QG79v-1BYVSpI,48
|
24
|
-
betterproto2_compiler/py.
|
25
|
-
betterproto2_compiler/
|
26
|
-
betterproto2_compiler/templates/header.py.j2,sha256=nTUJ-BioeTTCrEr2ZbxPPUl6iBqHOxXr_NAVOGa8jYg,1622
|
27
|
-
betterproto2_compiler/templates/service_stub.py.j2,sha256=r0AefgNbDCh-iDgFNV7aNx8fNe5kQY-8TNew-T_tUXc,929
|
26
|
+
betterproto2_compiler/templates/header.py.j2,sha256=4C88YH5jtEzlBcUP054rk6lK5pQ1n5_TCzlH_3VrztY,1754
|
27
|
+
betterproto2_compiler/templates/service_stub.py.j2,sha256=2fhbty6uw57EyxOskGcNlZjIjGELMKWY--pvq5ZEjFw,967
|
28
28
|
betterproto2_compiler/templates/service_stub_async.py.j2,sha256=JNOAa8FPhzYS5D0zi0DPESVEwAjkdFsVQZ008Qi4JmE,2968
|
29
29
|
betterproto2_compiler/templates/service_stub_sync.py.j2,sha256=V7HJIQJEgivX8VEBt7Ju6cXG5FeeCY9QyYMy1kicElM,2642
|
30
|
-
betterproto2_compiler/templates/template.py.j2,sha256=
|
31
|
-
betterproto2_compiler-0.
|
32
|
-
betterproto2_compiler-0.
|
33
|
-
betterproto2_compiler-0.
|
34
|
-
betterproto2_compiler-0.
|
35
|
-
betterproto2_compiler-0.5.1.dist-info/RECORD,,
|
30
|
+
betterproto2_compiler/templates/template.py.j2,sha256=1leU6V5AmlgPvKYCjBYYeVPAnfvcDrl9KQHgiuNiigo,6572
|
31
|
+
betterproto2_compiler-0.7.0.dist-info/METADATA,sha256=rHB3App3Zkmtp7OKB8vlesiZRaz7Ba7tdb5XzwSA5wk,658
|
32
|
+
betterproto2_compiler-0.7.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
33
|
+
betterproto2_compiler-0.7.0.dist-info/entry_points.txt,sha256=MXDaz7YfiaWx8KiSzArjUPLt6eTlMRbqzE4jCjXozuI,85
|
34
|
+
betterproto2_compiler-0.7.0.dist-info/RECORD,,
|
@@ -1,22 +0,0 @@
|
|
1
|
-
MIT License
|
2
|
-
|
3
|
-
Copyright (c) 2023 Daniel G. Taylor
|
4
|
-
Copyright (c) 2024 The betterproto contributors
|
5
|
-
|
6
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
7
|
-
of this software and associated documentation files (the "Software"), to deal
|
8
|
-
in the Software without restriction, including without limitation the rights
|
9
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
10
|
-
copies of the Software, and to permit persons to whom the Software is
|
11
|
-
furnished to do so, subject to the following conditions:
|
12
|
-
|
13
|
-
The above copyright notice and this permission notice shall be included in all
|
14
|
-
copies or substantial portions of the Software.
|
15
|
-
|
16
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
17
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
18
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
19
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
20
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
21
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
22
|
-
SOFTWARE.
|
@@ -1,36 +0,0 @@
|
|
1
|
-
Metadata-Version: 2.3
|
2
|
-
Name: betterproto2_compiler
|
3
|
-
Version: 0.5.1
|
4
|
-
Summary: Compiler for betterproto2
|
5
|
-
License: MIT
|
6
|
-
Keywords: protobuf,gRPC,compiler
|
7
|
-
Author: Adrien Vannson
|
8
|
-
Author-email: adrien.vannson@protonmail.com
|
9
|
-
Requires-Python: >=3.10,<4.0
|
10
|
-
Classifier: License :: OSI Approved :: MIT License
|
11
|
-
Classifier: Programming Language :: Python :: 3
|
12
|
-
Classifier: Programming Language :: Python :: 3.10
|
13
|
-
Classifier: Programming Language :: Python :: 3.11
|
14
|
-
Classifier: Programming Language :: Python :: 3.12
|
15
|
-
Classifier: Programming Language :: Python :: 3.13
|
16
|
-
Requires-Dist: betterproto2[grpclib] (>=0.5.1,<0.6.0)
|
17
|
-
Requires-Dist: jinja2 (>=3.0.3)
|
18
|
-
Requires-Dist: ruff (>=0.9.3,<0.10.0)
|
19
|
-
Requires-Dist: strenum (>=0.4.15,<0.5.0) ; python_version == "3.10"
|
20
|
-
Requires-Dist: typing-extensions (>=4.7.1,<5.0.0)
|
21
|
-
Project-URL: Documentation, https://betterproto.github.io/python-betterproto2-compiler/
|
22
|
-
Project-URL: Repository, https://github.com/betterproto/python-betterproto2-compiler
|
23
|
-
Description-Content-Type: text/markdown
|
24
|
-
|
25
|
-
# Betterproto2 compiler
|
26
|
-
|
27
|
-

|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
## License
|
32
|
-
|
33
|
-
Copyright © 2019 Daniel G. Taylor
|
34
|
-
|
35
|
-
Copyright © 2024 The betterproto contributors
|
36
|
-
|