diff --git a/python/google/protobuf/pyext/message.cc b/python/google/protobuf/pyext/message.cc index aa3ab97a6..62c7c478f 100644 --- a/python/google/protobuf/pyext/message.cc +++ b/python/google/protobuf/pyext/message.cc @@ -340,7 +340,7 @@ static int InsertEmptyWeakref(PyTypeObject *base_type) { } // namespace message_meta -PyTypeObject PyMessageMeta_Type { +PyTypeObject PyMessageMeta_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) FULL_MODULE_NAME ".MessageMeta", // tp_name sizeof(PyMessageMeta), // tp_basicsize @@ -1776,22 +1776,25 @@ class PythonFieldValuePrinter : public TextFormat::FieldValuePrinter { // Python floats to ensure consistency. string PrintFloat(float value) const { return PrintDouble(value); } string PrintDouble(double value) const { - // Same as float.__str__() - char* buf = PyOS_double_to_string( - value, -#if PY_MAJOR_VERSION < 3 - 'g', PyFloat_STR_PRECISION, // Output is rounded to 12 digits. -#else - 'r', 0, -#endif - Py_DTSF_ADD_DOT_0, // Trailing .0 is always printed. - NULL); - if (!buf) { + // This implementation is not highly optimized (it allocates two temporary + // Python objects) but it is simple and portable. If this is shown to be a + // performance bottleneck, we can optimize it, but the results will likely + // be more complicated to accommodate the differing behavior of double + // formatting between Python 2 and Python 3. + // + // (Though a valid question is: do we really want to make out output + // dependent on the Python version?) + ScopedPyObjectPtr py_value(PyFloat_FromDouble(value)); + if (!py_value.get()) { return string(); } - string result(buf); - PyMem_Free(buf); - return result; + + ScopedPyObjectPtr py_str(PyObject_Str(py_value.get())); + if (!py_str.get()) { + return string(); + } + + return string(PyString_AsString(py_str.get())); } };