From 404b23ff5b966a2f0a16eb79aef43c26e590ed79 Mon Sep 17 00:00:00 2001 From: Adrien Vannson Date: Thu, 26 Dec 2024 13:29:14 +0100 Subject: [PATCH 1/6] Simplify dataclass fields --- src/betterproto2_compiler/plugin/models.py | 39 +++++++++++++--------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/src/betterproto2_compiler/plugin/models.py b/src/betterproto2_compiler/plugin/models.py index 1e44b307..d71f75bd 100644 --- a/src/betterproto2_compiler/plugin/models.py +++ b/src/betterproto2_compiler/plugin/models.py @@ -53,6 +53,7 @@ FieldDescriptorProto, FieldDescriptorProtoLabel, FieldDescriptorProtoType, + FieldDescriptorProtoType as FieldType, FileDescriptorProto, MethodDescriptorProto, ) @@ -339,7 +340,7 @@ def is_map(proto_field_obj: FieldDescriptorProto, parent_message: DescriptorProt map_entry = f"{proto_field_obj.name.replace('_', '').lower()}entry" if message_type == map_entry: for nested in parent_message.nested_type: # parent message - if nested.name.replace("_", "").lower() == map_entry and nested.options.map_entry: + if nested.name.replace("_", "").lower() == map_entry and nested.options and nested.options.map_entry: return True return False @@ -382,7 +383,10 @@ def get_field_string(self) -> str: """Construct string representation of this field as a field.""" name = f"{self.py_name}" field_args = ", ".join(([""] + self.betterproto_field_args) if self.betterproto_field_args else []) - betterproto_field_type = f"betterproto2.{self.field_type}_field({self.proto_obj.number}{field_args})" + + betterproto_field_type = ( + f"betterproto2.field({self.proto_obj.number}, betterproto2.{str(self.field_type)}{field_args})" + ) if self.py_name in dir(builtins): self.parent.builtins_types.add(self.py_name) return f'{name}: "{self.annotation}" = {betterproto_field_type}' @@ -396,9 +400,9 @@ def betterproto_field_args(self) -> list[str]: args.append("optional=True") if self.repeated: args.append("repeated=True") - if self.field_type == "enum": + if self.field_type == FieldType.TYPE_ENUM: t = self.py_type - args.append(f"enum_default_value=lambda: {t}.try_value(0)") + args.append(f"default_factory=lambda: {t}.try_value(0)") return args @property @@ -426,12 +430,13 @@ def repeated(self) -> bool: @property def optional(self) -> bool: - return self.proto_obj.proto3_optional or (self.field_type == "message" and not self.repeated) + # TODO not for maps + return self.proto_obj.proto3_optional or (self.field_type == FieldType.TYPE_MESSAGE and not self.repeated) @property - def field_type(self) -> str: - """String representation of proto field type.""" - return FieldDescriptorProtoType(self.proto_obj.type).name.lower().replace("type_", "") + def field_type(self) -> FieldType: + # TODO it should be possible to remove constructor + return FieldType(self.proto_obj.type) @property def packed(self) -> bool: @@ -540,13 +545,17 @@ def ready(self) -> None: raise ValueError("can't find enum") - @property - def betterproto_field_args(self) -> list[str]: - return [f"betterproto2.{self.proto_k_type}", f"betterproto2.{self.proto_v_type}"] - - @property - def field_type(self) -> str: - return "map" + def get_field_string(self) -> str: + """Construct string representation of this field as a field.""" + betterproto_field_type = ( + f"betterproto2.field({self.proto_obj.number}, " + "betterproto2.TYPE_MAP, " + f"map_types=(betterproto2.{self.proto_k_type}, " + f"betterproto2.{self.proto_v_type}))" + ) + if self.py_name in dir(builtins): + self.parent.builtins_types.add(self.py_name) + return f'{self.py_name}: "{self.annotation}" = {betterproto_field_type}' @property def annotation(self) -> str: From d21bb82bc0345f929dc2a6684d88bb4d3c2b8eb8 Mon Sep 17 00:00:00 2001 From: Adrien Vannson Date: Thu, 26 Dec 2024 14:37:01 +0100 Subject: [PATCH 2/6] Add pickling test --- tests/inputs/pickling/pickling.proto | 43 ++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 tests/inputs/pickling/pickling.proto diff --git a/tests/inputs/pickling/pickling.proto b/tests/inputs/pickling/pickling.proto new file mode 100644 index 00000000..3de7ae43 --- /dev/null +++ b/tests/inputs/pickling/pickling.proto @@ -0,0 +1,43 @@ +syntax = "proto3"; + +package pickling; + +import "google/protobuf/any.proto"; +import "google/protobuf/struct.proto"; + + +message Test {} + +message Fe { + string abc = 1; +} + +message Fi { + string abc = 1; +} + +message Fo { + string abc = 1; +} + +message NestedData { + map struct_foo = 1; + map map_str_any_bar = 2; +} + +message Complex { + string foo_str = 1; + oneof grp { + Fe fe = 3; + Fi fi = 4; + Fo fo = 5; + } + NestedData nested_data = 6; + map mapping = 7; +} + +message PickledMessage { + bool foo = 1; + int32 bar = 2; + repeated string baz = 3; +} From cebb61d791ba29c75b713d3dd4dad7e5e73cf2f0 Mon Sep 17 00:00:00 2001 From: Adrien Vannson Date: Thu, 26 Dec 2024 14:42:39 +0100 Subject: [PATCH 3/6] Add stream stream test --- tests/inputs/stream_stream/stream_stream.proto | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 tests/inputs/stream_stream/stream_stream.proto diff --git a/tests/inputs/stream_stream/stream_stream.proto b/tests/inputs/stream_stream/stream_stream.proto new file mode 100644 index 00000000..2bfd5971 --- /dev/null +++ b/tests/inputs/stream_stream/stream_stream.proto @@ -0,0 +1,7 @@ +syntax = "proto3"; + +package stream_stream; + +message Message { + string body = 1; +} From 0b2c1d9e0acef07e00cbbaad94cf4ccfb3e9398f Mon Sep 17 00:00:00 2001 From: Adrien Vannson Date: Thu, 26 Dec 2024 19:45:57 +0100 Subject: [PATCH 4/6] Add a few messages for the features test --- tests/inputs/features/features.proto | 49 ++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 tests/inputs/features/features.proto diff --git a/tests/inputs/features/features.proto b/tests/inputs/features/features.proto new file mode 100644 index 00000000..e0151d95 --- /dev/null +++ b/tests/inputs/features/features.proto @@ -0,0 +1,49 @@ +syntax = "proto3"; + +package features; + +message Bar { + string name = 1; +} + +message Foo { + string name = 1; + Bar child = 2; +} + +// Enums as int json +enum Enum { + ZERO = 0; + ONE = 1; +} + +message EnumMsg { + Enum enum = 1; +} + +// Unknown fields +message Newer { + bool x = 1; + int32 y = 2; + string z = 3; +} + +message Older { + bool x = 1; +} + +// Oneof support +message IntMsg { + int32 val = 1; +} + +message OneofMsg { + oneof group1 { + int32 x = 1; + string y = 2; + } + oneof group2 { + IntMsg a = 3; + string b = 4; + } +} From f9e1dd643ed558690450beee5e334b51ea19d47a Mon Sep 17 00:00:00 2001 From: Adrien Vannson Date: Thu, 26 Dec 2024 20:22:27 +0100 Subject: [PATCH 5/6] Fix feature optional tests --- tests/inputs/features/features.proto | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/tests/inputs/features/features.proto b/tests/inputs/features/features.proto index e0151d95..31d1db57 100644 --- a/tests/inputs/features/features.proto +++ b/tests/inputs/features/features.proto @@ -1,5 +1,8 @@ syntax = "proto3"; +import "google/protobuf/timestamp.proto"; +import "google/protobuf/wrappers.proto"; + package features; message Bar { @@ -47,3 +50,28 @@ message OneofMsg { string b = 4; } } + +// JSON casing +message JsonCasingMsg { + int32 pascal_case = 1; + int32 camel_case = 2; + int32 snake_case = 3; + int32 kabob_case = 4; +} + +// Optional fields +message OptionalBoolMsg { + google.protobuf.BoolValue field = 1; +} + +message OptionalDatetimeMsg { + google.protobuf.Timestamp field = 1; +} + +// Other message definitions +message MsgA { + int32 some_int = 1; + double some_double = 2; + string some_str = 3; + bool some_bool = 4; +} \ No newline at end of file From e7318d0983807abcb186e4b91fc417180389bd53 Mon Sep 17 00:00:00 2001 From: Adrien Vannson Date: Thu, 26 Dec 2024 23:20:24 +0100 Subject: [PATCH 6/6] More message for feature test --- tests/inputs/features/features.proto | 42 ++++++++++++++++++++++++---- 1 file changed, 36 insertions(+), 6 deletions(-) diff --git a/tests/inputs/features/features.proto b/tests/inputs/features/features.proto index 31d1db57..65048850 100644 --- a/tests/inputs/features/features.proto +++ b/tests/inputs/features/features.proto @@ -1,6 +1,7 @@ syntax = "proto3"; import "google/protobuf/timestamp.proto"; +import "google/protobuf/duration.proto"; import "google/protobuf/wrappers.proto"; package features; @@ -14,7 +15,6 @@ message Foo { Bar child = 2; } -// Enums as int json enum Enum { ZERO = 0; ONE = 1; @@ -24,7 +24,6 @@ message EnumMsg { Enum enum = 1; } -// Unknown fields message Newer { bool x = 1; int32 y = 2; @@ -35,7 +34,6 @@ message Older { bool x = 1; } -// Oneof support message IntMsg { int32 val = 1; } @@ -51,7 +49,6 @@ message OneofMsg { } } -// JSON casing message JsonCasingMsg { int32 pascal_case = 1; int32 camel_case = 2; @@ -59,7 +56,6 @@ message JsonCasingMsg { int32 kabob_case = 4; } -// Optional fields message OptionalBoolMsg { google.protobuf.BoolValue field = 1; } @@ -68,10 +64,44 @@ message OptionalDatetimeMsg { google.protobuf.Timestamp field = 1; } -// Other message definitions +message Empty {} + +message TimeMsg { + google.protobuf.Timestamp timestamp = 1; + google.protobuf.Duration duration = 2; +} + message MsgA { int32 some_int = 1; double some_double = 2; string some_str = 3; bool some_bool = 4; +} + +message MsgB { + int32 some_int = 1; + double some_double = 2; + string some_str = 3; + bool some_bool = 4; + int32 some_default_int = 5; + double some_default_double = 6; + string some_default_str = 7; + bool some_default_bool = 8; +} + +message MsgC { + oneof group1 { + int32 int_field = 1; + string string_field = 2; + Empty empty_field = 3; + } +} + +message MsgD { + repeated google.protobuf.Timestamp timestamps = 1; +} + +message MsgE { + bool bool_field = 1; + optional int32 int_field = 2; } \ No newline at end of file