betterproto2-compiler 0.7.1__py3-none-any.whl → 0.8.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/known_types/__init__.py +14 -1
- betterproto2_compiler/known_types/any.py +24 -3
- betterproto2_compiler/known_types/duration.py +2 -2
- betterproto2_compiler/known_types/struct.py +111 -0
- betterproto2_compiler/known_types/timestamp.py +2 -2
- betterproto2_compiler/lib/__init__.py +12 -0
- betterproto2_compiler/lib/google/protobuf/__init__.py +902 -107
- betterproto2_compiler/lib/google/protobuf/compiler/__init__.py +22 -5
- betterproto2_compiler/lib/py.typed +0 -0
- betterproto2_compiler/plugin/models.py +47 -47
- betterproto2_compiler/plugin/parser.py +3 -1
- betterproto2_compiler/templates/template.py.j2 +25 -18
- {betterproto2_compiler-0.7.1.dist-info → betterproto2_compiler-0.8.0.dist-info}/METADATA +2 -2
- {betterproto2_compiler-0.7.1.dist-info → betterproto2_compiler-0.8.0.dist-info}/RECORD +16 -14
- {betterproto2_compiler-0.7.1.dist-info → betterproto2_compiler-0.8.0.dist-info}/WHEEL +0 -0
- {betterproto2_compiler-0.7.1.dist-info → betterproto2_compiler-0.8.0.dist-info}/entry_points.txt +0 -0
@@ -13,13 +13,14 @@ from .google_values import (
|
|
13
13
|
UInt32Value,
|
14
14
|
UInt64Value,
|
15
15
|
)
|
16
|
+
from .struct import ListValue, Struct, Value
|
16
17
|
from .timestamp import Timestamp
|
17
18
|
|
18
19
|
# For each (package, message name), lists the methods that should be added to the message definition.
|
19
20
|
# The source code of the method is read from the `known_types` folder. If imports are needed, they can be directly added
|
20
21
|
# to the template file: they will automatically be removed if not necessary.
|
21
22
|
KNOWN_METHODS: dict[tuple[str, str], list[Callable]] = {
|
22
|
-
("google.protobuf", "Any"): [Any.pack, Any.unpack, Any.to_dict],
|
23
|
+
("google.protobuf", "Any"): [Any.pack, Any.unpack, Any.to_dict, Any.from_dict],
|
23
24
|
("google.protobuf", "Timestamp"): [
|
24
25
|
Timestamp.from_datetime,
|
25
26
|
Timestamp.to_datetime,
|
@@ -92,6 +93,18 @@ KNOWN_METHODS: dict[tuple[str, str], list[Callable]] = {
|
|
92
93
|
BytesValue.from_wrapped,
|
93
94
|
BytesValue.to_wrapped,
|
94
95
|
],
|
96
|
+
("google.protobuf", "Struct"): [
|
97
|
+
Struct.from_dict,
|
98
|
+
Struct.to_dict,
|
99
|
+
],
|
100
|
+
("google.protobuf", "ListValue"): [
|
101
|
+
ListValue.from_dict,
|
102
|
+
ListValue.to_dict,
|
103
|
+
],
|
104
|
+
("google.protobuf", "Value"): [
|
105
|
+
Value.from_dict,
|
106
|
+
Value.to_dict,
|
107
|
+
],
|
95
108
|
}
|
96
109
|
|
97
110
|
# A wrapped type is the type of a message that is automatically replaced by a known Python type.
|
@@ -8,7 +8,8 @@ default_message_pool = betterproto2.MessagePool() # Only for typing purpose
|
|
8
8
|
|
9
9
|
|
10
10
|
class Any(VanillaAny):
|
11
|
-
|
11
|
+
@classmethod
|
12
|
+
def pack(cls, message: betterproto2.Message, message_pool: "betterproto2.MessagePool | None" = None) -> "Any":
|
12
13
|
"""
|
13
14
|
Pack the given message in the `Any` object.
|
14
15
|
|
@@ -17,8 +18,10 @@ class Any(VanillaAny):
|
|
17
18
|
"""
|
18
19
|
message_pool = message_pool or default_message_pool
|
19
20
|
|
20
|
-
|
21
|
-
|
21
|
+
type_url = message_pool.type_to_url[type(message)]
|
22
|
+
value = bytes(message)
|
23
|
+
|
24
|
+
return cls(type_url=type_url, value=value)
|
22
25
|
|
23
26
|
def unpack(self, message_pool: "betterproto2.MessagePool | None" = None) -> betterproto2.Message | None:
|
24
27
|
"""
|
@@ -54,3 +57,21 @@ class Any(VanillaAny):
|
|
54
57
|
output["value"] = value.to_dict(**kwargs)
|
55
58
|
|
56
59
|
return output
|
60
|
+
|
61
|
+
# TODO typing
|
62
|
+
@classmethod
|
63
|
+
def from_dict(cls, value, *, ignore_unknown_fields: bool = False):
|
64
|
+
value = dict(value) # Make a copy
|
65
|
+
|
66
|
+
type_url = value.pop("@type", None)
|
67
|
+
msg_cls = default_message_pool.url_to_type.get(type_url, None)
|
68
|
+
|
69
|
+
if not msg_cls:
|
70
|
+
raise TypeError(f"Can't unpack unregistered type: {type_url}")
|
71
|
+
|
72
|
+
if not msg_cls.to_dict == betterproto2.Message.to_dict:
|
73
|
+
value = value["value"]
|
74
|
+
|
75
|
+
return cls(
|
76
|
+
type_url=type_url, value=bytes(msg_cls.from_dict(value, ignore_unknown_fields=ignore_unknown_fields))
|
77
|
+
)
|
@@ -30,7 +30,7 @@ class Duration(VanillaDuration):
|
|
30
30
|
|
31
31
|
# TODO typing
|
32
32
|
@classmethod
|
33
|
-
def from_dict(cls, value):
|
33
|
+
def from_dict(cls, value, *, ignore_unknown_fields: bool = False):
|
34
34
|
if isinstance(value, str):
|
35
35
|
if not re.match(r"^\d+(\.\d+)?s$", value):
|
36
36
|
raise ValueError(f"Invalid duration string: {value}")
|
@@ -38,7 +38,7 @@ class Duration(VanillaDuration):
|
|
38
38
|
seconds = float(value[:-1])
|
39
39
|
return Duration(seconds=int(seconds), nanos=int((seconds - int(seconds)) * 1e9))
|
40
40
|
|
41
|
-
return super().from_dict(value)
|
41
|
+
return super().from_dict(value, ignore_unknown_fields=ignore_unknown_fields)
|
42
42
|
|
43
43
|
# TODO typing
|
44
44
|
def to_dict(
|
@@ -0,0 +1,111 @@
|
|
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
|
+
@classmethod
|
16
|
+
def from_dict(cls, value, *, ignore_unknown_fields: bool = False):
|
17
|
+
assert isinstance(value, dict)
|
18
|
+
|
19
|
+
fields: dict[str, Value] = {}
|
20
|
+
|
21
|
+
for key, val in value.items():
|
22
|
+
fields[key] = Value.from_dict(val)
|
23
|
+
|
24
|
+
return cls(fields=fields) # type: ignore[reportArgumentType]
|
25
|
+
|
26
|
+
# TODO typing
|
27
|
+
def to_dict(
|
28
|
+
self,
|
29
|
+
*,
|
30
|
+
output_format: betterproto2.OutputFormat = betterproto2.OutputFormat.PROTO_JSON,
|
31
|
+
casing: betterproto2.Casing = betterproto2.Casing.CAMEL,
|
32
|
+
include_default_values: bool = False,
|
33
|
+
) -> dict[str, typing.Any] | typing.Any:
|
34
|
+
# If the output format is PYTHON, we should have kept the wrapped type without building the real class
|
35
|
+
assert output_format == betterproto2.OutputFormat.PROTO_JSON
|
36
|
+
|
37
|
+
return {
|
38
|
+
key: value.to_dict(
|
39
|
+
output_format=output_format, casing=casing, include_default_values=include_default_values
|
40
|
+
)
|
41
|
+
for key, value in self.fields.items()
|
42
|
+
}
|
43
|
+
|
44
|
+
|
45
|
+
# We can't use the unwrap mechanism to support directly using a Python object due to the None case: it would then be
|
46
|
+
# impossible to distinguish between the absence of the message and a None value.
|
47
|
+
class Value(VanillaValue):
|
48
|
+
# TODO typing
|
49
|
+
@classmethod
|
50
|
+
def from_dict(cls, value, *, ignore_unknown_fields: bool = False):
|
51
|
+
match value:
|
52
|
+
case bool() as b:
|
53
|
+
return cls(bool_value=b)
|
54
|
+
case int() | float() as num:
|
55
|
+
return cls(number_value=num)
|
56
|
+
case str() as s:
|
57
|
+
return cls(string_value=s)
|
58
|
+
case list() as l:
|
59
|
+
return cls(list_value=ListValue.from_dict(l))
|
60
|
+
case dict() as d:
|
61
|
+
return cls(struct_value=Struct.from_dict(d))
|
62
|
+
case None:
|
63
|
+
return cls(null_value=NullValue.NULL_VALUE)
|
64
|
+
raise ValueError(f"Unknown value type: {type(value)}")
|
65
|
+
|
66
|
+
# TODO typing
|
67
|
+
def to_dict(
|
68
|
+
self,
|
69
|
+
*,
|
70
|
+
output_format: betterproto2.OutputFormat = betterproto2.OutputFormat.PROTO_JSON,
|
71
|
+
casing: betterproto2.Casing = betterproto2.Casing.CAMEL,
|
72
|
+
include_default_values: bool = False,
|
73
|
+
) -> dict[str, typing.Any] | typing.Any:
|
74
|
+
# If the output format is PYTHON, we should have kept the wrapped type without building the real class
|
75
|
+
assert output_format == betterproto2.OutputFormat.PROTO_JSON
|
76
|
+
|
77
|
+
match self:
|
78
|
+
case Value(null_value=NullValue.NULL_VALUE):
|
79
|
+
return None
|
80
|
+
case Value(bool_value=bool(b)):
|
81
|
+
return b
|
82
|
+
case Value(number_value=int(num)) | Value(number_value=float(num)):
|
83
|
+
return num
|
84
|
+
case Value(string_value=str(s)):
|
85
|
+
return s
|
86
|
+
case Value(list_value=ListValue(values=l)):
|
87
|
+
return [v.to_dict() for v in l]
|
88
|
+
case Value(struct_value=Struct(fields=f)):
|
89
|
+
return {k: v.to_dict() for k, v in f.items()}
|
90
|
+
|
91
|
+
raise ValueError("Invalid value")
|
92
|
+
|
93
|
+
|
94
|
+
class ListValue(VanillaListValue):
|
95
|
+
# TODO typing
|
96
|
+
@classmethod
|
97
|
+
def from_dict(cls, value, *, ignore_unknown_fields: bool = False):
|
98
|
+
return cls(values=[Value.from_dict(v) for v in value])
|
99
|
+
|
100
|
+
# TODO typing
|
101
|
+
def to_dict(
|
102
|
+
self,
|
103
|
+
*,
|
104
|
+
output_format: betterproto2.OutputFormat = betterproto2.OutputFormat.PROTO_JSON,
|
105
|
+
casing: betterproto2.Casing = betterproto2.Casing.CAMEL,
|
106
|
+
include_default_values: bool = False,
|
107
|
+
) -> dict[str, typing.Any] | typing.Any:
|
108
|
+
# If the output format is PYTHON, we should have kept the wrapped type without building the real class
|
109
|
+
assert output_format == betterproto2.OutputFormat.PROTO_JSON
|
110
|
+
|
111
|
+
return [value.to_dict() for value in self.values]
|
@@ -55,13 +55,13 @@ class Timestamp(VanillaTimestamp):
|
|
55
55
|
|
56
56
|
# TODO typing
|
57
57
|
@classmethod
|
58
|
-
def from_dict(cls, value):
|
58
|
+
def from_dict(cls, value, *, ignore_unknown_fields: bool = False):
|
59
59
|
if isinstance(value, str):
|
60
60
|
dt = dateutil.parser.isoparse(value)
|
61
61
|
dt = dt.astimezone(datetime.timezone.utc)
|
62
62
|
return Timestamp.from_datetime(dt)
|
63
63
|
|
64
|
-
return super().from_dict(value)
|
64
|
+
return super().from_dict(value, ignore_unknown_fields=ignore_unknown_fields)
|
65
65
|
|
66
66
|
# TODO typing
|
67
67
|
def to_dict(
|
@@ -0,0 +1,12 @@
|
|
1
|
+
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
2
|
+
# sources: protobuf.proto
|
3
|
+
# plugin: python-betterproto2
|
4
|
+
# This file has been @generated
|
5
|
+
|
6
|
+
__all__ = ()
|
7
|
+
|
8
|
+
|
9
|
+
import betterproto2
|
10
|
+
|
11
|
+
_COMPILER_VERSION = "0.8.0"
|
12
|
+
betterproto2.check_compiler_version(_COMPILER_VERSION)
|