betterproto: support Struct
and Value
(#551)
* betterproto: support `Struct` and `Value` Signed-off-by: William Woodruff <william@trailofbits.com> * betterproto: handle struct in to_dict as well Signed-off-by: William Woodruff <william@trailofbits.com> * tests: add Struct roundtrip tests Signed-off-by: William Woodruff <william@trailofbits.com> * specialize from_dict and to_dict on Struct ...rather than special-casing in the Message ABC. Signed-off-by: William Woodruff <william@trailofbits.com> * betterproto: `poe format` Signed-off-by: William Woodruff <william@trailofbits.com> * Update src/betterproto/__init__.py Co-authored-by: James Hilton-Balfe <gobot1234yt@gmail.com> * remove future annotations Signed-off-by: William Woodruff <william@trailofbits.com> * replace type[...] with typing.T Signed-off-by: William Woodruff <william@trailofbits.com> * quote instead Signed-off-by: William Woodruff <william@trailofbits.com> --------- Signed-off-by: William Woodruff <william@trailofbits.com> Co-authored-by: James Hilton-Balfe <gobot1234yt@gmail.com>
This commit is contained in:
parent
ce5093eec0
commit
5666393f9d
@ -2,14 +2,19 @@
|
|||||||
# sources: google/protobuf/any.proto, google/protobuf/api.proto, google/protobuf/descriptor.proto, google/protobuf/duration.proto, google/protobuf/empty.proto, google/protobuf/field_mask.proto, google/protobuf/source_context.proto, google/protobuf/struct.proto, google/protobuf/timestamp.proto, google/protobuf/type.proto, google/protobuf/wrappers.proto
|
# sources: google/protobuf/any.proto, google/protobuf/api.proto, google/protobuf/descriptor.proto, google/protobuf/duration.proto, google/protobuf/empty.proto, google/protobuf/field_mask.proto, google/protobuf/source_context.proto, google/protobuf/struct.proto, google/protobuf/timestamp.proto, google/protobuf/type.proto, google/protobuf/wrappers.proto
|
||||||
# plugin: python-betterproto
|
# plugin: python-betterproto
|
||||||
# This file has been @generated
|
# This file has been @generated
|
||||||
|
|
||||||
import warnings
|
import warnings
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from typing import (
|
from typing import (
|
||||||
Dict,
|
Dict,
|
||||||
List,
|
List,
|
||||||
|
Mapping,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
from typing_extensions import Self
|
||||||
|
|
||||||
import betterproto
|
import betterproto
|
||||||
|
from betterproto.utils import hybridmethod
|
||||||
|
|
||||||
|
|
||||||
class Syntax(betterproto.Enum):
|
class Syntax(betterproto.Enum):
|
||||||
@ -1458,6 +1463,32 @@ class Struct(betterproto.Message):
|
|||||||
)
|
)
|
||||||
"""Unordered map of dynamically typed values."""
|
"""Unordered map of dynamically typed values."""
|
||||||
|
|
||||||
|
@hybridmethod
|
||||||
|
def from_dict(cls: "type[Self]", value: Mapping[str, Any]) -> Self: # type: ignore
|
||||||
|
self = cls()
|
||||||
|
return self.from_dict(value)
|
||||||
|
|
||||||
|
@from_dict.instancemethod
|
||||||
|
def from_dict(self, value: Mapping[str, Any]) -> Self:
|
||||||
|
fields = {**value}
|
||||||
|
for k in fields:
|
||||||
|
if hasattr(fields[k], "from_dict"):
|
||||||
|
fields[k] = fields[k].from_dict()
|
||||||
|
|
||||||
|
self.fields = fields
|
||||||
|
return self
|
||||||
|
|
||||||
|
def to_dict(
|
||||||
|
self,
|
||||||
|
casing: betterproto.Casing = betterproto.Casing.CAMEL,
|
||||||
|
include_default_values: bool = False,
|
||||||
|
) -> Dict[str, Any]:
|
||||||
|
output = {**self.fields}
|
||||||
|
for k in self.fields:
|
||||||
|
if hasattr(self.fields[k], "to_dict"):
|
||||||
|
output[k] = self.fields[k].to_dict(casing, include_default_values)
|
||||||
|
return output
|
||||||
|
|
||||||
|
|
||||||
@dataclass(eq=False, repr=False)
|
@dataclass(eq=False, repr=False)
|
||||||
class Value(betterproto.Message):
|
class Value(betterproto.Message):
|
||||||
|
24
tests/test_struct.py
Normal file
24
tests/test_struct.py
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
import json
|
||||||
|
|
||||||
|
from betterproto.lib.google.protobuf import Struct
|
||||||
|
|
||||||
|
|
||||||
|
def test_struct_roundtrip():
|
||||||
|
data = {
|
||||||
|
"foo": "bar",
|
||||||
|
"baz": None,
|
||||||
|
"quux": 123,
|
||||||
|
"zap": [1, {"two": 3}, "four"],
|
||||||
|
}
|
||||||
|
data_json = json.dumps(data)
|
||||||
|
|
||||||
|
struct_from_dict = Struct().from_dict(data)
|
||||||
|
assert struct_from_dict.fields == data
|
||||||
|
assert struct_from_dict.to_dict() == data
|
||||||
|
assert struct_from_dict.to_json() == data_json
|
||||||
|
|
||||||
|
struct_from_json = Struct().from_json(data_json)
|
||||||
|
assert struct_from_json.fields == data
|
||||||
|
assert struct_from_json.to_dict() == data
|
||||||
|
assert struct_from_json == struct_from_dict
|
||||||
|
assert struct_from_json.to_json() == data_json
|
Loading…
x
Reference in New Issue
Block a user