Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add additional parameters to to_json() and to_dict() methods #384

Merged
merged 12 commits into from
Sep 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 13 additions & 2 deletions proto/message.py
Original file line number Diff line number Diff line change
Expand Up @@ -376,7 +376,9 @@ def to_json(
use_integers_for_enums=True,
including_default_value_fields=True,
preserving_proto_field_name=False,
sort_keys=False,
indent=2,
float_precision=None,
) -> str:
"""Given a message instance, serialize it to json

Expand All @@ -389,10 +391,13 @@ def to_json(
preserving_proto_field_name (Optional(bool)): An option that
determines whether field name representations preserve
proto case (snake_case) or use lowerCamelCase. Default is False.
indent: The JSON object will be pretty-printed with this indent level.
sort_keys (Optional(bool)): If True, then the output will be sorted by field names.
Default is False.
indent (Optional(int)): The JSON object will be pretty-printed with this indent level.
An indent level of 0 or negative will only insert newlines.
Pass None for the most compact representation without newlines.

float_precision (Optional(int)): If set, use this to specify float field valid digits.
Default is None.
Returns:
str: The json string representation of the protocol buffer.
"""
Expand All @@ -401,7 +406,9 @@ def to_json(
use_integers_for_enums=use_integers_for_enums,
including_default_value_fields=including_default_value_fields,
preserving_proto_field_name=preserving_proto_field_name,
sort_keys=sort_keys,
indent=indent,
float_precision=float_precision,
)

def from_json(cls, payload, *, ignore_unknown_fields=False) -> "Message":
Expand All @@ -428,6 +435,7 @@ def to_dict(
use_integers_for_enums=True,
preserving_proto_field_name=True,
including_default_value_fields=True,
float_precision=None,
) -> "Message":
"""Given a message instance, return its representation as a python dict.

Expand All @@ -443,6 +451,8 @@ def to_dict(
including_default_value_fields (Optional(bool)): An option that
determines whether the default field values should be included in the results.
Default is True.
float_precision (Optional(int)): If set, use this to specify float field valid digits.
Default is None.

Returns:
dict: A representation of the protocol buffer using pythonic data structures.
Expand All @@ -454,6 +464,7 @@ def to_dict(
including_default_value_fields=including_default_value_fields,
preserving_proto_field_name=preserving_proto_field_name,
use_integers_for_enums=use_integers_for_enums,
float_precision=float_precision,
)

def copy_from(cls, instance, other):
Expand Down
24 changes: 24 additions & 0 deletions tests/test_json.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
# limitations under the License.

import pytest
import re

import proto
from google.protobuf.json_format import MessageToJson, Parse, ParseError
Expand Down Expand Up @@ -172,3 +173,26 @@ class Squid(proto.Message):
s_two = Squid.from_json(j)

assert s == s_two


def test_json_sort_keys():
class Squid(proto.Message):
name = proto.Field(proto.STRING, number=1)
mass_kg = proto.Field(proto.INT32, number=2)

s = Squid(name="Steve", mass_kg=20)
j = Squid.to_json(s, sort_keys=True, indent=None)

assert re.search(r"massKg.*name", j)


# TODO: https://github.com/googleapis/proto-plus-python/issues/390
def test_json_float_precision():
class Squid(proto.Message):
name = proto.Field(proto.STRING, number=1)
mass_kg = proto.Field(proto.FLOAT, number=2)

s = Squid(name="Steve", mass_kg=3.14159265)
j = Squid.to_json(s, float_precision=3, indent=None)

assert j == '{"name": "Steve", "massKg": 3.14}'
11 changes: 11 additions & 0 deletions tests/test_message.py
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,17 @@ class Color(proto.Enum):
assert new_s == s


# TODO: https://github.com/googleapis/proto-plus-python/issues/390
def test_serialize_to_dict_float_precision():
class Squid(proto.Message):
mass_kg = proto.Field(proto.FLOAT, number=1)

s = Squid(mass_kg=3.14159265)

s_dict = Squid.to_dict(s, float_precision=3)
assert s_dict["mass_kg"] == 3.14
Copy link
Contributor

@parthea parthea Sep 6, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would have expected this to be 3.141 or 3.142 since float_precision=3. If you agree, can you file a bug and add a comment?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I filed #390

Should it block this PR?



def test_unknown_field_deserialize():
# This is a somewhat common setup: a client uses an older proto definition,
# while the server sends the newer definition. The client still needs to be
Expand Down