Skip to content

Commit 591ec5e

Browse files
authored
Pull down the include_default_values argument to to_json (#405)
1 parent f31d51c commit 591ec5e

File tree

2 files changed

+82
-2
lines changed

2 files changed

+82
-2
lines changed

src/betterproto/__init__.py

+19-2
Original file line numberDiff line numberDiff line change
@@ -1260,7 +1260,12 @@ def from_dict(self: T, value: Dict[str, Any]) -> T:
12601260
setattr(self, field_name, v)
12611261
return self
12621262

1263-
def to_json(self, indent: Union[None, int, str] = None) -> str:
1263+
def to_json(
1264+
self,
1265+
indent: Union[None, int, str] = None,
1266+
include_default_values: bool = False,
1267+
casing: Casing = Casing.CAMEL,
1268+
) -> str:
12641269
"""A helper function to parse the message instance into its JSON
12651270
representation.
12661271
@@ -1273,12 +1278,24 @@ def to_json(self, indent: Union[None, int, str] = None) -> str:
12731278
indent: Optional[Union[:class:`int`, :class:`str`]]
12741279
The indent to pass to :func:`json.dumps`.
12751280
1281+
include_default_values: :class:`bool`
1282+
If ``True`` will include the default values of fields. Default is ``False``.
1283+
E.g. an ``int32`` field will be included with a value of ``0`` if this is
1284+
set to ``True``, otherwise this would be ignored.
1285+
1286+
casing: :class:`Casing`
1287+
The casing to use for key values. Default is :attr:`Casing.CAMEL` for
1288+
compatibility purposes.
1289+
12761290
Returns
12771291
--------
12781292
:class:`str`
12791293
The JSON representation of the message.
12801294
"""
1281-
return json.dumps(self.to_dict(), indent=indent)
1295+
return json.dumps(
1296+
self.to_dict(include_default_values=include_default_values, casing=casing),
1297+
indent=indent,
1298+
)
12821299

12831300
def from_json(self: T, value: Union[str, bytes]) -> T:
12841301
"""A helper function to return the message instance from its JSON

tests/test_features.py

+63
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import json
12
from copy import (
23
copy,
34
deepcopy,
@@ -190,6 +191,37 @@ class CasingTest(betterproto.Message):
190191

191192
assert test == CasingTest(1, 2, 3, 4)
192193

194+
# Serializing should be strict.
195+
assert json.loads(test.to_json()) == {
196+
"pascalCase": 1,
197+
"camelCase": 2,
198+
"snakeCase": 3,
199+
"kabobCase": 4,
200+
}
201+
202+
assert json.loads(test.to_json(casing=betterproto.Casing.SNAKE)) == {
203+
"pascal_case": 1,
204+
"camel_case": 2,
205+
"snake_case": 3,
206+
"kabob_case": 4,
207+
}
208+
209+
210+
def test_dict_casing():
211+
@dataclass
212+
class CasingTest(betterproto.Message):
213+
pascal_case: int = betterproto.int32_field(1)
214+
camel_case: int = betterproto.int32_field(2)
215+
snake_case: int = betterproto.int32_field(3)
216+
kabob_case: int = betterproto.int32_field(4)
217+
218+
# Parsing should accept almost any input
219+
test = CasingTest().from_dict(
220+
{"PascalCase": 1, "camelCase": 2, "snake_case": 3, "kabob-case": 4}
221+
)
222+
223+
assert test == CasingTest(1, 2, 3, 4)
224+
193225
# Serializing should be strict.
194226
assert test.to_dict() == {
195227
"pascalCase": 1,
@@ -233,6 +265,37 @@ class Request(betterproto.Message):
233265
assert Request().parse(b"\n\x00").flag is False
234266

235267

268+
def test_to_json_default_values():
269+
@dataclass
270+
class TestMessage(betterproto.Message):
271+
some_int: int = betterproto.int32_field(1)
272+
some_double: float = betterproto.double_field(2)
273+
some_str: str = betterproto.string_field(3)
274+
some_bool: bool = betterproto.bool_field(4)
275+
276+
# Empty dict
277+
test = TestMessage().from_dict({})
278+
279+
assert json.loads(test.to_json(include_default_values=True)) == {
280+
"someInt": 0,
281+
"someDouble": 0.0,
282+
"someStr": "",
283+
"someBool": False,
284+
}
285+
286+
# All default values
287+
test = TestMessage().from_dict(
288+
{"someInt": 0, "someDouble": 0.0, "someStr": "", "someBool": False}
289+
)
290+
291+
assert json.loads(test.to_json(include_default_values=True)) == {
292+
"someInt": 0,
293+
"someDouble": 0.0,
294+
"someStr": "",
295+
"someBool": False,
296+
}
297+
298+
236299
def test_to_dict_default_values():
237300
@dataclass
238301
class TestMessage(betterproto.Message):

0 commit comments

Comments
 (0)