Pull down the include_default_values argument to to_json (#405)

This commit is contained in:
Samuel Yvon 2022-08-08 09:26:28 -04:00 committed by GitHub
parent f31d51cf3c
commit 591ec5efb3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 82 additions and 2 deletions

View File

@ -1260,7 +1260,12 @@ class Message(ABC):
setattr(self, field_name, v)
return self
def to_json(self, indent: Union[None, int, str] = None) -> str:
def to_json(
self,
indent: Union[None, int, str] = None,
include_default_values: bool = False,
casing: Casing = Casing.CAMEL,
) -> str:
"""A helper function to parse the message instance into its JSON
representation.
@ -1273,12 +1278,24 @@ class Message(ABC):
indent: Optional[Union[:class:`int`, :class:`str`]]
The indent to pass to :func:`json.dumps`.
include_default_values: :class:`bool`
If ``True`` will include the default values of fields. Default is ``False``.
E.g. an ``int32`` field will be included with a value of ``0`` if this is
set to ``True``, otherwise this would be ignored.
casing: :class:`Casing`
The casing to use for key values. Default is :attr:`Casing.CAMEL` for
compatibility purposes.
Returns
--------
:class:`str`
The JSON representation of the message.
"""
return json.dumps(self.to_dict(), indent=indent)
return json.dumps(
self.to_dict(include_default_values=include_default_values, casing=casing),
indent=indent,
)
def from_json(self: T, value: Union[str, bytes]) -> T:
"""A helper function to return the message instance from its JSON

View File

@ -1,3 +1,4 @@
import json
from copy import (
copy,
deepcopy,
@ -190,6 +191,37 @@ def test_json_casing():
assert test == CasingTest(1, 2, 3, 4)
# Serializing should be strict.
assert json.loads(test.to_json()) == {
"pascalCase": 1,
"camelCase": 2,
"snakeCase": 3,
"kabobCase": 4,
}
assert json.loads(test.to_json(casing=betterproto.Casing.SNAKE)) == {
"pascal_case": 1,
"camel_case": 2,
"snake_case": 3,
"kabob_case": 4,
}
def test_dict_casing():
@dataclass
class CasingTest(betterproto.Message):
pascal_case: int = betterproto.int32_field(1)
camel_case: int = betterproto.int32_field(2)
snake_case: int = betterproto.int32_field(3)
kabob_case: int = betterproto.int32_field(4)
# Parsing should accept almost any input
test = CasingTest().from_dict(
{"PascalCase": 1, "camelCase": 2, "snake_case": 3, "kabob-case": 4}
)
assert test == CasingTest(1, 2, 3, 4)
# Serializing should be strict.
assert test.to_dict() == {
"pascalCase": 1,
@ -233,6 +265,37 @@ def test_optional_flag():
assert Request().parse(b"\n\x00").flag is False
def test_to_json_default_values():
@dataclass
class TestMessage(betterproto.Message):
some_int: int = betterproto.int32_field(1)
some_double: float = betterproto.double_field(2)
some_str: str = betterproto.string_field(3)
some_bool: bool = betterproto.bool_field(4)
# Empty dict
test = TestMessage().from_dict({})
assert json.loads(test.to_json(include_default_values=True)) == {
"someInt": 0,
"someDouble": 0.0,
"someStr": "",
"someBool": False,
}
# All default values
test = TestMessage().from_dict(
{"someInt": 0, "someDouble": 0.0, "someStr": "", "someBool": False}
)
assert json.loads(test.to_json(include_default_values=True)) == {
"someInt": 0,
"someDouble": 0.0,
"someStr": "",
"someBool": False,
}
def test_to_dict_default_values():
@dataclass
class TestMessage(betterproto.Message):