Commits

Anonymous committed 1cb8c67

In Python, avoid relying on float('inf') and float('nan') as these don't work on Windows with Python pre-2.6.

Comments (0)

Files changed (4)

python/google/protobuf/internal/generator_test.py

 
   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

python/google/protobuf/internal/text_format_test.py

                '{',
                (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),
     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()

python/google/protobuf/text_format.py

             '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."""
 
     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)

src/google/protobuf/compiler/python/python_generator.cc

     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);
       }
     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);
       }