Skip to content
This repository was archived by the owner on Jun 9, 2025. It is now read-only.

Commit 4969568

Browse files
Simplify dataclass fields, new tests (#15)
* Simplify dataclass fields * Add pickling test * Add stream stream test * Add a few messages for the features test * Fix feature optional tests * More message for feature test
1 parent 5863013 commit 4969568

File tree

4 files changed

+181
-15
lines changed

4 files changed

+181
-15
lines changed

src/betterproto2_compiler/plugin/models.py

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
FieldDescriptorProto,
5454
FieldDescriptorProtoLabel,
5555
FieldDescriptorProtoType,
56+
FieldDescriptorProtoType as FieldType,
5657
FileDescriptorProto,
5758
MethodDescriptorProto,
5859
)
@@ -339,7 +340,7 @@ def is_map(proto_field_obj: FieldDescriptorProto, parent_message: DescriptorProt
339340
map_entry = f"{proto_field_obj.name.replace('_', '').lower()}entry"
340341
if message_type == map_entry:
341342
for nested in parent_message.nested_type: # parent message
342-
if nested.name.replace("_", "").lower() == map_entry and nested.options.map_entry:
343+
if nested.name.replace("_", "").lower() == map_entry and nested.options and nested.options.map_entry:
343344
return True
344345
return False
345346

@@ -382,7 +383,10 @@ def get_field_string(self) -> str:
382383
"""Construct string representation of this field as a field."""
383384
name = f"{self.py_name}"
384385
field_args = ", ".join(([""] + self.betterproto_field_args) if self.betterproto_field_args else [])
385-
betterproto_field_type = f"betterproto2.{self.field_type}_field({self.proto_obj.number}{field_args})"
386+
387+
betterproto_field_type = (
388+
f"betterproto2.field({self.proto_obj.number}, betterproto2.{str(self.field_type)}{field_args})"
389+
)
386390
if self.py_name in dir(builtins):
387391
self.parent.builtins_types.add(self.py_name)
388392
return f'{name}: "{self.annotation}" = {betterproto_field_type}'
@@ -396,9 +400,9 @@ def betterproto_field_args(self) -> list[str]:
396400
args.append("optional=True")
397401
if self.repeated:
398402
args.append("repeated=True")
399-
if self.field_type == "enum":
403+
if self.field_type == FieldType.TYPE_ENUM:
400404
t = self.py_type
401-
args.append(f"enum_default_value=lambda: {t}.try_value(0)")
405+
args.append(f"default_factory=lambda: {t}.try_value(0)")
402406
return args
403407

404408
@property
@@ -426,12 +430,13 @@ def repeated(self) -> bool:
426430

427431
@property
428432
def optional(self) -> bool:
429-
return self.proto_obj.proto3_optional or (self.field_type == "message" and not self.repeated)
433+
# TODO not for maps
434+
return self.proto_obj.proto3_optional or (self.field_type == FieldType.TYPE_MESSAGE and not self.repeated)
430435

431436
@property
432-
def field_type(self) -> str:
433-
"""String representation of proto field type."""
434-
return FieldDescriptorProtoType(self.proto_obj.type).name.lower().replace("type_", "")
437+
def field_type(self) -> FieldType:
438+
# TODO it should be possible to remove constructor
439+
return FieldType(self.proto_obj.type)
435440

436441
@property
437442
def packed(self) -> bool:
@@ -540,13 +545,17 @@ def ready(self) -> None:
540545

541546
raise ValueError("can't find enum")
542547

543-
@property
544-
def betterproto_field_args(self) -> list[str]:
545-
return [f"betterproto2.{self.proto_k_type}", f"betterproto2.{self.proto_v_type}"]
546-
547-
@property
548-
def field_type(self) -> str:
549-
return "map"
548+
def get_field_string(self) -> str:
549+
"""Construct string representation of this field as a field."""
550+
betterproto_field_type = (
551+
f"betterproto2.field({self.proto_obj.number}, "
552+
"betterproto2.TYPE_MAP, "
553+
f"map_types=(betterproto2.{self.proto_k_type}, "
554+
f"betterproto2.{self.proto_v_type}))"
555+
)
556+
if self.py_name in dir(builtins):
557+
self.parent.builtins_types.add(self.py_name)
558+
return f'{self.py_name}: "{self.annotation}" = {betterproto_field_type}'
550559

551560
@property
552561
def annotation(self) -> str:

tests/inputs/features/features.proto

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
syntax = "proto3";
2+
3+
import "google/protobuf/timestamp.proto";
4+
import "google/protobuf/duration.proto";
5+
import "google/protobuf/wrappers.proto";
6+
7+
package features;
8+
9+
message Bar {
10+
string name = 1;
11+
}
12+
13+
message Foo {
14+
string name = 1;
15+
Bar child = 2;
16+
}
17+
18+
enum Enum {
19+
ZERO = 0;
20+
ONE = 1;
21+
}
22+
23+
message EnumMsg {
24+
Enum enum = 1;
25+
}
26+
27+
message Newer {
28+
bool x = 1;
29+
int32 y = 2;
30+
string z = 3;
31+
}
32+
33+
message Older {
34+
bool x = 1;
35+
}
36+
37+
message IntMsg {
38+
int32 val = 1;
39+
}
40+
41+
message OneofMsg {
42+
oneof group1 {
43+
int32 x = 1;
44+
string y = 2;
45+
}
46+
oneof group2 {
47+
IntMsg a = 3;
48+
string b = 4;
49+
}
50+
}
51+
52+
message JsonCasingMsg {
53+
int32 pascal_case = 1;
54+
int32 camel_case = 2;
55+
int32 snake_case = 3;
56+
int32 kabob_case = 4;
57+
}
58+
59+
message OptionalBoolMsg {
60+
google.protobuf.BoolValue field = 1;
61+
}
62+
63+
message OptionalDatetimeMsg {
64+
google.protobuf.Timestamp field = 1;
65+
}
66+
67+
message Empty {}
68+
69+
message TimeMsg {
70+
google.protobuf.Timestamp timestamp = 1;
71+
google.protobuf.Duration duration = 2;
72+
}
73+
74+
message MsgA {
75+
int32 some_int = 1;
76+
double some_double = 2;
77+
string some_str = 3;
78+
bool some_bool = 4;
79+
}
80+
81+
message MsgB {
82+
int32 some_int = 1;
83+
double some_double = 2;
84+
string some_str = 3;
85+
bool some_bool = 4;
86+
int32 some_default_int = 5;
87+
double some_default_double = 6;
88+
string some_default_str = 7;
89+
bool some_default_bool = 8;
90+
}
91+
92+
message MsgC {
93+
oneof group1 {
94+
int32 int_field = 1;
95+
string string_field = 2;
96+
Empty empty_field = 3;
97+
}
98+
}
99+
100+
message MsgD {
101+
repeated google.protobuf.Timestamp timestamps = 1;
102+
}
103+
104+
message MsgE {
105+
bool bool_field = 1;
106+
optional int32 int_field = 2;
107+
}

tests/inputs/pickling/pickling.proto

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
syntax = "proto3";
2+
3+
package pickling;
4+
5+
import "google/protobuf/any.proto";
6+
import "google/protobuf/struct.proto";
7+
8+
9+
message Test {}
10+
11+
message Fe {
12+
string abc = 1;
13+
}
14+
15+
message Fi {
16+
string abc = 1;
17+
}
18+
19+
message Fo {
20+
string abc = 1;
21+
}
22+
23+
message NestedData {
24+
map<string, google.protobuf.Struct> struct_foo = 1;
25+
map<string, google.protobuf.Any> map_str_any_bar = 2;
26+
}
27+
28+
message Complex {
29+
string foo_str = 1;
30+
oneof grp {
31+
Fe fe = 3;
32+
Fi fi = 4;
33+
Fo fo = 5;
34+
}
35+
NestedData nested_data = 6;
36+
map<string, google.protobuf.Any> mapping = 7;
37+
}
38+
39+
message PickledMessage {
40+
bool foo = 1;
41+
int32 bar = 2;
42+
repeated string baz = 3;
43+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
syntax = "proto3";
2+
3+
package stream_stream;
4+
5+
message Message {
6+
string body = 1;
7+
}

0 commit comments

Comments
 (0)