Skip to content
Merged
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
37 changes: 33 additions & 4 deletions python/google/protobuf/json_format.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
__author__ = 'jieluo@google.com (Jie Luo)'


import ctypes
import base64
from collections import OrderedDict
import json
Expand All @@ -51,7 +52,6 @@
import re
import sys

from google.protobuf.internal import type_checkers
from google.protobuf import descriptor
from google.protobuf import symbol_database

Expand All @@ -75,6 +75,35 @@
_VALID_EXTENSION_NAME = re.compile(r'\[[a-zA-Z0-9\._]*\]$')


# NOTE(anton): copied from internal/type_checkers.py to avoid having json_format.py depend on internal interface of the
# protobuf library.
# Depending on an internal protobuf interface can hurt us since we are forking this file in noom-contracts, and the
# version of the protobuf library used on the client is under client's control.
# The other two imports in this file (descriptor and symbol_database) are part of the protobuf public interface, and
# there is less risk that this will change under us.
def TruncateToFourByteFloat(original):
return ctypes.c_float(original).value


# NOTE(anton): same comment from above TruncateToFourByteFloat applies here.
def ToShortestFloat(original):
"""Returns the shortest float that has same value in wire."""

Choose a reason for hiding this comment

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

Is this supposed to be commented out? Or is this some kind of logging?

Copy link
Author

Choose a reason for hiding this comment

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

The """ is the python way to put a comment about what a method does.

Explained here:
https://stackoverflow.com/questions/7057450/why-does-python-use-unconventional-triple-quotation-marks-for-comments

# All 4 byte floats have between 6 and 9 significant digits, so we
# start with 6 as the lower bound.
# It has to be iterative because use '.9g' directly can not get rid
# of the noises for most values. For example if set a float_field=0.9
# use '.9g' will print 0.899999976.
precision = 6
rounded = float('{0:.{1}g}'.format(original, precision))
while TruncateToFourByteFloat(rounded) != original:
precision += 1
rounded = float('{0:.{1}g}'.format(original, precision))
return rounded

# NOTE(anton): same comment from above TruncateToFourByteFloat applies here.
_FLOAT_MAX = float.fromhex('0x1.fffffep+127')
_FLOAT_MIN = -_FLOAT_MAX

class Error(Exception):
"""Top-level module error for json_format."""

Expand Down Expand Up @@ -308,7 +337,7 @@ def _FieldToJsonObject(self, field, value):
if self.float_format:
return float(format(value, self.float_format))
else:
return type_checkers.ToShortestFloat(value)
return ToShortestFloat(value)

return value

Expand Down Expand Up @@ -791,10 +820,10 @@ def _ConvertFloat(value, field):
'use quoted "-Infinity" instead.')
if field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_FLOAT:
# pylint: disable=protected-access
if value > type_checkers._FLOAT_MAX:
if value > _FLOAT_MAX:
raise ParseError('Float value too large')
# pylint: disable=protected-access
if value < type_checkers._FLOAT_MIN:
if value < _FLOAT_MIN:
raise ParseError('Float value too small')
if value == 'nan':
raise ParseError('Couldn\'t parse float "nan", use "NaN" instead.')
Expand Down