betterproto2-compiler 0.0.3__py3-none-any.whl → 0.1.1__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 +11 -15
- betterproto2_compiler/lib/google/protobuf/__init__.py +0 -1
- betterproto2_compiler/lib/google/protobuf/compiler/__init__.py +229 -1
- betterproto2_compiler/plugin/compiler.py +5 -2
- betterproto2_compiler/plugin/models.py +83 -81
- betterproto2_compiler/plugin/module_validation.py +2 -7
- betterproto2_compiler/plugin/parser.py +30 -34
- betterproto2_compiler/plugin/typing_compiler.py +8 -12
- betterproto2_compiler/templates/header.py.j2 +2 -0
- betterproto2_compiler/templates/template.py.j2 +8 -1
- {betterproto2_compiler-0.0.3.dist-info → betterproto2_compiler-0.1.1.dist-info}/METADATA +3 -3
- betterproto2_compiler-0.1.1.dist-info/RECORD +26 -0
- {betterproto2_compiler-0.0.3.dist-info → betterproto2_compiler-0.1.1.dist-info}/WHEEL +1 -1
- betterproto2_compiler-0.1.1.dist-info/entry_points.txt +3 -0
- betterproto2_compiler/_types.py +0 -13
- betterproto2_compiler/enum.py +0 -180
- betterproto2_compiler/grpc/__init__.py +0 -0
- betterproto2_compiler/grpc/grpclib_client.py +0 -172
- betterproto2_compiler/grpc/grpclib_server.py +0 -32
- betterproto2_compiler/grpc/util/__init__.py +0 -0
- betterproto2_compiler/grpc/util/async_channel.py +0 -190
- betterproto2_compiler/lib/pydantic/__init__.py +0 -0
- betterproto2_compiler/lib/pydantic/google/__init__.py +0 -0
- betterproto2_compiler/lib/pydantic/google/protobuf/__init__.py +0 -2690
- betterproto2_compiler/lib/pydantic/google/protobuf/compiler/__init__.py +0 -209
- betterproto2_compiler/lib/std/__init__.py +0 -0
- betterproto2_compiler/lib/std/google/__init__.py +0 -0
- betterproto2_compiler/lib/std/google/protobuf/__init__.py +0 -2521
- betterproto2_compiler/lib/std/google/protobuf/compiler/__init__.py +0 -197
- betterproto2_compiler-0.0.3.dist-info/RECORD +0 -41
- betterproto2_compiler-0.0.3.dist-info/entry_points.txt +0 -3
- {betterproto2_compiler-0.0.3.dist-info → betterproto2_compiler-0.1.1.dist-info}/LICENSE.md +0 -0
@@ -31,36 +31,32 @@ reference to `A` to `B`'s `fields` attribute.
|
|
31
31
|
|
32
32
|
import builtins
|
33
33
|
import re
|
34
|
+
from collections.abc import Iterable, Iterator
|
34
35
|
from dataclasses import (
|
35
36
|
dataclass,
|
36
37
|
field,
|
37
38
|
)
|
38
39
|
from typing import (
|
39
|
-
Dict,
|
40
|
-
Iterable,
|
41
|
-
Iterator,
|
42
|
-
List,
|
43
|
-
Optional,
|
44
|
-
Set,
|
45
|
-
Type,
|
46
40
|
Union,
|
47
41
|
)
|
48
42
|
|
49
43
|
import betterproto2
|
50
|
-
|
51
|
-
from betterproto2_compiler.compile.naming import (
|
52
|
-
pythonize_class_name,
|
53
|
-
pythonize_field_name,
|
54
|
-
pythonize_method_name,
|
55
|
-
)
|
56
|
-
from betterproto2_compiler.lib.google.protobuf import (
|
44
|
+
from betterproto2.lib.google.protobuf import (
|
57
45
|
DescriptorProto,
|
58
46
|
EnumDescriptorProto,
|
59
47
|
FieldDescriptorProto,
|
60
48
|
FieldDescriptorProtoLabel,
|
61
49
|
FieldDescriptorProtoType,
|
50
|
+
FieldDescriptorProtoType as FieldType,
|
62
51
|
FileDescriptorProto,
|
63
52
|
MethodDescriptorProto,
|
53
|
+
OneofDescriptorProto,
|
54
|
+
)
|
55
|
+
|
56
|
+
from betterproto2_compiler.compile.naming import (
|
57
|
+
pythonize_class_name,
|
58
|
+
pythonize_field_name,
|
59
|
+
pythonize_method_name,
|
64
60
|
)
|
65
61
|
from betterproto2_compiler.lib.google.protobuf.compiler import CodeGeneratorRequest
|
66
62
|
|
@@ -122,31 +118,9 @@ PROTO_PACKED_TYPES = (
|
|
122
118
|
)
|
123
119
|
|
124
120
|
|
125
|
-
# TODO patch again to make field optional
|
126
|
-
# def monkey_patch_oneof_index():
|
127
|
-
# """
|
128
|
-
# The compiler message types are written for proto2, but we read them as proto3.
|
129
|
-
# For this to work in the case of the oneof_index fields, which depend on being able
|
130
|
-
# to tell whether they were set, we have to treat them as oneof fields. This method
|
131
|
-
# monkey patches the generated classes after the fact to force this behaviour.
|
132
|
-
# """
|
133
|
-
# object.__setattr__(
|
134
|
-
# FieldDescriptorProto.__dataclass_fields__["oneof_index"].metadata[
|
135
|
-
# "betterproto"
|
136
|
-
# ],
|
137
|
-
# "group",
|
138
|
-
# "oneof_index",
|
139
|
-
# )
|
140
|
-
# object.__setattr__(
|
141
|
-
# Field.__dataclass_fields__["oneof_index"].metadata["betterproto"],
|
142
|
-
# "group",
|
143
|
-
# "oneof_index",
|
144
|
-
# )
|
145
|
-
|
146
|
-
|
147
121
|
def get_comment(
|
148
122
|
proto_file: "FileDescriptorProto",
|
149
|
-
path:
|
123
|
+
path: list[int],
|
150
124
|
) -> str:
|
151
125
|
for sci_loc in proto_file.source_code_info.location:
|
152
126
|
if list(sci_loc.path) == path:
|
@@ -182,10 +156,10 @@ class ProtoContentBase:
|
|
182
156
|
|
183
157
|
source_file: FileDescriptorProto
|
184
158
|
typing_compiler: TypingCompiler
|
185
|
-
path:
|
159
|
+
path: list[int]
|
186
160
|
parent: Union["betterproto2.Message", "OutputTemplate"]
|
187
161
|
|
188
|
-
__dataclass_fields__:
|
162
|
+
__dataclass_fields__: dict[str, object]
|
189
163
|
|
190
164
|
def __post_init__(self) -> None:
|
191
165
|
"""Checks that no fake default fields were left as placeholders."""
|
@@ -225,10 +199,10 @@ class ProtoContentBase:
|
|
225
199
|
@dataclass
|
226
200
|
class PluginRequestCompiler:
|
227
201
|
plugin_request_obj: CodeGeneratorRequest
|
228
|
-
output_packages:
|
202
|
+
output_packages: dict[str, "OutputTemplate"] = field(default_factory=dict)
|
229
203
|
|
230
204
|
@property
|
231
|
-
def all_messages(self) ->
|
205
|
+
def all_messages(self) -> list["MessageCompiler"]:
|
232
206
|
"""All of the messages in this request.
|
233
207
|
|
234
208
|
Returns
|
@@ -250,11 +224,11 @@ class OutputTemplate:
|
|
250
224
|
|
251
225
|
parent_request: PluginRequestCompiler
|
252
226
|
package_proto_obj: FileDescriptorProto
|
253
|
-
input_files:
|
254
|
-
imports_end:
|
255
|
-
messages:
|
256
|
-
enums:
|
257
|
-
services:
|
227
|
+
input_files: list[str] = field(default_factory=list)
|
228
|
+
imports_end: set[str] = field(default_factory=set)
|
229
|
+
messages: dict[str, "MessageCompiler"] = field(default_factory=dict)
|
230
|
+
enums: dict[str, "EnumDefinitionCompiler"] = field(default_factory=dict)
|
231
|
+
services: dict[str, "ServiceCompiler"] = field(default_factory=dict)
|
258
232
|
pydantic_dataclasses: bool = False
|
259
233
|
output: bool = True
|
260
234
|
typing_compiler: TypingCompiler = field(default_factory=DirectImportTypingCompiler)
|
@@ -290,9 +264,10 @@ class MessageCompiler(ProtoContentBase):
|
|
290
264
|
typing_compiler: TypingCompiler
|
291
265
|
parent: Union["MessageCompiler", OutputTemplate] = PLACEHOLDER
|
292
266
|
proto_obj: DescriptorProto = PLACEHOLDER
|
293
|
-
path:
|
294
|
-
fields:
|
295
|
-
|
267
|
+
path: list[int] = PLACEHOLDER
|
268
|
+
fields: list[Union["FieldCompiler", "MessageCompiler"]] = field(default_factory=list)
|
269
|
+
oneofs: list["OneofCompiler"] = field(default_factory=list)
|
270
|
+
builtins_types: set[str] = field(default_factory=set)
|
296
271
|
|
297
272
|
def __post_init__(self) -> None:
|
298
273
|
# Add message to output file
|
@@ -328,11 +303,9 @@ class MessageCompiler(ProtoContentBase):
|
|
328
303
|
@property
|
329
304
|
def has_message_field(self) -> bool:
|
330
305
|
return any(
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
if isinstance(field.proto_obj, FieldDescriptorProto)
|
335
|
-
)
|
306
|
+
field.proto_obj.type in PROTO_MESSAGE_TYPES
|
307
|
+
for field in self.fields
|
308
|
+
if isinstance(field.proto_obj, FieldDescriptorProto)
|
336
309
|
)
|
337
310
|
|
338
311
|
|
@@ -347,7 +320,7 @@ def is_map(proto_field_obj: FieldDescriptorProto, parent_message: DescriptorProt
|
|
347
320
|
map_entry = f"{proto_field_obj.name.replace('_', '').lower()}entry"
|
348
321
|
if message_type == map_entry:
|
349
322
|
for nested in parent_message.nested_type: # parent message
|
350
|
-
if nested.name.replace("_", "").lower() == map_entry and nested.options.map_entry:
|
323
|
+
if nested.name.replace("_", "").lower() == map_entry and nested.options and nested.options.map_entry:
|
351
324
|
return True
|
352
325
|
return False
|
353
326
|
|
@@ -374,8 +347,8 @@ def is_oneof(proto_field_obj: FieldDescriptorProto) -> bool:
|
|
374
347
|
class FieldCompiler(ProtoContentBase):
|
375
348
|
source_file: FileDescriptorProto
|
376
349
|
typing_compiler: TypingCompiler
|
377
|
-
path:
|
378
|
-
builtins_types:
|
350
|
+
path: list[int] = PLACEHOLDER
|
351
|
+
builtins_types: set[str] = field(default_factory=set)
|
379
352
|
|
380
353
|
parent: MessageCompiler = PLACEHOLDER
|
381
354
|
proto_obj: FieldDescriptorProto = PLACEHOLDER
|
@@ -390,13 +363,16 @@ class FieldCompiler(ProtoContentBase):
|
|
390
363
|
"""Construct string representation of this field as a field."""
|
391
364
|
name = f"{self.py_name}"
|
392
365
|
field_args = ", ".join(([""] + self.betterproto_field_args) if self.betterproto_field_args else [])
|
393
|
-
|
366
|
+
|
367
|
+
betterproto_field_type = (
|
368
|
+
f"betterproto2.field({self.proto_obj.number}, betterproto2.{str(self.field_type)}{field_args})"
|
369
|
+
)
|
394
370
|
if self.py_name in dir(builtins):
|
395
371
|
self.parent.builtins_types.add(self.py_name)
|
396
372
|
return f'{name}: "{self.annotation}" = {betterproto_field_type}'
|
397
373
|
|
398
374
|
@property
|
399
|
-
def betterproto_field_args(self) ->
|
375
|
+
def betterproto_field_args(self) -> list[str]:
|
400
376
|
args = []
|
401
377
|
if self.field_wraps:
|
402
378
|
args.append(f"wraps={self.field_wraps}")
|
@@ -404,9 +380,9 @@ class FieldCompiler(ProtoContentBase):
|
|
404
380
|
args.append("optional=True")
|
405
381
|
if self.repeated:
|
406
382
|
args.append("repeated=True")
|
407
|
-
if self.field_type ==
|
383
|
+
if self.field_type == FieldType.TYPE_ENUM:
|
408
384
|
t = self.py_type
|
409
|
-
args.append(f"
|
385
|
+
args.append(f"default_factory=lambda: {t}.try_value(0)")
|
410
386
|
return args
|
411
387
|
|
412
388
|
@property
|
@@ -416,7 +392,7 @@ class FieldCompiler(ProtoContentBase):
|
|
416
392
|
)
|
417
393
|
|
418
394
|
@property
|
419
|
-
def field_wraps(self) ->
|
395
|
+
def field_wraps(self) -> str | None:
|
420
396
|
"""Returns betterproto wrapped field type or None."""
|
421
397
|
match_wrapper = re.match(r"\.google\.protobuf\.(.+)Value$", self.proto_obj.type_name)
|
422
398
|
if match_wrapper:
|
@@ -428,17 +404,19 @@ class FieldCompiler(ProtoContentBase):
|
|
428
404
|
@property
|
429
405
|
def repeated(self) -> bool:
|
430
406
|
return self.proto_obj.label == FieldDescriptorProtoLabel.LABEL_REPEATED and not is_map(
|
431
|
-
self.proto_obj,
|
407
|
+
self.proto_obj,
|
408
|
+
self.parent,
|
432
409
|
)
|
433
410
|
|
434
411
|
@property
|
435
412
|
def optional(self) -> bool:
|
436
|
-
|
413
|
+
# TODO not for maps
|
414
|
+
return self.proto_obj.proto3_optional or (self.field_type == FieldType.TYPE_MESSAGE and not self.repeated)
|
437
415
|
|
438
416
|
@property
|
439
|
-
def field_type(self) ->
|
440
|
-
|
441
|
-
return
|
417
|
+
def field_type(self) -> FieldType:
|
418
|
+
# TODO it should be possible to remove constructor
|
419
|
+
return FieldType(self.proto_obj.type)
|
442
420
|
|
443
421
|
@property
|
444
422
|
def packed(self) -> bool:
|
@@ -500,7 +478,7 @@ class OneOfFieldCompiler(FieldCompiler):
|
|
500
478
|
return True
|
501
479
|
|
502
480
|
@property
|
503
|
-
def betterproto_field_args(self) ->
|
481
|
+
def betterproto_field_args(self) -> list[str]:
|
504
482
|
args = super().betterproto_field_args
|
505
483
|
group = self.parent.proto_obj.oneof_decl[self.proto_obj.oneof_index].name
|
506
484
|
args.append(f'group="{group}"')
|
@@ -509,8 +487,8 @@ class OneOfFieldCompiler(FieldCompiler):
|
|
509
487
|
|
510
488
|
@dataclass
|
511
489
|
class MapEntryCompiler(FieldCompiler):
|
512
|
-
py_k_type:
|
513
|
-
py_v_type:
|
490
|
+
py_k_type: type | None = None
|
491
|
+
py_v_type: type | None = None
|
514
492
|
proto_k_type: str = ""
|
515
493
|
proto_v_type: str = ""
|
516
494
|
|
@@ -547,13 +525,17 @@ class MapEntryCompiler(FieldCompiler):
|
|
547
525
|
|
548
526
|
raise ValueError("can't find enum")
|
549
527
|
|
550
|
-
|
551
|
-
|
552
|
-
|
553
|
-
|
554
|
-
|
555
|
-
|
556
|
-
|
528
|
+
def get_field_string(self) -> str:
|
529
|
+
"""Construct string representation of this field as a field."""
|
530
|
+
betterproto_field_type = (
|
531
|
+
f"betterproto2.field({self.proto_obj.number}, "
|
532
|
+
"betterproto2.TYPE_MAP, "
|
533
|
+
f"map_types=(betterproto2.{self.proto_k_type}, "
|
534
|
+
f"betterproto2.{self.proto_v_type}))"
|
535
|
+
)
|
536
|
+
if self.py_name in dir(builtins):
|
537
|
+
self.parent.builtins_types.add(self.py_name)
|
538
|
+
return f'{self.py_name}: "{self.annotation}" = {betterproto_field_type}'
|
557
539
|
|
558
540
|
@property
|
559
541
|
def annotation(self) -> str:
|
@@ -564,12 +546,32 @@ class MapEntryCompiler(FieldCompiler):
|
|
564
546
|
return False # maps cannot be repeated
|
565
547
|
|
566
548
|
|
549
|
+
@dataclass
|
550
|
+
class OneofCompiler(ProtoContentBase):
|
551
|
+
source_file: FileDescriptorProto
|
552
|
+
typing_compiler: TypingCompiler
|
553
|
+
path: list[int] = PLACEHOLDER
|
554
|
+
|
555
|
+
parent: MessageCompiler = PLACEHOLDER
|
556
|
+
proto_obj: OneofDescriptorProto = PLACEHOLDER
|
557
|
+
|
558
|
+
def __post_init__(self) -> None:
|
559
|
+
# Add oneof to message
|
560
|
+
if isinstance(self.parent, MessageCompiler): # TODO why?
|
561
|
+
self.parent.oneofs.append(self)
|
562
|
+
super().__post_init__()
|
563
|
+
|
564
|
+
@property
|
565
|
+
def name(self) -> str:
|
566
|
+
return self.proto_obj.name
|
567
|
+
|
568
|
+
|
567
569
|
@dataclass
|
568
570
|
class EnumDefinitionCompiler(MessageCompiler):
|
569
571
|
"""Representation of a proto Enum definition."""
|
570
572
|
|
571
573
|
proto_obj: EnumDescriptorProto = PLACEHOLDER
|
572
|
-
entries:
|
574
|
+
entries: list["EnumDefinitionCompiler.EnumEntry"] = PLACEHOLDER
|
573
575
|
|
574
576
|
@dataclass(unsafe_hash=True)
|
575
577
|
class EnumEntry:
|
@@ -597,8 +599,8 @@ class ServiceCompiler(ProtoContentBase):
|
|
597
599
|
source_file: FileDescriptorProto
|
598
600
|
parent: OutputTemplate = PLACEHOLDER
|
599
601
|
proto_obj: DescriptorProto = PLACEHOLDER
|
600
|
-
path:
|
601
|
-
methods:
|
602
|
+
path: list[int] = PLACEHOLDER
|
603
|
+
methods: list["ServiceMethodCompiler"] = field(default_factory=list)
|
602
604
|
|
603
605
|
def __post_init__(self) -> None:
|
604
606
|
# Add service to output file
|
@@ -619,7 +621,7 @@ class ServiceMethodCompiler(ProtoContentBase):
|
|
619
621
|
source_file: FileDescriptorProto
|
620
622
|
parent: ServiceCompiler
|
621
623
|
proto_obj: MethodDescriptorProto
|
622
|
-
path:
|
624
|
+
path: list[int] = PLACEHOLDER
|
623
625
|
|
624
626
|
def __post_init__(self) -> None:
|
625
627
|
# Add method to service
|
@@ -1,15 +1,10 @@
|
|
1
1
|
import re
|
2
2
|
from collections import defaultdict
|
3
|
+
from collections.abc import Iterator
|
3
4
|
from dataclasses import (
|
4
5
|
dataclass,
|
5
6
|
field,
|
6
7
|
)
|
7
|
-
from typing import (
|
8
|
-
Dict,
|
9
|
-
Iterator,
|
10
|
-
List,
|
11
|
-
Tuple,
|
12
|
-
)
|
13
8
|
|
14
9
|
|
15
10
|
@dataclass
|
@@ -17,7 +12,7 @@ class ModuleValidator:
|
|
17
12
|
line_iterator: Iterator[str]
|
18
13
|
line_number: int = field(init=False, default=0)
|
19
14
|
|
20
|
-
collisions:
|
15
|
+
collisions: dict[str, list[tuple[int, str]]] = field(init=False, default_factory=lambda: defaultdict(list))
|
21
16
|
|
22
17
|
def add_import(self, imp: str, number: int, full_line: str):
|
23
18
|
"""
|
@@ -1,20 +1,14 @@
|
|
1
1
|
import pathlib
|
2
2
|
import sys
|
3
|
-
from
|
4
|
-
Generator,
|
5
|
-
List,
|
6
|
-
Set,
|
7
|
-
Tuple,
|
8
|
-
Union,
|
9
|
-
)
|
3
|
+
from collections.abc import Generator
|
10
4
|
|
11
|
-
from
|
5
|
+
from betterproto2.lib.google.protobuf import (
|
12
6
|
DescriptorProto,
|
13
7
|
EnumDescriptorProto,
|
14
|
-
FieldDescriptorProto,
|
15
8
|
FileDescriptorProto,
|
16
9
|
ServiceDescriptorProto,
|
17
10
|
)
|
11
|
+
|
18
12
|
from betterproto2_compiler.lib.google.protobuf.compiler import (
|
19
13
|
CodeGeneratorRequest,
|
20
14
|
CodeGeneratorResponse,
|
@@ -28,6 +22,7 @@ from .models import (
|
|
28
22
|
FieldCompiler,
|
29
23
|
MapEntryCompiler,
|
30
24
|
MessageCompiler,
|
25
|
+
OneofCompiler,
|
31
26
|
OneOfFieldCompiler,
|
32
27
|
OutputTemplate,
|
33
28
|
PluginRequestCompiler,
|
@@ -45,13 +40,13 @@ from .typing_compiler import (
|
|
45
40
|
|
46
41
|
def traverse(
|
47
42
|
proto_file: FileDescriptorProto,
|
48
|
-
) -> Generator[
|
43
|
+
) -> Generator[tuple[EnumDescriptorProto | DescriptorProto, list[int]], None, None]:
|
49
44
|
# Todo: Keep information about nested hierarchy
|
50
45
|
def _traverse(
|
51
|
-
path:
|
52
|
-
items:
|
46
|
+
path: list[int],
|
47
|
+
items: list[EnumDescriptorProto] | list[DescriptorProto],
|
53
48
|
prefix: str = "",
|
54
|
-
) -> Generator[
|
49
|
+
) -> Generator[tuple[EnumDescriptorProto | DescriptorProto, list[int]], None, None]:
|
55
50
|
for i, item in enumerate(items):
|
56
51
|
# Adjust the name since we flatten the hierarchy.
|
57
52
|
# Todo: don't change the name, but include full name in returned tuple
|
@@ -82,7 +77,8 @@ def generate_code(request: CodeGeneratorRequest) -> CodeGeneratorResponse:
|
|
82
77
|
if output_package_name not in request_data.output_packages:
|
83
78
|
# Create a new output if there is no output for this package
|
84
79
|
request_data.output_packages[output_package_name] = OutputTemplate(
|
85
|
-
parent_request=request_data,
|
80
|
+
parent_request=request_data,
|
81
|
+
package_proto_obj=proto_file,
|
86
82
|
)
|
87
83
|
# Add this input file to the output corresponding to this package
|
88
84
|
request_data.output_packages[output_package_name].input_files.append(proto_file)
|
@@ -144,7 +140,7 @@ def generate_code(request: CodeGeneratorRequest) -> CodeGeneratorResponse:
|
|
144
140
|
service.ready()
|
145
141
|
|
146
142
|
# Generate output files
|
147
|
-
output_paths:
|
143
|
+
output_paths: set[pathlib.Path] = set()
|
148
144
|
for output_package_name, output_package in request_data.output_packages.items():
|
149
145
|
if not output_package.output:
|
150
146
|
continue
|
@@ -158,7 +154,7 @@ def generate_code(request: CodeGeneratorRequest) -> CodeGeneratorResponse:
|
|
158
154
|
name=str(output_path),
|
159
155
|
# Render and then format the output file
|
160
156
|
content=outputfile_compiler(output_file=output_package),
|
161
|
-
)
|
157
|
+
),
|
162
158
|
)
|
163
159
|
|
164
160
|
# Make each output directory a package with __init__ file
|
@@ -178,25 +174,9 @@ def generate_code(request: CodeGeneratorRequest) -> CodeGeneratorResponse:
|
|
178
174
|
return response
|
179
175
|
|
180
176
|
|
181
|
-
def _make_one_of_field_compiler(
|
182
|
-
output_package: OutputTemplate,
|
183
|
-
source_file: "FileDescriptorProto",
|
184
|
-
parent: MessageCompiler,
|
185
|
-
proto_obj: "FieldDescriptorProto",
|
186
|
-
path: List[int],
|
187
|
-
) -> FieldCompiler:
|
188
|
-
return OneOfFieldCompiler(
|
189
|
-
source_file=source_file,
|
190
|
-
parent=parent,
|
191
|
-
proto_obj=proto_obj,
|
192
|
-
path=path,
|
193
|
-
typing_compiler=output_package.typing_compiler,
|
194
|
-
)
|
195
|
-
|
196
|
-
|
197
177
|
def read_protobuf_type(
|
198
178
|
item: DescriptorProto,
|
199
|
-
path:
|
179
|
+
path: list[int],
|
200
180
|
source_file: "FileDescriptorProto",
|
201
181
|
output_package: OutputTemplate,
|
202
182
|
) -> None:
|
@@ -222,7 +202,13 @@ def read_protobuf_type(
|
|
222
202
|
typing_compiler=output_package.typing_compiler,
|
223
203
|
)
|
224
204
|
elif is_oneof(field):
|
225
|
-
|
205
|
+
OneOfFieldCompiler(
|
206
|
+
source_file=source_file,
|
207
|
+
parent=message_data,
|
208
|
+
proto_obj=field,
|
209
|
+
path=path + [2, index],
|
210
|
+
typing_compiler=output_package.typing_compiler,
|
211
|
+
)
|
226
212
|
else:
|
227
213
|
FieldCompiler(
|
228
214
|
source_file=source_file,
|
@@ -231,6 +217,16 @@ def read_protobuf_type(
|
|
231
217
|
path=path + [2, index],
|
232
218
|
typing_compiler=output_package.typing_compiler,
|
233
219
|
)
|
220
|
+
|
221
|
+
for index, oneof in enumerate(item.oneof_decl):
|
222
|
+
OneofCompiler(
|
223
|
+
source_file=source_file,
|
224
|
+
typing_compiler=output_package.typing_compiler,
|
225
|
+
path=path + [8, index],
|
226
|
+
parent=message_data,
|
227
|
+
proto_obj=oneof,
|
228
|
+
)
|
229
|
+
|
234
230
|
elif isinstance(item, EnumDescriptorProto):
|
235
231
|
# Enum
|
236
232
|
EnumDefinitionCompiler(
|
@@ -1,15 +1,11 @@
|
|
1
1
|
import abc
|
2
|
+
import builtins
|
2
3
|
from collections import defaultdict
|
4
|
+
from collections.abc import Iterator
|
3
5
|
from dataclasses import (
|
4
6
|
dataclass,
|
5
7
|
field,
|
6
8
|
)
|
7
|
-
from typing import (
|
8
|
-
Dict,
|
9
|
-
Iterator,
|
10
|
-
Optional,
|
11
|
-
Set,
|
12
|
-
)
|
13
9
|
|
14
10
|
|
15
11
|
class TypingCompiler(metaclass=abc.ABCMeta):
|
@@ -42,7 +38,7 @@ class TypingCompiler(metaclass=abc.ABCMeta):
|
|
42
38
|
raise NotImplementedError
|
43
39
|
|
44
40
|
@abc.abstractmethod
|
45
|
-
def imports(self) ->
|
41
|
+
def imports(self) -> builtins.dict[str, set[str] | None]:
|
46
42
|
"""
|
47
43
|
Returns either the direct import as a key with none as value, or a set of
|
48
44
|
values to import from the key.
|
@@ -63,7 +59,7 @@ class TypingCompiler(metaclass=abc.ABCMeta):
|
|
63
59
|
|
64
60
|
@dataclass
|
65
61
|
class DirectImportTypingCompiler(TypingCompiler):
|
66
|
-
_imports:
|
62
|
+
_imports: dict[str, set[str]] = field(default_factory=lambda: defaultdict(set))
|
67
63
|
|
68
64
|
def optional(self, type_: str) -> str:
|
69
65
|
self._imports["typing"].add("Optional")
|
@@ -93,7 +89,7 @@ class DirectImportTypingCompiler(TypingCompiler):
|
|
93
89
|
self._imports["typing"].add("AsyncIterator")
|
94
90
|
return f"AsyncIterator[{type_}]"
|
95
91
|
|
96
|
-
def imports(self) ->
|
92
|
+
def imports(self) -> builtins.dict[str, set[str] | None]:
|
97
93
|
return {k: v if v else None for k, v in self._imports.items()}
|
98
94
|
|
99
95
|
|
@@ -129,7 +125,7 @@ class TypingImportTypingCompiler(TypingCompiler):
|
|
129
125
|
self._imported = True
|
130
126
|
return f"typing.AsyncIterator[{type_}]"
|
131
127
|
|
132
|
-
def imports(self) ->
|
128
|
+
def imports(self) -> builtins.dict[str, set[str] | None]:
|
133
129
|
if self._imported:
|
134
130
|
return {"typing": None}
|
135
131
|
return {}
|
@@ -137,7 +133,7 @@ class TypingImportTypingCompiler(TypingCompiler):
|
|
137
133
|
|
138
134
|
@dataclass
|
139
135
|
class NoTyping310TypingCompiler(TypingCompiler):
|
140
|
-
_imports:
|
136
|
+
_imports: dict[str, set[str]] = field(default_factory=lambda: defaultdict(set))
|
141
137
|
|
142
138
|
def optional(self, type_: str) -> str:
|
143
139
|
return f"{type_} | None"
|
@@ -163,5 +159,5 @@ class NoTyping310TypingCompiler(TypingCompiler):
|
|
163
159
|
self._imports["collections.abc"].add("AsyncIterator")
|
164
160
|
return f"AsyncIterator[{type_}]"
|
165
161
|
|
166
|
-
def imports(self) ->
|
162
|
+
def imports(self) -> builtins.dict[str, set[str] | None]:
|
167
163
|
return {k: v if v else None for k, v in self._imports.items()}
|
@@ -32,9 +32,16 @@ class {{ enum.py_name }}(betterproto2.Enum):
|
|
32
32
|
@dataclass(eq=False, repr=False)
|
33
33
|
{% endif %}
|
34
34
|
class {{ message.py_name }}(betterproto2.Message):
|
35
|
-
{% if message.comment %}
|
35
|
+
{% if message.comment or message.oneofs %}
|
36
36
|
"""
|
37
37
|
{{ message.comment | indent(4) }}
|
38
|
+
|
39
|
+
{% if message.oneofs %}
|
40
|
+
Oneofs:
|
41
|
+
{% for oneof in message.oneofs %}
|
42
|
+
- {{ oneof.name }}: {{ oneof.comment | indent(12) }}
|
43
|
+
{% endfor %}
|
44
|
+
{% endif %}
|
38
45
|
"""
|
39
46
|
{% endif %}
|
40
47
|
|
@@ -1,6 +1,6 @@
|
|
1
|
-
Metadata-Version: 2.
|
1
|
+
Metadata-Version: 2.3
|
2
2
|
Name: betterproto2_compiler
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.1.1
|
4
4
|
Summary: Compiler for betterproto2
|
5
5
|
Home-page: https://github.com/betterproto/python-betterproto2-compiler
|
6
6
|
License: MIT
|
@@ -14,7 +14,7 @@ Classifier: Programming Language :: Python :: 3.10
|
|
14
14
|
Classifier: Programming Language :: Python :: 3.11
|
15
15
|
Classifier: Programming Language :: Python :: 3.12
|
16
16
|
Classifier: Programming Language :: Python :: 3.13
|
17
|
-
Requires-Dist: betterproto2 (
|
17
|
+
Requires-Dist: betterproto2 (>=0.1.1,<0.2.0)
|
18
18
|
Requires-Dist: grpclib (>=0.4.1,<0.5.0)
|
19
19
|
Requires-Dist: jinja2 (>=3.0.3)
|
20
20
|
Requires-Dist: ruff (>=0.7.4,<0.8.0)
|
@@ -0,0 +1,26 @@
|
|
1
|
+
betterproto2_compiler/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
2
|
+
betterproto2_compiler/casing.py,sha256=bMdI4W0hfYh6kV-DQIqFEjSfGYEqUtPciAzP64z5HLQ,3587
|
3
|
+
betterproto2_compiler/compile/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
4
|
+
betterproto2_compiler/compile/importing.py,sha256=JgvVFlWiA8zeb8L_pcAbxH61tDGNNNx18kVXRrfmIlo,7400
|
5
|
+
betterproto2_compiler/compile/naming.py,sha256=zf0VOmNojzyv33upOGelGxjZTEDE8JULEEED5_3inHg,562
|
6
|
+
betterproto2_compiler/lib/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
7
|
+
betterproto2_compiler/lib/google/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
8
|
+
betterproto2_compiler/lib/google/protobuf/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
9
|
+
betterproto2_compiler/lib/google/protobuf/compiler/__init__.py,sha256=CX9UOXUUZD8GpeS7CWb1JTJoPIKi2e6lH7BCw6RJ8uI,9285
|
10
|
+
betterproto2_compiler/plugin/__init__.py,sha256=L3pW0b4CvkM5x53x_sYt1kYiSFPO0_vaeH6EQPq9FAM,43
|
11
|
+
betterproto2_compiler/plugin/__main__.py,sha256=vBQ82334kX06ImDbFlPFgiBRiLIinwNk3z8Khs6hd74,31
|
12
|
+
betterproto2_compiler/plugin/compiler.py,sha256=jICLI4-5rAOkWQI1v5j7JqIvoao-ZM9szMuq0OBRteA,2138
|
13
|
+
betterproto2_compiler/plugin/main.py,sha256=Q9PmcJqXuYYFe51l7AqHVzJrHqi2LWCUu80CZSQOOwk,1469
|
14
|
+
betterproto2_compiler/plugin/models.py,sha256=RfHRt8Iw_v9q-Rpi58VNHkcDfED5TwHWur2O4wr1Z8Q,24482
|
15
|
+
betterproto2_compiler/plugin/module_validation.py,sha256=RdPFwdmkbD6NKADaHC5eaPix_pz-yGxHvYJj8Ev48fA,4822
|
16
|
+
betterproto2_compiler/plugin/parser.py,sha256=AZihuRp7XCTKG04YNJcthR9fmarllfkPSfLS0l9exLI,9668
|
17
|
+
betterproto2_compiler/plugin/plugin.bat,sha256=lfLT1WguAXqyerLLsRL6BfHA0RqUE6QG79v-1BYVSpI,48
|
18
|
+
betterproto2_compiler/plugin/typing_compiler.py,sha256=IK6m4ggHXK7HL98Ed_WjvQ_yeWfIpf_fIBZ9SA8UcyM,4873
|
19
|
+
betterproto2_compiler/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
20
|
+
betterproto2_compiler/templates/header.py.j2,sha256=nxqsengMcM_IRqQYNVntPQ0gUFUPCy_1P1mcoLvbDos,1464
|
21
|
+
betterproto2_compiler/templates/template.py.j2,sha256=R_9a5IvX2wU6yKzcdjj-uMb09askExrShu4UX2ayQO8,8911
|
22
|
+
betterproto2_compiler-0.1.1.dist-info/LICENSE.md,sha256=Pgl2pReU-2yw2miGeQ55UFlyzqAZ_EpYVyZ2nWjwRv4,1121
|
23
|
+
betterproto2_compiler-0.1.1.dist-info/METADATA,sha256=G9d9cnAsNG8x00x3wWxDDcWZdXOaZyaitkblivnE8lw,1170
|
24
|
+
betterproto2_compiler-0.1.1.dist-info/WHEEL,sha256=RaoafKOydTQ7I_I3JTrPCg6kUmTgtm4BornzOqyEfJ8,88
|
25
|
+
betterproto2_compiler-0.1.1.dist-info/entry_points.txt,sha256=re3Qg8lLljbVobeeKH2f1FVQZ114wfZkGv3zCZTD8Ok,84
|
26
|
+
betterproto2_compiler-0.1.1.dist-info/RECORD,,
|
betterproto2_compiler/_types.py
DELETED
@@ -1,13 +0,0 @@
|
|
1
|
-
from typing import (
|
2
|
-
TYPE_CHECKING,
|
3
|
-
TypeVar,
|
4
|
-
)
|
5
|
-
|
6
|
-
if TYPE_CHECKING:
|
7
|
-
from grpclib._typing import IProtoMessage
|
8
|
-
|
9
|
-
from . import Message
|
10
|
-
|
11
|
-
# Bound type variable to allow methods to return `self` of subclasses
|
12
|
-
T = TypeVar("T", bound="Message")
|
13
|
-
ST = TypeVar("ST", bound="IProtoMessage")
|