aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorkenton@google.com <kenton@google.com@630680e5-0e50-0410-840e-4b1c322b438d>2009-12-23 02:01:01 +0000
committerkenton@google.com <kenton@google.com@630680e5-0e50-0410-840e-4b1c322b438d>2009-12-23 02:01:01 +0000
commitd0047c43d955174d79a2df623dbb4007965252b5 (patch)
tree43b2b4dbffe90e2ca7b00da247c6a631484d0bde
parenteef5f8396dd527c17ab7e419ca8781052031d05d (diff)
downloadprotobuf-d0047c43d955174d79a2df623dbb4007965252b5.tar.gz
protobuf-d0047c43d955174d79a2df623dbb4007965252b5.tar.bz2
protobuf-d0047c43d955174d79a2df623dbb4007965252b5.zip
In Python, avoid relying on float('inf') and float('nan') as these don't work on Windows with Python pre-2.6.
-rwxr-xr-xpython/google/protobuf/internal/generator_test.py27
-rwxr-xr-xpython/google/protobuf/internal/text_format_test.py14
-rwxr-xr-xpython/google/protobuf/text_format.py12
-rw-r--r--src/google/protobuf/compiler/python/python_generator.cc20
4 files changed, 56 insertions, 17 deletions
diff --git a/python/google/protobuf/internal/generator_test.py b/python/google/protobuf/internal/generator_test.py
index dd27c9a3..78360b53 100755
--- a/python/google/protobuf/internal/generator_test.py
+++ b/python/google/protobuf/internal/generator_test.py
@@ -78,12 +78,27 @@ class GeneratorTest(unittest.TestCase):
def testExtremeDefaultValues(self):
message = unittest_pb2.TestExtremeDefaultValues()
- self.assertEquals(float('inf'), message.inf_double)
- self.assertEquals(float('-inf'), message.neg_inf_double)
- self.assert_(message.nan_double != message.nan_double)
- self.assertEquals(float('inf'), message.inf_float)
- self.assertEquals(float('-inf'), message.neg_inf_float)
- self.assert_(message.nan_float != message.nan_float)
+
+ # Python pre-2.6 does not have isinf() or isnan() functions, so we have
+ # to provide our own.
+ def isnan(val):
+ # NaN is never equal to itself.
+ return val != val
+ def isinf(val):
+ # Infinity times zero equals NaN.
+ return not isnan(val) and isnan(val * 0)
+
+ self.assertTrue(isinf(message.inf_double))
+ self.assertTrue(message.inf_double > 0)
+ self.assertTrue(isinf(message.neg_inf_double))
+ self.assertTrue(message.neg_inf_double < 0)
+ self.assertTrue(isnan(message.nan_double))
+
+ self.assertTrue(isinf(message.inf_float))
+ self.assertTrue(message.inf_float > 0)
+ self.assertTrue(isinf(message.neg_inf_float))
+ self.assertTrue(message.neg_inf_float < 0)
+ self.assertTrue(isnan(message.nan_float))
def testHasDefaultValues(self):
desc = unittest_pb2.TestAllTypes.DESCRIPTOR
diff --git a/python/google/protobuf/internal/text_format_test.py b/python/google/protobuf/internal/text_format_test.py
index 6d46f7e4..e0991cb1 100755
--- a/python/google/protobuf/internal/text_format_test.py
+++ b/python/google/protobuf/internal/text_format_test.py
@@ -325,10 +325,10 @@ class TokenizerTest(unittest.TestCase):
'{',
(tokenizer.ConsumeIdentifier, 'A'),
':',
- (tokenizer.ConsumeFloat, float('inf')),
+ (tokenizer.ConsumeFloat, text_format._INFINITY),
(tokenizer.ConsumeIdentifier, 'B'),
':',
- (tokenizer.ConsumeFloat, float('-inf')),
+ (tokenizer.ConsumeFloat, -text_format._INFINITY),
(tokenizer.ConsumeIdentifier, 'C'),
':',
(tokenizer.ConsumeBool, True),
@@ -413,6 +413,16 @@ class TokenizerTest(unittest.TestCase):
tokenizer = text_format._Tokenizer(text)
self.assertRaises(text_format.ParseError, tokenizer.ConsumeBool)
+ def testInfNan(self):
+ # Make sure our infinity and NaN definitions are sound.
+ self.assertEquals(float, type(text_format._INFINITY))
+ self.assertEquals(float, type(text_format._NAN))
+ self.assertTrue(text_format._NAN != text_format._NAN)
+
+ inf_times_zero = text_format._INFINITY * 0
+ self.assertTrue(inf_times_zero != inf_times_zero)
+ self.assertTrue(text_format._INFINITY > 0)
+
if __name__ == '__main__':
unittest.main()
diff --git a/python/google/protobuf/text_format.py b/python/google/protobuf/text_format.py
index c5713b63..2def19c2 100755
--- a/python/google/protobuf/text_format.py
+++ b/python/google/protobuf/text_format.py
@@ -43,6 +43,12 @@ __all__ = [ 'MessageToString', 'PrintMessage', 'PrintField',
'PrintFieldValue', 'Merge' ]
+# Infinity and NaN are not explicitly supported by Python pre-2.6, and
+# float('inf') does not work on Windows (pre-2.6).
+_INFINITY = float('1e10000')
+_NAN = _INFINITY * 0
+
+
class ParseError(Exception):
"""Thrown in case of ASCII parsing error."""
@@ -478,12 +484,12 @@ class _Tokenizer(object):
if re.match(self._FLOAT_INFINITY, text):
self.NextToken()
if text.startswith('-'):
- return float('-inf')
- return float('inf')
+ return -_INFINITY
+ return _INFINITY
if re.match(self._FLOAT_NAN, text):
self.NextToken()
- return float('nan')
+ return _NAN
try:
result = float(text)
diff --git a/src/google/protobuf/compiler/python/python_generator.cc b/src/google/protobuf/compiler/python/python_generator.cc
index 54ab0a2d..2f7d0981 100644
--- a/src/google/protobuf/compiler/python/python_generator.cc
+++ b/src/google/protobuf/compiler/python/python_generator.cc
@@ -168,11 +168,15 @@ string StringifyDefaultValue(const FieldDescriptor& field) {
case FieldDescriptor::CPPTYPE_DOUBLE: {
double value = field.default_value_double();
if (value == numeric_limits<double>::infinity()) {
- return "float('inf')";
+ // Python pre-2.6 on Windows does not parse "inf" correctly. However,
+ // parsing a number that is too big for a double will return infinity.
+ return "float('1e10000')";
} else if (value == -numeric_limits<double>::infinity()) {
- return "float('-inf')";
+ // See above.
+ return "float('-1e10000')";
} else if (value != value) {
- return "float('nan')";
+ // infinity * 0 = nan
+ return "(float('1e10000') * 0)";
} else {
return SimpleDtoa(value);
}
@@ -180,11 +184,15 @@ string StringifyDefaultValue(const FieldDescriptor& field) {
case FieldDescriptor::CPPTYPE_FLOAT: {
float value = field.default_value_float();
if (value == numeric_limits<float>::infinity()) {
- return "float('inf')";
+ // Python pre-2.6 on Windows does not parse "inf" correctly. However,
+ // parsing a number that is too big for a double will return infinity.
+ return "float('1e10000')";
} else if (value == -numeric_limits<float>::infinity()) {
- return "float('-inf')";
+ // See above.
+ return "float('-1e10000')";
} else if (value != value) {
- return "float('nan')";
+ // infinity - infinity = nan
+ return "(float('1e10000') - float('1e10000'))";
} else {
return SimpleFtoa(value);
}