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

Commit 1c7a572

Browse files
committed
Add to_dict for structs
1 parent 517c698 commit 1c7a572

File tree

2 files changed

+82
-2
lines changed

2 files changed

+82
-2
lines changed

src/betterproto2_compiler/known_types/__init__.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,19 @@
1313
UInt32Value,
1414
UInt64Value,
1515
)
16+
from .struct import ListValue, Struct, Value
1617
from .timestamp import Timestamp
1718

1819
# For each (package, message name), lists the methods that should be added to the message definition.
1920
# The source code of the method is read from the `known_types` folder. If imports are needed, they can be directly added
2021
# to the template file: they will automatically be removed if not necessary.
2122
KNOWN_METHODS: dict[tuple[str, str], list[Callable]] = {
2223
("google.protobuf", "Any"): [Any.pack, Any.unpack, Any.to_dict],
24+
# Struct
25+
("google.protobuf", "Struct"): [Struct.to_dict],
26+
("google.protobuf", "Value"): [Value.to_dict],
27+
("google.protobuf", "ListValue"): [ListValue.to_dict],
28+
# Time
2329
("google.protobuf", "Timestamp"): [
2430
Timestamp.from_datetime,
2531
Timestamp.to_datetime,
@@ -38,6 +44,7 @@
3844
Duration.from_wrapped,
3945
Duration.to_wrapped,
4046
],
47+
# Values
4148
("google.protobuf", "BoolValue"): [
4249
BoolValue.from_dict,
4350
BoolValue.to_dict,
@@ -96,6 +103,10 @@
96103

97104
# A wrapped type is the type of a message that is automatically replaced by a known Python type.
98105
WRAPPED_TYPES: dict[tuple[str, str], str] = {
106+
# Time
107+
("google.protobuf", "Timestamp"): "datetime.datetime",
108+
("google.protobuf", "Duration"): "datetime.timedelta",
109+
# Values
99110
("google.protobuf", "BoolValue"): "bool",
100111
("google.protobuf", "Int32Value"): "int",
101112
("google.protobuf", "Int64Value"): "int",
@@ -105,6 +116,4 @@
105116
("google.protobuf", "DoubleValue"): "float",
106117
("google.protobuf", "StringValue"): "str",
107118
("google.protobuf", "BytesValue"): "bytes",
108-
("google.protobuf", "Timestamp"): "datetime.datetime",
109-
("google.protobuf", "Duration"): "datetime.timedelta",
110119
}
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import typing
2+
3+
import betterproto2
4+
5+
from betterproto2_compiler.lib.google.protobuf import (
6+
ListValue as VanillaListValue,
7+
NullValue,
8+
Struct as VanillaStruct,
9+
Value as VanillaValue,
10+
)
11+
12+
13+
class Struct(VanillaStruct):
14+
# TODO typing
15+
def to_dict(
16+
self,
17+
*,
18+
output_format: betterproto2.OutputFormat = betterproto2.OutputFormat.PROTO_JSON,
19+
casing: betterproto2.Casing = betterproto2.Casing.CAMEL,
20+
include_default_values: bool = False,
21+
) -> dict[str, typing.Any] | typing.Any:
22+
# If the output format is PYTHON, we should have kept the wraped type without building the real class
23+
assert output_format == betterproto2.OutputFormat.PROTO_JSON
24+
25+
json = {}
26+
for name, value in self.fields.items():
27+
json[name] = value.to_dict(casing=casing)
28+
return json
29+
30+
31+
class Value(VanillaValue):
32+
def to_dict(
33+
self,
34+
*,
35+
output_format: betterproto2.OutputFormat = betterproto2.OutputFormat.PROTO_JSON,
36+
casing: betterproto2.Casing = betterproto2.Casing.CAMEL,
37+
include_default_values: bool = False,
38+
) -> dict[str, typing.Any] | typing.Any:
39+
# If the output format is PYTHON, we should have kept the wraped type without building the real class
40+
assert output_format == betterproto2.OutputFormat.PROTO_JSON
41+
42+
match self:
43+
case Value(null_value=NullValue()):
44+
return None
45+
case Value(number_value=float(number_value)):
46+
return number_value
47+
case Value(string_value=str(string_value)):
48+
return string_value
49+
case Value(bool_value=bool(bool_value)):
50+
return bool_value
51+
case Value(struct_value=struct_value) if struct_value is not None:
52+
return struct_value.to_dict(casing=casing)
53+
case Value(list_value=list_value) if list_value is not None:
54+
return list_value.to_dict(casing=casing)
55+
56+
57+
class ListValue(VanillaListValue):
58+
def to_dict(
59+
self,
60+
*,
61+
output_format: betterproto2.OutputFormat = betterproto2.OutputFormat.PROTO_JSON,
62+
casing: betterproto2.Casing = betterproto2.Casing.CAMEL,
63+
include_default_values: bool = False,
64+
) -> dict[str, typing.Any] | typing.Any:
65+
# If the output format is PYTHON, we should have kept the wraped type without building the real class
66+
assert output_format == betterproto2.OutputFormat.PROTO_JSON
67+
68+
json = []
69+
for value in self.values:
70+
json.append(value.to_dict(casing=casing))
71+
return json

0 commit comments

Comments
 (0)