diff options
author | Adam Cozzette <acozzette@google.com> | 2018-03-13 16:37:29 -0700 |
---|---|---|
committer | Adam Cozzette <acozzette@google.com> | 2018-03-13 16:37:29 -0700 |
commit | 0400cca3236de1ca303af38bf81eab332d042b7c (patch) | |
tree | a8a9b19853f64567c96750a1c7d253926471daa5 /python/google/protobuf/internal | |
parent | 96b535cc2f4f7b7e22a1b8622149f7c26a5a3f63 (diff) |
Integrated internal changes from Google
Diffstat (limited to 'python/google/protobuf/internal')
-rwxr-xr-x | python/google/protobuf/internal/_parameterized.py | 50 | ||||
-rwxr-xr-x | python/google/protobuf/internal/api_implementation.py | 11 | ||||
-rwxr-xr-x | python/google/protobuf/internal/encoder.py | 16 | ||||
-rw-r--r-- | python/google/protobuf/internal/json_format_test.py | 12 | ||||
-rwxr-xr-x | python/google/protobuf/internal/message_test.py | 29 | ||||
-rw-r--r-- | python/google/protobuf/internal/no_package.proto | 12 | ||||
-rwxr-xr-x | python/google/protobuf/internal/text_format_test.py | 93 | ||||
-rw-r--r-- | python/google/protobuf/internal/well_known_types.py | 10 | ||||
-rw-r--r-- | python/google/protobuf/internal/well_known_types_test.py | 16 |
9 files changed, 196 insertions, 53 deletions
diff --git a/python/google/protobuf/internal/_parameterized.py b/python/google/protobuf/internal/_parameterized.py index 23a78f03..f2c0b305 100755 --- a/python/google/protobuf/internal/_parameterized.py +++ b/python/google/protobuf/internal/_parameterized.py @@ -37,8 +37,8 @@ argument tuples. A simple example: - class AdditionExample(parameterized.ParameterizedTestCase): - @parameterized.Parameters( + class AdditionExample(parameterized.TestCase): + @parameterized.parameters( (1, 2, 3), (4, 5, 9), (1, 1, 3)) @@ -54,8 +54,8 @@ fail due to an assertion error (1 + 1 != 3). Parameters for invididual test cases can be tuples (with positional parameters) or dictionaries (with named parameters): - class AdditionExample(parameterized.ParameterizedTestCase): - @parameterized.Parameters( + class AdditionExample(parameterized.TestCase): + @parameterized.parameters( {'op1': 1, 'op2': 2, 'result': 3}, {'op1': 4, 'op2': 5, 'result': 9}, ) @@ -77,13 +77,13 @@ stay the same across several invocations, object representations like '<__main__.Foo object at 0x23d8610>' are turned into '<__main__.Foo>'. For even more descriptive names, -especially in test logs, you can use the NamedParameters decorator. In +especially in test logs, you can use the named_parameters decorator. In this case, only tuples are supported, and the first parameters has to be a string (or an object that returns an apt name when converted via str()): - class NamedExample(parameterized.ParameterizedTestCase): - @parameterized.NamedParameters( + class NamedExample(parameterized.TestCase): + @parameterized.named_parameters( ('Normal', 'aa', 'aaa', True), ('EmptyPrefix', '', 'abc', True), ('BothEmpty', '', '', True)) @@ -103,13 +103,13 @@ from the command line: Parameterized Classes ===================== If invocation arguments are shared across test methods in a single -ParameterizedTestCase class, instead of decorating all test methods +TestCase class, instead of decorating all test methods individually, the class itself can be decorated: - @parameterized.Parameters( + @parameterized.parameters( (1, 2, 3) (4, 5, 9)) - class ArithmeticTest(parameterized.ParameterizedTestCase): + class ArithmeticTest(parameterized.TestCase): def testAdd(self, arg1, arg2, result): self.assertEqual(arg1 + arg2, result) @@ -122,8 +122,8 @@ If parameters should be shared across several test cases, or are dynamically created from other sources, a single non-tuple iterable can be passed into the decorator. This iterable will be used to obtain the test cases: - class AdditionExample(parameterized.ParameterizedTestCase): - @parameterized.Parameters( + class AdditionExample(parameterized.TestCase): + @parameterized.parameters( c.op1, c.op2, c.result for c in testcases ) def testAddition(self, op1, op2, result): @@ -135,8 +135,8 @@ Single-Argument Test Methods If a test method takes only one argument, the single argument does not need to be wrapped into a tuple: - class NegativeNumberExample(parameterized.ParameterizedTestCase): - @parameterized.Parameters( + class NegativeNumberExample(parameterized.TestCase): + @parameterized.parameters( -1, -3, -4, -5 ) def testIsNegative(self, arg): @@ -212,7 +212,7 @@ class _ParameterizedTestIter(object): def __call__(self, *args, **kwargs): raise RuntimeError('You appear to be running a parameterized test case ' 'without having inherited from parameterized.' - 'ParameterizedTestCase. This is bad because none of ' + 'TestCase. This is bad because none of ' 'your test cases are actually being run.') def __iter__(self): @@ -306,7 +306,7 @@ def _ParameterDecorator(naming_type, testcases): return _Apply -def Parameters(*testcases): +def parameters(*testcases): # pylint: disable=invalid-name """A decorator for creating parameterized tests. See the module docstring for a usage example. @@ -321,7 +321,7 @@ def Parameters(*testcases): return _ParameterDecorator(_ARGUMENT_REPR, testcases) -def NamedParameters(*testcases): +def named_parameters(*testcases): # pylint: disable=invalid-name """A decorator for creating parameterized tests. See the module docstring for a usage example. The first element of @@ -348,7 +348,7 @@ class TestGeneratorMetaclass(type): up as tests by the unittest framework. In general, it is supposed to be used in conjunction with the - Parameters decorator. + parameters decorator. """ def __new__(mcs, class_name, bases, dct): @@ -385,8 +385,8 @@ def _UpdateClassDictForParamTestCase(dct, id_suffix, name, iterator): id_suffix[new_name] = getattr(func, '__x_extra_id__', '') -class ParameterizedTestCase(unittest.TestCase): - """Base class for test cases using the Parameters decorator.""" +class TestCase(unittest.TestCase): + """Base class for test cases using the parameters decorator.""" __metaclass__ = TestGeneratorMetaclass def _OriginalName(self): @@ -409,10 +409,10 @@ class ParameterizedTestCase(unittest.TestCase): self._id_suffix.get(self._testMethodName, '')) -def CoopParameterizedTestCase(other_base_class): +def CoopTestCase(other_base_class): """Returns a new base class with a cooperative metaclass base. - This enables the ParameterizedTestCase to be used in combination + This enables the TestCase to be used in combination with other base classes that have custom metaclasses, such as mox.MoxTestBase. @@ -425,7 +425,7 @@ def CoopParameterizedTestCase(other_base_class): from google3.testing.pybase import parameterized - class ExampleTest(parameterized.CoopParameterizedTestCase(mox.MoxTestBase)): + class ExampleTest(parameterized.CoopTestCase(mox.MoxTestBase)): ... Args: @@ -439,5 +439,5 @@ def CoopParameterizedTestCase(other_base_class): (other_base_class.__metaclass__, TestGeneratorMetaclass), {}) return metaclass( - 'CoopParameterizedTestCase', - (other_base_class, ParameterizedTestCase), {}) + 'CoopTestCase', + (other_base_class, TestCase), {}) diff --git a/python/google/protobuf/internal/api_implementation.py b/python/google/protobuf/internal/api_implementation.py index 553fcdb6..ab9e7812 100755 --- a/python/google/protobuf/internal/api_implementation.py +++ b/python/google/protobuf/internal/api_implementation.py @@ -66,10 +66,13 @@ if _api_version < 0: # Still unspecified? from google.protobuf.internal import use_pure_python del use_pure_python # Avoids a pylint error and namespace pollution. except ImportError: - if _proto_extension_modules_exist_in_build: - if sys.version_info[0] >= 3: # Python 3 defaults to C++ impl v2. - _api_version = 2 - # TODO(b/17427486): Make Python 2 default to C++ impl v2. + # TODO(b/74017912): It's unsafe to enable :use_fast_cpp_protos by default; + # it can cause data loss if you have any Python-only extensions to any + # message passed back and forth with C++ code. + # + # TODO(b/17427486): Once that bug is fixed, we want to make both Python 2 + # and Python 3 default to `_api_version = 2` (C++ implementation V2). + pass _default_implementation_type = ( 'python' if _api_version <= 0 else 'cpp') diff --git a/python/google/protobuf/internal/encoder.py b/python/google/protobuf/internal/encoder.py index dc7a8ce8..0d1f49dd 100755 --- a/python/google/protobuf/internal/encoder.py +++ b/python/google/protobuf/internal/encoder.py @@ -372,7 +372,7 @@ def MapSizer(field_descriptor, is_message_map): def _VarintEncoder(): """Return an encoder for a basic varint value (does not include tag).""" - def EncodeVarint(write, value, unused_deterministic): + def EncodeVarint(write, value, unused_deterministic=None): bits = value & 0x7f value >>= 7 while value: @@ -388,7 +388,7 @@ def _SignedVarintEncoder(): """Return an encoder for a basic signed varint value (does not include tag).""" - def EncodeSignedVarint(write, value, unused_deterministic): + def EncodeSignedVarint(write, value, unused_deterministic=None): if value < 0: value += (1 << 64) bits = value & 0x7f @@ -524,14 +524,14 @@ def _StructPackEncoder(wire_type, format): return EncodePackedField elif is_repeated: tag_bytes = TagBytes(field_number, wire_type) - def EncodeRepeatedField(write, value, unused_deterministic): + def EncodeRepeatedField(write, value, unused_deterministic=None): for element in value: write(tag_bytes) write(local_struct_pack(format, element)) return EncodeRepeatedField else: tag_bytes = TagBytes(field_number, wire_type) - def EncodeField(write, value, unused_deterministic): + def EncodeField(write, value, unused_deterministic=None): write(tag_bytes) return write(local_struct_pack(format, value)) return EncodeField @@ -595,7 +595,7 @@ def _FloatingPointEncoder(wire_type, format): return EncodePackedField elif is_repeated: tag_bytes = TagBytes(field_number, wire_type) - def EncodeRepeatedField(write, value, unused_deterministic): + def EncodeRepeatedField(write, value, unused_deterministic=None): for element in value: write(tag_bytes) try: @@ -605,7 +605,7 @@ def _FloatingPointEncoder(wire_type, format): return EncodeRepeatedField else: tag_bytes = TagBytes(field_number, wire_type) - def EncodeField(write, value, unused_deterministic): + def EncodeField(write, value, unused_deterministic=None): write(tag_bytes) try: write(local_struct_pack(format, value)) @@ -662,7 +662,7 @@ def BoolEncoder(field_number, is_repeated, is_packed): return EncodePackedField elif is_repeated: tag_bytes = TagBytes(field_number, wire_format.WIRETYPE_VARINT) - def EncodeRepeatedField(write, value, unused_deterministic): + def EncodeRepeatedField(write, value, unused_deterministic=None): for element in value: write(tag_bytes) if element: @@ -672,7 +672,7 @@ def BoolEncoder(field_number, is_repeated, is_packed): return EncodeRepeatedField else: tag_bytes = TagBytes(field_number, wire_format.WIRETYPE_VARINT) - def EncodeField(write, value, unused_deterministic): + def EncodeField(write, value, unused_deterministic=None): write(tag_bytes) if value: return write(true_byte) diff --git a/python/google/protobuf/internal/json_format_test.py b/python/google/protobuf/internal/json_format_test.py index 19182b7f..d891dce1 100644 --- a/python/google/protobuf/internal/json_format_test.py +++ b/python/google/protobuf/internal/json_format_test.py @@ -983,6 +983,18 @@ class JsonFormatTest(JsonFormatBase): self.assertEqual('{\n"int32Value": 12345\n}', json_format.MessageToJson(message, indent=0)) + def testFormatEnumsAsInts(self): + message = json_format_proto3_pb2.TestMessage() + message.enum_value = json_format_proto3_pb2.BAR + message.repeated_enum_value.append(json_format_proto3_pb2.FOO) + message.repeated_enum_value.append(json_format_proto3_pb2.BAR) + self.assertEqual(json.loads('{\n' + ' "enumValue": 1,\n' + ' "repeatedEnumValue": [0, 1]\n' + '}\n'), + json.loads(json_format.MessageToJson( + message, use_integers_for_enums=True))) + def testParseDict(self): expected = 12345 js_dict = {'int32Value': expected} diff --git a/python/google/protobuf/internal/message_test.py b/python/google/protobuf/internal/message_test.py index 8dae6377..61a56a67 100755 --- a/python/google/protobuf/internal/message_test.py +++ b/python/google/protobuf/internal/message_test.py @@ -99,7 +99,7 @@ def IsNegInf(val): BaseTestCase = testing_refleaks.BaseTestCase -@_parameterized.NamedParameters( +@_parameterized.named_parameters( ('_proto2', unittest_pb2), ('_proto3', unittest_proto3_arena_pb2)) class MessageTest(BaseTestCase): @@ -1694,6 +1694,33 @@ class Proto3Test(BaseTestCase): with self.assertRaises(TypeError): del msg2.map_int32_foreign_message[''] + def testMapMergeFrom(self): + msg = map_unittest_pb2.TestMap() + msg.map_int32_int32[12] = 34 + msg.map_int32_int32[56] = 78 + msg.map_int64_int64[22] = 33 + msg.map_int32_foreign_message[111].c = 5 + msg.map_int32_foreign_message[222].c = 10 + + msg2 = map_unittest_pb2.TestMap() + msg2.map_int32_int32[12] = 55 + msg2.map_int64_int64[88] = 99 + msg2.map_int32_foreign_message[222].c = 15 + msg2.map_int32_foreign_message[222].d = 20 + + msg2.map_int32_int32.MergeFrom(msg.map_int32_int32) + self.assertEqual(34, msg2.map_int32_int32[12]) + self.assertEqual(78, msg2.map_int32_int32[56]) + + msg2.map_int64_int64.MergeFrom(msg.map_int64_int64) + self.assertEqual(33, msg2.map_int64_int64[22]) + self.assertEqual(99, msg2.map_int64_int64[88]) + + msg2.map_int32_foreign_message.MergeFrom(msg.map_int32_foreign_message) + self.assertEqual(5, msg2.map_int32_foreign_message[111].c) + self.assertEqual(10, msg2.map_int32_foreign_message[222].c) + self.assertFalse(msg2.map_int32_foreign_message[222].HasField('d')) + def testMergeFromBadType(self): msg = map_unittest_pb2.TestMap() with self.assertRaisesRegexp( diff --git a/python/google/protobuf/internal/no_package.proto b/python/google/protobuf/internal/no_package.proto new file mode 100644 index 00000000..f6d26735 --- /dev/null +++ b/python/google/protobuf/internal/no_package.proto @@ -0,0 +1,12 @@ +syntax = "proto2"; + +option py_api_version = 2; + +enum NoPackageEnum { + NO_PACKAGE_VALUE_0 = 0; + NO_PACKAGE_VALUE_1 = 1; +} + +message NoPackageMessage { + optional NoPackageEnum no_package_enum = 1; +}
\ No newline at end of file diff --git a/python/google/protobuf/internal/text_format_test.py b/python/google/protobuf/internal/text_format_test.py index ed3445f2..237a2d50 100755 --- a/python/google/protobuf/internal/text_format_test.py +++ b/python/google/protobuf/internal/text_format_test.py @@ -48,6 +48,7 @@ except ImportError: from google.protobuf.internal import _parameterized +from google.protobuf import any_pb2 from google.protobuf import any_test_pb2 from google.protobuf import map_unittest_pb2 from google.protobuf import unittest_mset_pb2 @@ -99,7 +100,7 @@ class TextFormatBase(unittest.TestCase): return text -@_parameterized.Parameters((unittest_pb2), (unittest_proto3_arena_pb2)) +@_parameterized.parameters((unittest_pb2), (unittest_proto3_arena_pb2)) class TextFormatTest(TextFormatBase): def testPrintExotic(self, message_module): @@ -369,6 +370,7 @@ class TextFormatTest(TextFormatBase): def testParseRepeatedScalarShortFormat(self, message_module): message = message_module.TestAllTypes() text = ('repeated_int64: [100, 200];\n' + 'repeated_int64: []\n' 'repeated_int64: 300,\n' 'repeated_string: ["one", "two"];\n') text_format.Parse(text, message) @@ -524,20 +526,68 @@ class OnlyWorksWithProto2RightNowTests(TextFormatBase): def testPrintInIndexOrder(self): message = unittest_pb2.TestFieldOrderings() - message.my_string = '115' + # Fields are listed in index order instead of field number. + message.my_string = 'str' message.my_int = 101 message.my_float = 111 message.optional_nested_message.oo = 0 message.optional_nested_message.bb = 1 + message.Extensions[unittest_pb2.my_extension_string] = 'ext_str0' + # Extensions are listed based on the order of extension number. + # Extension number 12. + message.Extensions[unittest_pb2.TestExtensionOrderings2. + test_ext_orderings2].my_string = 'ext_str2' + # Extension number 13. + message.Extensions[unittest_pb2.TestExtensionOrderings1. + test_ext_orderings1].my_string = 'ext_str1' + # Extension number 14. + message.Extensions[ + unittest_pb2.TestExtensionOrderings2.TestExtensionOrderings3. + test_ext_orderings3].my_string = 'ext_str3' + + # Print in index order. self.CompareToGoldenText( - self.RemoveRedundantZeros(text_format.MessageToString( - message, use_index_order=True)), - 'my_string: \"115\"\nmy_int: 101\nmy_float: 111\n' - 'optional_nested_message {\n oo: 0\n bb: 1\n}\n') + self.RemoveRedundantZeros( + text_format.MessageToString(message, use_index_order=True)), + 'my_string: "str"\n' + 'my_int: 101\n' + 'my_float: 111\n' + 'optional_nested_message {\n' + ' oo: 0\n' + ' bb: 1\n' + '}\n' + '[protobuf_unittest.TestExtensionOrderings2.test_ext_orderings2] {\n' + ' my_string: "ext_str2"\n' + '}\n' + '[protobuf_unittest.TestExtensionOrderings1.test_ext_orderings1] {\n' + ' my_string: "ext_str1"\n' + '}\n' + '[protobuf_unittest.TestExtensionOrderings2.TestExtensionOrderings3' + '.test_ext_orderings3] {\n' + ' my_string: "ext_str3"\n' + '}\n' + '[protobuf_unittest.my_extension_string]: "ext_str0"\n') + # By default, print in field number order. self.CompareToGoldenText( self.RemoveRedundantZeros(text_format.MessageToString(message)), - 'my_int: 101\nmy_string: \"115\"\nmy_float: 111\n' - 'optional_nested_message {\n bb: 1\n oo: 0\n}\n') + 'my_int: 101\n' + 'my_string: "str"\n' + '[protobuf_unittest.TestExtensionOrderings2.test_ext_orderings2] {\n' + ' my_string: "ext_str2"\n' + '}\n' + '[protobuf_unittest.TestExtensionOrderings1.test_ext_orderings1] {\n' + ' my_string: "ext_str1"\n' + '}\n' + '[protobuf_unittest.TestExtensionOrderings2.TestExtensionOrderings3' + '.test_ext_orderings3] {\n' + ' my_string: "ext_str3"\n' + '}\n' + '[protobuf_unittest.my_extension_string]: "ext_str0"\n' + 'my_float: 111\n' + 'optional_nested_message {\n' + ' bb: 1\n' + ' oo: 0\n' + '}\n') def testMergeLinesGolden(self): opened = self.ReadGolden('text_format_unittest_data_oneof_implemented.txt') @@ -970,15 +1020,26 @@ class Proto2Tests(TextFormatBase): '"protobuf_unittest.optional_int32_extension" extensions.'), text_format.Parse, text, message) - def testParseDuplicateNestedMessageScalars(self): + def testParseDuplicateMessages(self): message = unittest_pb2.TestAllTypes() text = ('optional_nested_message { bb: 1 } ' 'optional_nested_message { bb: 2 }') six.assertRaisesRegex(self, text_format.ParseError, ( - '1:65 : Message type "protobuf_unittest.TestAllTypes.NestedMessage" ' - 'should not have multiple "bb" fields.'), text_format.Parse, text, + '1:59 : Message type "protobuf_unittest.TestAllTypes" ' + 'should not have multiple "optional_nested_message" fields.'), + text_format.Parse, text, message) + def testParseDuplicateExtensionMessages(self): + message = unittest_pb2.TestAllExtensions() + text = ('[protobuf_unittest.optional_nested_message_extension]: {} ' + '[protobuf_unittest.optional_nested_message_extension]: {}') + six.assertRaisesRegex(self, text_format.ParseError, ( + '1:114 : Message type "protobuf_unittest.TestAllExtensions" ' + 'should not have multiple ' + '"protobuf_unittest.optional_nested_message_extension" extensions.'), + text_format.Parse, text, message) + def testParseDuplicateScalars(self): message = unittest_pb2.TestAllTypes() text = ('optional_int32: 42 ' 'optional_int32: 67') @@ -1065,6 +1126,14 @@ class Proto3Tests(unittest.TestCase): ' }\n' '}\n') + def testTopAnyMessage(self): + packed_msg = unittest_pb2.OneString() + msg = any_pb2.Any() + msg.Pack(packed_msg) + text = text_format.MessageToString(msg) + other_msg = text_format.Parse(text, any_pb2.Any()) + self.assertEqual(msg, other_msg) + def testPrintMessageExpandAnyRepeated(self): packed_message = unittest_pb2.OneString() message = any_test_pb2.TestAny() @@ -1489,7 +1558,7 @@ class TokenizerTest(unittest.TestCase): # Tests for pretty printer functionality. -@_parameterized.Parameters((unittest_pb2), (unittest_proto3_arena_pb2)) +@_parameterized.parameters((unittest_pb2), (unittest_proto3_arena_pb2)) class PrettyPrinterTest(TextFormatBase): def testPrettyPrintNoMatch(self, message_module): diff --git a/python/google/protobuf/internal/well_known_types.py b/python/google/protobuf/internal/well_known_types.py index 3573770b..37a65cfa 100644 --- a/python/google/protobuf/internal/well_known_types.py +++ b/python/google/protobuf/internal/well_known_types.py @@ -375,6 +375,9 @@ def _CheckDurationValid(seconds, nanos): raise Error( 'Duration is not valid: Nanos {0} must be in range ' '[-999999999, 999999999].'.format(nanos)) + if (nanos < 0 and seconds > 0) or (nanos > 0 and seconds < 0): + raise Error( + 'Duration is not valid: Sign mismatch.') def _RoundTowardZero(value, divider): @@ -649,9 +652,10 @@ def _MergeMessage( raise ValueError('Error: Field {0} in message {1} is not a singular ' 'message field and cannot have sub-fields.'.format( name, source_descriptor.full_name)) - _MergeMessage( - child, getattr(source, name), getattr(destination, name), - replace_message, replace_repeated) + if source.HasField(name): + _MergeMessage( + child, getattr(source, name), getattr(destination, name), + replace_message, replace_repeated) continue if field.label == FieldDescriptor.LABEL_REPEATED: if replace_repeated: diff --git a/python/google/protobuf/internal/well_known_types_test.py b/python/google/protobuf/internal/well_known_types_test.py index 573bc37d..965940b2 100644 --- a/python/google/protobuf/internal/well_known_types_test.py +++ b/python/google/protobuf/internal/well_known_types_test.py @@ -345,6 +345,12 @@ class TimeUtilTest(TimeUtilTestBase): r'Duration is not valid\: Nanos 1000000000 must be in range' r' \[-999999999\, 999999999\].', message.ToJsonString) + message.seconds = -1 + message.nanos = 1 + self.assertRaisesRegexp( + well_known_types.Error, + r'Duration is not valid\: Sign mismatch.', + message.ToJsonString) class FieldMaskTest(unittest.TestCase): @@ -599,6 +605,16 @@ class FieldMaskTest(unittest.TestCase): self.assertEqual(1, len(nested_dst.payload.repeated_int32)) self.assertEqual(1234, nested_dst.payload.repeated_int32[0]) + # Test Merge oneof field. + new_msg = unittest_pb2.TestOneof2() + dst = unittest_pb2.TestOneof2() + dst.foo_message.qux_int = 1 + mask = field_mask_pb2.FieldMask() + mask.FromJsonString('fooMessage,fooLazyMessage.quxInt') + mask.MergeMessage(new_msg, dst) + self.assertTrue(dst.HasField('foo_message')) + self.assertFalse(dst.HasField('foo_lazy_message')) + def testMergeErrors(self): src = unittest_pb2.TestAllTypes() dst = unittest_pb2.TestAllTypes() |