From 3b3c8abb9635eb3ea078a821a99c9ef29d66dff7 Mon Sep 17 00:00:00 2001 From: Jisi Liu Date: Wed, 30 Mar 2016 11:39:59 -0700 Subject: Integrate google internal changes. --- .../protobuf/internal/descriptor_database_test.py | 3 +- .../protobuf/internal/descriptor_pool_test.py | 13 +- python/google/protobuf/internal/descriptor_test.py | 5 +- python/google/protobuf/internal/generator_test.py | 3 +- .../google/protobuf/internal/json_format_test.py | 5 +- .../protobuf/internal/message_factory_test.py | 3 +- python/google/protobuf/internal/message_test.py | 53 +++----- .../google/protobuf/internal/proto_builder_test.py | 5 +- python/google/protobuf/internal/reflection_test.py | 3 +- .../protobuf/internal/service_reflection_test.py | 4 +- .../protobuf/internal/symbol_database_test.py | 3 +- python/google/protobuf/internal/test_util.py | 2 + .../google/protobuf/internal/text_encoding_test.py | 3 +- .../google/protobuf/internal/text_format_test.py | 37 +++++- .../protobuf/internal/unknown_fields_test.py | 2 +- .../protobuf/internal/well_known_types_test.py | 2 +- .../google/protobuf/internal/wire_format_test.py | 3 +- python/google/protobuf/json_format.py | 6 +- python/google/protobuf/pyext/descriptor.cc | 10 +- .../google/protobuf/pyext/descriptor_database.cc | 3 + python/google/protobuf/pyext/extension_dict.h | 2 +- python/google/protobuf/pyext/map_container.h | 2 +- python/google/protobuf/pyext/message.cc | 34 +++-- python/google/protobuf/pyext/message.h | 4 +- .../protobuf/pyext/repeated_composite_container.h | 2 +- .../protobuf/pyext/repeated_scalar_container.h | 2 +- python/google/protobuf/text_format.py | 137 ++++++++++++++------- 27 files changed, 216 insertions(+), 135 deletions(-) (limited to 'python/google') diff --git a/python/google/protobuf/internal/descriptor_database_test.py b/python/google/protobuf/internal/descriptor_database_test.py index 1baff7d1..5225a458 100644 --- a/python/google/protobuf/internal/descriptor_database_test.py +++ b/python/google/protobuf/internal/descriptor_database_test.py @@ -35,9 +35,10 @@ __author__ = 'matthewtoia@google.com (Matt Toia)' try: - import unittest2 as unittest + import unittest2 as unittest #PY26 except ImportError: import unittest + from google.protobuf import descriptor_pb2 from google.protobuf.internal import factory_test2_pb2 from google.protobuf import descriptor_database diff --git a/python/google/protobuf/internal/descriptor_pool_test.py b/python/google/protobuf/internal/descriptor_pool_test.py index f1d6bf99..4b1811d8 100644 --- a/python/google/protobuf/internal/descriptor_pool_test.py +++ b/python/google/protobuf/internal/descriptor_pool_test.py @@ -35,11 +35,13 @@ __author__ = 'matthewtoia@google.com (Matt Toia)' import os +import sys try: - import unittest2 as unittest + import unittest2 as unittest #PY26 except ImportError: import unittest + from google.protobuf import unittest_import_pb2 from google.protobuf import unittest_import_public_pb2 from google.protobuf import unittest_pb2 @@ -49,7 +51,6 @@ from google.protobuf.internal import descriptor_pool_test1_pb2 from google.protobuf.internal import descriptor_pool_test2_pb2 from google.protobuf.internal import factory_test1_pb2 from google.protobuf.internal import factory_test2_pb2 -from google.protobuf.internal import test_util from google.protobuf import descriptor from google.protobuf import descriptor_database from google.protobuf import descriptor_pool @@ -350,7 +351,7 @@ class DescriptorPoolTest(unittest.TestCase): @unittest.skipIf(api_implementation.Type() != 'cpp', - 'explicit tests of the C++ implementation') + 'explicit tests of the C++ implementation') class CppDescriptorPoolTest(DescriptorPoolTest): # TODO(amauryfa): remove when descriptor_pool.DescriptorPool() creates true # C++ descriptor pool object for C++ implementation. @@ -555,7 +556,7 @@ class AddDescriptorTest(unittest.TestCase): prefix + 'protobuf_unittest.TestAllTypes.NestedMessage').name) @unittest.skipIf(api_implementation.Type() == 'cpp', - 'With the cpp implementation, Add() must be called first') + 'With the cpp implementation, Add() must be called first') def testMessage(self): self._TestMessage('') self._TestMessage('.') @@ -591,13 +592,13 @@ class AddDescriptorTest(unittest.TestCase): prefix + 'protobuf_unittest.TestAllTypes.NestedEnum').name) @unittest.skipIf(api_implementation.Type() == 'cpp', - 'With the cpp implementation, Add() must be called first') + 'With the cpp implementation, Add() must be called first') def testEnum(self): self._TestEnum('') self._TestEnum('.') @unittest.skipIf(api_implementation.Type() == 'cpp', - 'With the cpp implementation, Add() must be called first') + 'With the cpp implementation, Add() must be called first') def testFile(self): pool = descriptor_pool.DescriptorPool() pool.AddFileDescriptor(unittest_pb2.DESCRIPTOR) diff --git a/python/google/protobuf/internal/descriptor_test.py b/python/google/protobuf/internal/descriptor_test.py index fee09a56..b8e75553 100755 --- a/python/google/protobuf/internal/descriptor_test.py +++ b/python/google/protobuf/internal/descriptor_test.py @@ -37,9 +37,10 @@ __author__ = 'robinson@google.com (Will Robinson)' import sys try: - import unittest2 as unittest + import unittest2 as unittest #PY26 except ImportError: import unittest + from google.protobuf import unittest_custom_options_pb2 from google.protobuf import unittest_import_pb2 from google.protobuf import unittest_pb2 @@ -596,7 +597,7 @@ class DescriptorCopyToProtoTest(unittest.TestCase): """ self._InternalTestCopyToProto( - unittest_pb2._FOREIGNENUM, + unittest_pb2.ForeignEnum.DESCRIPTOR, descriptor_pb2.EnumDescriptorProto, TEST_FOREIGN_ENUM_ASCII) diff --git a/python/google/protobuf/internal/generator_test.py b/python/google/protobuf/internal/generator_test.py index 9956da59..83ea5f50 100755 --- a/python/google/protobuf/internal/generator_test.py +++ b/python/google/protobuf/internal/generator_test.py @@ -42,9 +42,10 @@ further ensures that we can use Python protocol message objects as we expect. __author__ = 'robinson@google.com (Will Robinson)' try: - import unittest2 as unittest + import unittest2 as unittest #PY26 except ImportError: import unittest + from google.protobuf.internal import test_bad_identifiers_pb2 from google.protobuf import unittest_custom_options_pb2 from google.protobuf import unittest_import_pb2 diff --git a/python/google/protobuf/internal/json_format_test.py b/python/google/protobuf/internal/json_format_test.py index 49e96a46..bdc9f49a 100644 --- a/python/google/protobuf/internal/json_format_test.py +++ b/python/google/protobuf/internal/json_format_test.py @@ -39,9 +39,10 @@ import math import sys try: - import unittest2 as unittest + import unittest2 as unittest #PY26 except ImportError: import unittest + from google.protobuf import any_pb2 from google.protobuf import duration_pb2 from google.protobuf import field_mask_pb2 @@ -758,7 +759,7 @@ class JsonFormatTest(JsonFormatBase): 'Can not find message descriptor by type_url: ' 'type.googleapis.com/MessageNotExist.', json_format.Parse, text, message) - # Only last part is to be used. + # Only last part is to be used: b/25630112 text = (r'{"@type": "incorrect.googleapis.com/google.protobuf.Int32Value",' r'"value": 1234}') json_format.Parse(text, message) diff --git a/python/google/protobuf/internal/message_factory_test.py b/python/google/protobuf/internal/message_factory_test.py index 2fbe5ea7..54b1f688 100644 --- a/python/google/protobuf/internal/message_factory_test.py +++ b/python/google/protobuf/internal/message_factory_test.py @@ -35,9 +35,10 @@ __author__ = 'matthewtoia@google.com (Matt Toia)' try: - import unittest2 as unittest + import unittest2 as unittest #PY26 except ImportError: import unittest + from google.protobuf import descriptor_pb2 from google.protobuf.internal import factory_test1_pb2 from google.protobuf.internal import factory_test2_pb2 diff --git a/python/google/protobuf/internal/message_test.py b/python/google/protobuf/internal/message_test.py index d03f2d25..34e74bb3 100755 --- a/python/google/protobuf/internal/message_test.py +++ b/python/google/protobuf/internal/message_test.py @@ -53,14 +53,14 @@ import six import sys try: - import unittest2 as unittest + import unittest2 as unittest #PY26 except ImportError: import unittest + from google.protobuf.internal import _parameterized from google.protobuf import map_unittest_pb2 from google.protobuf import unittest_pb2 from google.protobuf import unittest_proto3_arena_pb2 -from google.protobuf.internal import any_test_pb2 from google.protobuf.internal import api_implementation from google.protobuf.internal import packed_field_test_pb2 from google.protobuf.internal import test_util @@ -69,6 +69,7 @@ from google.protobuf import message if six.PY3: long = int + # Python pre-2.6 does not have isinf() or isnan() functions, so we have # to provide our own. def isnan(val): @@ -1157,6 +1158,7 @@ class Proto2Test(unittest.TestCase): unittest_pb2.TestAllTypes(repeated_nested_enum='FOO') + # Class to test proto3-only features/behavior (updated field presence & enums) class Proto3Test(unittest.TestCase): @@ -1448,6 +1450,22 @@ class Proto3Test(unittest.TestCase): del msg2.map_int32_foreign_message[222] self.assertFalse(222 in msg2.map_int32_foreign_message) + def testMergeFromBadType(self): + msg = map_unittest_pb2.TestMap() + with self.assertRaisesRegexp( + TypeError, + r'Parameter to MergeFrom\(\) must be instance of same class: expected ' + r'.*TestMap got int\.'): + msg.MergeFrom(1) + + def testCopyFromBadType(self): + msg = map_unittest_pb2.TestMap() + with self.assertRaisesRegexp( + TypeError, + r'Parameter to [A-Za-z]*From\(\) must be instance of same class: ' + r'expected .*TestMap got int\.'): + msg.CopyFrom(1) + def testIntegerMapWithLongs(self): msg = map_unittest_pb2.TestMap() msg.map_int32_int32[long(-123)] = long(-456) @@ -1666,37 +1684,6 @@ class Proto3Test(unittest.TestCase): msg.map_string_foreign_message['foo'].c = 5 self.assertEqual(0, len(msg.FindInitializationErrors())) - def testAnyMessage(self): - # Creates and sets message. - msg = any_test_pb2.TestAny() - msg_descriptor = msg.DESCRIPTOR - all_types = unittest_pb2.TestAllTypes() - all_descriptor = all_types.DESCRIPTOR - all_types.repeated_string.append(u'\u00fc\ua71f') - # Packs to Any. - msg.value.Pack(all_types) - self.assertEqual(msg.value.type_url, - 'type.googleapis.com/%s' % all_descriptor.full_name) - self.assertEqual(msg.value.value, - all_types.SerializeToString()) - # Tests Is() method. - self.assertTrue(msg.value.Is(all_descriptor)) - self.assertFalse(msg.value.Is(msg_descriptor)) - # Unpacks Any. - unpacked_message = unittest_pb2.TestAllTypes() - self.assertTrue(msg.value.Unpack(unpacked_message)) - self.assertEqual(all_types, unpacked_message) - # Unpacks to different type. - self.assertFalse(msg.value.Unpack(msg)) - # Only Any messages have Pack method. - try: - msg.Pack(all_types) - except AttributeError: - pass - else: - raise AttributeError('%s should not have Pack method.' % - msg_descriptor.full_name) - class ValidTypeNamesTest(unittest.TestCase): diff --git a/python/google/protobuf/internal/proto_builder_test.py b/python/google/protobuf/internal/proto_builder_test.py index 822ad895..880b570d 100644 --- a/python/google/protobuf/internal/proto_builder_test.py +++ b/python/google/protobuf/internal/proto_builder_test.py @@ -36,10 +36,7 @@ try: from collections import OrderedDict except ImportError: from ordereddict import OrderedDict #PY26 -try: - import unittest2 as unittest -except ImportError: - import unittest +import unittest from google.protobuf import descriptor_pb2 from google.protobuf import descriptor_pool from google.protobuf import proto_builder diff --git a/python/google/protobuf/internal/reflection_test.py b/python/google/protobuf/internal/reflection_test.py index 752f2f5d..9e61ea0e 100755 --- a/python/google/protobuf/internal/reflection_test.py +++ b/python/google/protobuf/internal/reflection_test.py @@ -42,9 +42,10 @@ import six import struct try: - import unittest2 as unittest + import unittest2 as unittest #PY26 except ImportError: import unittest + from google.protobuf import unittest_import_pb2 from google.protobuf import unittest_mset_pb2 from google.protobuf import unittest_pb2 diff --git a/python/google/protobuf/internal/service_reflection_test.py b/python/google/protobuf/internal/service_reflection_test.py index 98614b77..62900b1d 100755 --- a/python/google/protobuf/internal/service_reflection_test.py +++ b/python/google/protobuf/internal/service_reflection_test.py @@ -34,10 +34,12 @@ __author__ = 'petar@google.com (Petar Petrov)' + try: - import unittest2 as unittest + import unittest2 as unittest #PY26 except ImportError: import unittest + from google.protobuf import unittest_pb2 from google.protobuf import service_reflection from google.protobuf import service diff --git a/python/google/protobuf/internal/symbol_database_test.py b/python/google/protobuf/internal/symbol_database_test.py index 0cb935a8..c99b426d 100644 --- a/python/google/protobuf/internal/symbol_database_test.py +++ b/python/google/protobuf/internal/symbol_database_test.py @@ -33,9 +33,10 @@ """Tests for google.protobuf.symbol_database.""" try: - import unittest2 as unittest + import unittest2 as unittest #PY26 except ImportError: import unittest + from google.protobuf import unittest_pb2 from google.protobuf import descriptor from google.protobuf import symbol_database diff --git a/python/google/protobuf/internal/test_util.py b/python/google/protobuf/internal/test_util.py index ac88fa81..2c805599 100755 --- a/python/google/protobuf/internal/test_util.py +++ b/python/google/protobuf/internal/test_util.py @@ -38,6 +38,8 @@ __author__ = 'robinson@google.com (Will Robinson)' import os.path +import sys + from google.protobuf import unittest_import_pb2 from google.protobuf import unittest_pb2 from google.protobuf import descriptor_pb2 diff --git a/python/google/protobuf/internal/text_encoding_test.py b/python/google/protobuf/internal/text_encoding_test.py index 338a287b..c7d182c4 100755 --- a/python/google/protobuf/internal/text_encoding_test.py +++ b/python/google/protobuf/internal/text_encoding_test.py @@ -33,9 +33,10 @@ """Tests for google.protobuf.text_encoding.""" try: - import unittest2 as unittest + import unittest2 as unittest #PY26 except ImportError: import unittest + from google.protobuf import text_encoding TEST_VALUES = [ diff --git a/python/google/protobuf/internal/text_format_test.py b/python/google/protobuf/internal/text_format_test.py index 0e14556c..8ce0a44f 100755 --- a/python/google/protobuf/internal/text_format_test.py +++ b/python/google/protobuf/internal/text_format_test.py @@ -40,9 +40,10 @@ import six import string try: - import unittest2 as unittest + import unittest2 as unittest #PY26 except ImportError: import unittest + from google.protobuf.internal import _parameterized from google.protobuf import map_unittest_pb2 @@ -62,7 +63,7 @@ class SimpleTextFormatTests(unittest.TestCase): # expects single characters. Therefore it's an error (in addition to being # non-sensical in the first place) to try to specify a "quote mark" that is # more than one character. - def TestQuoteMarksAreSingleChars(self): + def testQuoteMarksAreSingleChars(self): for quote in text_format._QUOTES: self.assertEqual(1, len(quote)) @@ -314,6 +315,18 @@ class TextFormatTest(TextFormatBase): self.assertEqual(u'one', message.repeated_string[0]) self.assertEqual(u'two', message.repeated_string[1]) + def testParseRepeatedMessageShortFormat(self, message_module): + message = message_module.TestAllTypes() + text = ('repeated_nested_message: [{bb: 100}, {bb: 200}],\n' + 'repeated_nested_message: {bb: 300}\n' + 'repeated_nested_message [{bb: 400}];\n') + text_format.Parse(text, message) + + self.assertEqual(100, message.repeated_nested_message[0].bb) + self.assertEqual(200, message.repeated_nested_message[1].bb) + self.assertEqual(300, message.repeated_nested_message[2].bb) + self.assertEqual(400, message.repeated_nested_message[3].bb) + def testParseEmptyText(self, message_module): message = message_module.TestAllTypes() text = '' @@ -411,6 +424,19 @@ class TextFormatTest(TextFormatBase): text_format.Parse(text_format.MessageToString(m), m2) self.assertEqual('oneof_uint32', m2.WhichOneof('oneof_field')) + def testParseMultipleOneof(self, message_module): + m_string = '\n'.join([ + 'oneof_uint32: 11', + 'oneof_string: "foo"']) + m2 = message_module.TestAllTypes() + if message_module is unittest_pb2: + with self.assertRaisesRegexp( + text_format.ParseError, ' is specified along with field '): + text_format.Parse(m_string, m2) + else: + text_format.Parse(m_string, m2) + self.assertEqual('oneof_string', m2.WhichOneof('oneof_field')) + # These are tests that aren't fundamentally specific to proto2, but are at # the moment because of differences between the proto2 and proto3 test schemas. @@ -426,7 +452,8 @@ class OnlyWorksWithProto2RightNowTests(TextFormatBase): 'text_format_unittest_data_pointy_oneof.txt') def testParseGolden(self): - golden_text = '\n'.join(self.ReadGolden('text_format_unittest_data.txt')) + golden_text = '\n'.join(self.ReadGolden( + 'text_format_unittest_data_oneof_implemented.txt')) parsed_message = unittest_pb2.TestAllTypes() r = text_format.Parse(golden_text, parsed_message) self.assertIs(r, parsed_message) @@ -469,7 +496,7 @@ class OnlyWorksWithProto2RightNowTests(TextFormatBase): 'optional_nested_message {\n bb: 1\n oo: 0\n}\n') def testMergeLinesGolden(self): - opened = self.ReadGolden('text_format_unittest_data.txt') + opened = self.ReadGolden('text_format_unittest_data_oneof_implemented.txt') parsed_message = unittest_pb2.TestAllTypes() r = text_format.MergeLines(opened, parsed_message) self.assertIs(r, parsed_message) @@ -479,7 +506,7 @@ class OnlyWorksWithProto2RightNowTests(TextFormatBase): self.assertEqual(message, parsed_message) def testParseLinesGolden(self): - opened = self.ReadGolden('text_format_unittest_data.txt') + opened = self.ReadGolden('text_format_unittest_data_oneof_implemented.txt') parsed_message = unittest_pb2.TestAllTypes() r = text_format.ParseLines(opened, parsed_message) self.assertIs(r, parsed_message) diff --git a/python/google/protobuf/internal/unknown_fields_test.py b/python/google/protobuf/internal/unknown_fields_test.py index 9685b8b4..bb2748e4 100755 --- a/python/google/protobuf/internal/unknown_fields_test.py +++ b/python/google/protobuf/internal/unknown_fields_test.py @@ -36,7 +36,7 @@ __author__ = 'bohdank@google.com (Bohdan Koval)' try: - import unittest2 as unittest + import unittest2 as unittest #PY26 except ImportError: import unittest from google.protobuf import unittest_mset_pb2 diff --git a/python/google/protobuf/internal/well_known_types_test.py b/python/google/protobuf/internal/well_known_types_test.py index 6acbee22..18329205 100644 --- a/python/google/protobuf/internal/well_known_types_test.py +++ b/python/google/protobuf/internal/well_known_types_test.py @@ -37,7 +37,7 @@ __author__ = 'jieluo@google.com (Jie Luo)' from datetime import datetime try: - import unittest2 as unittest + import unittest2 as unittest #PY26 except ImportError: import unittest diff --git a/python/google/protobuf/internal/wire_format_test.py b/python/google/protobuf/internal/wire_format_test.py index f659d18e..da120f33 100755 --- a/python/google/protobuf/internal/wire_format_test.py +++ b/python/google/protobuf/internal/wire_format_test.py @@ -35,9 +35,10 @@ __author__ = 'robinson@google.com (Will Robinson)' try: - import unittest2 as unittest + import unittest2 as unittest #PY26 except ImportError: import unittest + from google.protobuf import message from google.protobuf.internal import wire_format diff --git a/python/google/protobuf/json_format.py b/python/google/protobuf/json_format.py index 23382bdb..4342755a 100644 --- a/python/google/protobuf/json_format.py +++ b/python/google/protobuf/json_format.py @@ -271,10 +271,8 @@ def _ListValueMessageToJsonObject(message, unused_including_default=False): def _StructMessageToJsonObject(message, unused_including_default=False): """Converts Struct message according to Proto3 JSON Specification.""" fields = message.fields - js = {} - for key in fields.keys(): - js[key] = _ValueMessageToJsonObject(fields[key]) - return js + return {key: _ValueMessageToJsonObject(fields[key]) + for key in fields} def _IsWrapperMessage(message_descriptor): diff --git a/python/google/protobuf/pyext/descriptor.cc b/python/google/protobuf/pyext/descriptor.cc index a875a7be..07550706 100644 --- a/python/google/protobuf/pyext/descriptor.cc +++ b/python/google/protobuf/pyext/descriptor.cc @@ -92,11 +92,10 @@ PyObject* PyString_FromCppString(const string& str) { // TODO(amauryfa): Change the proto2 compiler to remove the assignments, and // remove this hack. bool _CalledFromGeneratedFile(int stacklevel) { - PyThreadState *state = PyThreadState_GET(); - if (state == NULL) { - return false; - } - PyFrameObject* frame = state->frame; +#ifndef PYPY_VERSION + // This check is not critical and is somewhat difficult to implement correctly + // in PyPy. + PyFrameObject* frame = PyEval_GetFrame(); if (frame == NULL) { return false; } @@ -130,6 +129,7 @@ bool _CalledFromGeneratedFile(int stacklevel) { // Filename is not ending with _pb2. return false; } +#endif return true; } diff --git a/python/google/protobuf/pyext/descriptor_database.cc b/python/google/protobuf/pyext/descriptor_database.cc index 514722b4..daa40cc7 100644 --- a/python/google/protobuf/pyext/descriptor_database.cc +++ b/python/google/protobuf/pyext/descriptor_database.cc @@ -64,6 +64,9 @@ static bool GetFileDescriptorProto(PyObject* py_descriptor, } return false; } + if (py_descriptor == Py_None) { + return false; + } const Descriptor* filedescriptor_descriptor = FileDescriptorProto::default_instance().GetDescriptor(); CMessage* message = reinterpret_cast(py_descriptor); diff --git a/python/google/protobuf/pyext/extension_dict.h b/python/google/protobuf/pyext/extension_dict.h index d92cf956..1e7f6f7b 100644 --- a/python/google/protobuf/pyext/extension_dict.h +++ b/python/google/protobuf/pyext/extension_dict.h @@ -48,7 +48,7 @@ class Message; class FieldDescriptor; #ifdef _SHARED_PTR_H -using std::shared_ptr; +using shared_ptr; #else using internal::shared_ptr; #endif diff --git a/python/google/protobuf/pyext/map_container.h b/python/google/protobuf/pyext/map_container.h index ddf94be7..27ee6dbd 100644 --- a/python/google/protobuf/pyext/map_container.h +++ b/python/google/protobuf/pyext/map_container.h @@ -47,7 +47,7 @@ namespace protobuf { class Message; #ifdef _SHARED_PTR_H -using std::shared_ptr; +using shared_ptr; #else using internal::shared_ptr; #endif diff --git a/python/google/protobuf/pyext/message.cc b/python/google/protobuf/pyext/message.cc index 60ec9c1b..a8248888 100644 --- a/python/google/protobuf/pyext/message.cc +++ b/python/google/protobuf/pyext/message.cc @@ -1851,8 +1851,12 @@ static PyObject* ToStr(CMessage* self) { PyObject* MergeFrom(CMessage* self, PyObject* arg) { CMessage* other_message; - if (!PyObject_TypeCheck(reinterpret_cast(arg), &CMessage_Type)) { - PyErr_SetString(PyExc_TypeError, "Must be a message"); + if (!PyObject_TypeCheck(arg, &CMessage_Type)) { + PyErr_Format(PyExc_TypeError, + "Parameter to MergeFrom() must be instance of same class: " + "expected %s got %s.", + self->message->GetDescriptor()->full_name().c_str(), + Py_TYPE(arg)->tp_name); return NULL; } @@ -1860,8 +1864,8 @@ PyObject* MergeFrom(CMessage* self, PyObject* arg) { if (other_message->message->GetDescriptor() != self->message->GetDescriptor()) { PyErr_Format(PyExc_TypeError, - "Tried to merge from a message with a different type. " - "to: %s, from: %s", + "Parameter to MergeFrom() must be instance of same class: " + "expected %s got %s.", self->message->GetDescriptor()->full_name().c_str(), other_message->message->GetDescriptor()->full_name().c_str()); return NULL; @@ -1879,8 +1883,12 @@ PyObject* MergeFrom(CMessage* self, PyObject* arg) { static PyObject* CopyFrom(CMessage* self, PyObject* arg) { CMessage* other_message; - if (!PyObject_TypeCheck(reinterpret_cast(arg), &CMessage_Type)) { - PyErr_SetString(PyExc_TypeError, "Must be a message"); + if (!PyObject_TypeCheck(arg, &CMessage_Type)) { + PyErr_Format(PyExc_TypeError, + "Parameter to CopyFrom() must be instance of same class: " + "expected %s got %s.", + self->message->GetDescriptor()->full_name().c_str(), + Py_TYPE(arg)->tp_name); return NULL; } @@ -1893,8 +1901,8 @@ static PyObject* CopyFrom(CMessage* self, PyObject* arg) { if (other_message->message->GetDescriptor() != self->message->GetDescriptor()) { PyErr_Format(PyExc_TypeError, - "Tried to copy from a message with a different type. " - "to: %s, from: %s", + "Parameter to CopyFrom() must be instance of same class: " + "expected %s got %s.", self->message->GetDescriptor()->full_name().c_str(), other_message->message->GetDescriptor()->full_name().c_str()); return NULL; @@ -2132,7 +2140,11 @@ static PyObject* ListFields(CMessage* self) { PyList_SET_ITEM(all_fields.get(), actual_size, t.release()); ++actual_size; } - Py_SIZE(all_fields.get()) = actual_size; + if (actual_size != fields.size() && + (PyList_SetSlice(all_fields.get(), actual_size, fields.size(), NULL) < + 0)) { + return NULL; + } return all_fields.release(); } @@ -2711,7 +2723,7 @@ int SetAttr(CMessage* self, PyObject* name, PyObject* value) { PyErr_Format(PyExc_AttributeError, "Assignment not allowed " - "(no field \"%s\"in protocol message object).", + "(no field \"%s\" in protocol message object).", PyString_AsString(name)); return -1; } @@ -2728,7 +2740,7 @@ PyTypeObject CMessage_Type = { 0, // tp_getattr 0, // tp_setattr 0, // tp_compare - 0, // tp_repr + (reprfunc)cmessage::ToStr, // tp_repr 0, // tp_as_number 0, // tp_as_sequence 0, // tp_as_mapping diff --git a/python/google/protobuf/pyext/message.h b/python/google/protobuf/pyext/message.h index cc0012e9..c2b62649 100644 --- a/python/google/protobuf/pyext/message.h +++ b/python/google/protobuf/pyext/message.h @@ -53,8 +53,8 @@ class DescriptorPool; class MessageFactory; #ifdef _SHARED_PTR_H -using std::shared_ptr; -using std::string; +using shared_ptr; +using std::std::string; #else using internal::shared_ptr; #endif diff --git a/python/google/protobuf/pyext/repeated_composite_container.h b/python/google/protobuf/pyext/repeated_composite_container.h index 58d37b02..442ce7e3 100644 --- a/python/google/protobuf/pyext/repeated_composite_container.h +++ b/python/google/protobuf/pyext/repeated_composite_container.h @@ -50,7 +50,7 @@ class FieldDescriptor; class Message; #ifdef _SHARED_PTR_H -using std::shared_ptr; +using shared_ptr; #else using internal::shared_ptr; #endif diff --git a/python/google/protobuf/pyext/repeated_scalar_container.h b/python/google/protobuf/pyext/repeated_scalar_container.h index 555e621c..608222e0 100644 --- a/python/google/protobuf/pyext/repeated_scalar_container.h +++ b/python/google/protobuf/pyext/repeated_scalar_container.h @@ -49,7 +49,7 @@ namespace protobuf { class Message; #ifdef _SHARED_PTR_H -using std::shared_ptr; +using shared_ptr; #else using internal::shared_ptr; #endif diff --git a/python/google/protobuf/text_format.py b/python/google/protobuf/text_format.py index 8d256076..a6f41ca8 100755 --- a/python/google/protobuf/text_format.py +++ b/python/google/protobuf/text_format.py @@ -384,7 +384,7 @@ def _MergeField(tokenizer, field are permitted, e.g., the string "foo: 1 foo: 2" for a required/optional field named "foo". allow_unknown_extension: if True, skip over missing extensions and keep - parsing + parsing. Raises: ParseError: In case of text parsing problems. @@ -442,55 +442,39 @@ def _MergeField(tokenizer, 'Message type "%s" has no field named "%s".' % ( message_descriptor.full_name, name)) - if field and field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE: - is_map_entry = _IsMapEntry(field) - tokenizer.TryConsume(':') - - if tokenizer.TryConsume('<'): - end_token = '>' - else: - tokenizer.Consume('{') - end_token = '}' - - if field.label == descriptor.FieldDescriptor.LABEL_REPEATED: - if field.is_extension: - sub_message = message.Extensions[field].add() - elif is_map_entry: - sub_message = field.message_type._concrete_class() - else: - sub_message = getattr(message, field.name).add() + if field: + if not allow_multiple_scalars and field.containing_oneof: + # Check if there's a different field set in this oneof. + # Note that we ignore the case if the same field was set before, and we + # apply allow_multiple_scalars to non-scalar fields as well. + which_oneof = message.WhichOneof(field.containing_oneof.name) + if which_oneof is not None and which_oneof != field.name: + raise tokenizer.ParseErrorPreviousToken( + 'Field "%s" is specified along with field "%s", another member of ' + 'oneof "%s" for message type "%s".' % ( + field.name, which_oneof, field.containing_oneof.name, + message_descriptor.full_name)) + + if field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE: + tokenizer.TryConsume(':') + merger = _MergeMessageField else: - if field.is_extension: - sub_message = message.Extensions[field] - else: - sub_message = getattr(message, field.name) - sub_message.SetInParent() - - while not tokenizer.TryConsume(end_token): - if tokenizer.AtEnd(): - raise tokenizer.ParseErrorPreviousToken('Expected "%s".' % (end_token)) - _MergeField(tokenizer, sub_message, allow_multiple_scalars, - allow_unknown_extension) - - if is_map_entry: - value_cpptype = field.message_type.fields_by_name['value'].cpp_type - if value_cpptype == descriptor.FieldDescriptor.CPPTYPE_MESSAGE: - value = getattr(message, field.name)[sub_message.key] - value.MergeFrom(sub_message.value) - else: - getattr(message, field.name)[sub_message.key] = sub_message.value - elif field: - tokenizer.Consume(':') - if (field.label == descriptor.FieldDescriptor.LABEL_REPEATED and - tokenizer.TryConsume('[')): + tokenizer.Consume(':') + merger = _MergeScalarField + + if (field.label == descriptor.FieldDescriptor.LABEL_REPEATED + and tokenizer.TryConsume('[')): # Short repeated format, e.g. "foo: [1, 2, 3]" while True: - _MergeScalarField(tokenizer, message, field, allow_multiple_scalars) - if tokenizer.TryConsume(']'): - break + merger(tokenizer, message, field, allow_multiple_scalars, + allow_unknown_extension) + if tokenizer.TryConsume(']'): break tokenizer.Consume(',') + else: - _MergeScalarField(tokenizer, message, field, allow_multiple_scalars) + merger(tokenizer, message, field, allow_multiple_scalars, + allow_unknown_extension) + else: # Proto field is unknown. assert allow_unknown_extension _SkipFieldContents(tokenizer) @@ -585,8 +569,64 @@ def _SkipFieldValue(tokenizer): raise ParseError('Invalid field value: ' + tokenizer.token) -def _MergeScalarField(tokenizer, message, field, allow_multiple_scalars): - """Merges a single protocol message scalar field into a message. +def _MergeMessageField(tokenizer, message, field, allow_multiple_scalars, + allow_unknown_extension): + """Merges a single scalar field into a message. + + Args: + tokenizer: A tokenizer to parse the field value. + message: The message of which field is a member. + field: The descriptor of the field to be merged. + allow_multiple_scalars: Determines if repeated values for a non-repeated + field are permitted, e.g., the string "foo: 1 foo: 2" for a + required/optional field named "foo". + allow_unknown_extension: if True, skip over missing extensions and keep + parsing. + + Raises: + ParseError: In case of text parsing problems. + """ + is_map_entry = _IsMapEntry(field) + + if tokenizer.TryConsume('<'): + end_token = '>' + else: + tokenizer.Consume('{') + end_token = '}' + + if field.label == descriptor.FieldDescriptor.LABEL_REPEATED: + if field.is_extension: + sub_message = message.Extensions[field].add() + elif is_map_entry: + # pylint: disable=protected-access + sub_message = field.message_type._concrete_class() + else: + sub_message = getattr(message, field.name).add() + else: + if field.is_extension: + sub_message = message.Extensions[field] + else: + sub_message = getattr(message, field.name) + sub_message.SetInParent() + + while not tokenizer.TryConsume(end_token): + if tokenizer.AtEnd(): + raise tokenizer.ParseErrorPreviousToken('Expected "%s".' % (end_token,)) + _MergeField(tokenizer, sub_message, allow_multiple_scalars, + allow_unknown_extension) + + if is_map_entry: + value_cpptype = field.message_type.fields_by_name['value'].cpp_type + if value_cpptype == descriptor.FieldDescriptor.CPPTYPE_MESSAGE: + value = getattr(message, field.name)[sub_message.key] + value.MergeFrom(sub_message.value) + else: + getattr(message, field.name)[sub_message.key] = sub_message.value + + +def _MergeScalarField(tokenizer, message, field, allow_multiple_scalars, + allow_unknown_extension): + """Merges a single scalar field into a message. Args: tokenizer: A tokenizer to parse the field value. @@ -595,11 +635,14 @@ def _MergeScalarField(tokenizer, message, field, allow_multiple_scalars): allow_multiple_scalars: Determines if repeated values for a non-repeated field are permitted, e.g., the string "foo: 1 foo: 2" for a required/optional field named "foo". + allow_unknown_extension: Unused, just here for consistency with + _MergeMessageField. Raises: ParseError: In case of text parsing problems. RuntimeError: On runtime errors. """ + _ = allow_unknown_extension value = None if field.type in (descriptor.FieldDescriptor.TYPE_INT32, -- cgit v1.2.3