aboutsummaryrefslogtreecommitdiffhomepage
path: root/python/google/protobuf/internal
diff options
context:
space:
mode:
Diffstat (limited to 'python/google/protobuf/internal')
-rwxr-xr-xpython/google/protobuf/internal/_parameterized.py50
-rwxr-xr-xpython/google/protobuf/internal/api_implementation.py11
-rwxr-xr-xpython/google/protobuf/internal/containers.py4
-rw-r--r--python/google/protobuf/internal/descriptor_database_test.py21
-rw-r--r--python/google/protobuf/internal/descriptor_pool_test.py56
-rwxr-xr-xpython/google/protobuf/internal/descriptor_test.py13
-rwxr-xr-xpython/google/protobuf/internal/encoder.py19
-rw-r--r--python/google/protobuf/internal/json_format_test.py15
-rwxr-xr-xpython/google/protobuf/internal/message_test.py45
-rw-r--r--python/google/protobuf/internal/no_package.proto10
-rwxr-xr-xpython/google/protobuf/internal/text_format_test.py100
-rw-r--r--python/google/protobuf/internal/well_known_types.py10
-rw-r--r--python/google/protobuf/internal/well_known_types_test.py18
13 files changed, 299 insertions, 73 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/containers.py b/python/google/protobuf/internal/containers.py
index 68be9e54..c6a3692a 100755
--- a/python/google/protobuf/internal/containers.py
+++ b/python/google/protobuf/internal/containers.py
@@ -549,10 +549,10 @@ class MessageMap(MutableMapping):
self._values = {}
def __getitem__(self, key):
+ key = self._key_checker.CheckValue(key)
try:
return self._values[key]
except KeyError:
- key = self._key_checker.CheckValue(key)
new_element = self._message_descriptor._concrete_class()
new_element._SetListener(self._message_listener)
self._values[key] = new_element
@@ -584,12 +584,14 @@ class MessageMap(MutableMapping):
return default
def __contains__(self, item):
+ item = self._key_checker.CheckValue(item)
return item in self._values
def __setitem__(self, key, value):
raise ValueError('May not set values directly, call my_map[key].foo = 5')
def __delitem__(self, key):
+ key = self._key_checker.CheckValue(key)
del self._values[key]
self._message_listener.Modified()
diff --git a/python/google/protobuf/internal/descriptor_database_test.py b/python/google/protobuf/internal/descriptor_database_test.py
index 1f1a3db9..f97477b3 100644
--- a/python/google/protobuf/internal/descriptor_database_test.py
+++ b/python/google/protobuf/internal/descriptor_database_test.py
@@ -38,6 +38,7 @@ try:
import unittest2 as unittest #PY26
except ImportError:
import unittest
+import warnings
from google.protobuf import unittest_pb2
from google.protobuf import descriptor_pb2
@@ -98,6 +99,26 @@ class DescriptorDatabaseTest(unittest.TestCase):
db.FindFileContainingSymbol,
'protobuf_unittest.NoneMessage')
+ def testConflictRegister(self):
+ db = descriptor_database.DescriptorDatabase()
+ unittest_fd = descriptor_pb2.FileDescriptorProto.FromString(
+ unittest_pb2.DESCRIPTOR.serialized_pb)
+ db.Add(unittest_fd)
+ conflict_fd = descriptor_pb2.FileDescriptorProto.FromString(
+ unittest_pb2.DESCRIPTOR.serialized_pb)
+ conflict_fd.name = 'other_file'
+ with warnings.catch_warnings(record=True) as w:
+ # Cause all warnings to always be triggered.
+ warnings.simplefilter('always')
+ db.Add(conflict_fd)
+ self.assertTrue(len(w))
+ self.assertIs(w[0].category, RuntimeWarning)
+ self.assertIn('Conflict register for file "other_file": ',
+ str(w[0].message))
+ self.assertIn('already defined in file '
+ '"google/protobuf/unittest.proto"',
+ str(w[0].message))
+
if __name__ == '__main__':
unittest.main()
diff --git a/python/google/protobuf/internal/descriptor_pool_test.py b/python/google/protobuf/internal/descriptor_pool_test.py
index 15c857bb..2cbf7813 100644
--- a/python/google/protobuf/internal/descriptor_pool_test.py
+++ b/python/google/protobuf/internal/descriptor_pool_test.py
@@ -34,8 +34,10 @@
__author__ = 'matthewtoia@google.com (Matt Toia)'
+import copy
import os
import sys
+import warnings
try:
import unittest2 as unittest #PY26
@@ -119,6 +121,14 @@ class DescriptorPoolTestBase(object):
self.assertEqual('google/protobuf/unittest.proto',
file_desc5.name)
+ # Tests the generated pool.
+ assert descriptor_pool.Default().FindFileContainingSymbol(
+ 'google.protobuf.python.internal.Factory2Message.one_more_field')
+ assert descriptor_pool.Default().FindFileContainingSymbol(
+ 'google.protobuf.python.internal.another_field')
+ assert descriptor_pool.Default().FindFileContainingSymbol(
+ 'protobuf_unittest.TestService')
+
def testFindFileContainingSymbolFailure(self):
with self.assertRaises(KeyError):
self.pool.FindFileContainingSymbol('Does not exist')
@@ -492,6 +502,52 @@ class DescriptorPoolTestBase(object):
TEST1_FILE.CheckFile(self, self.pool)
TEST2_FILE.CheckFile(self, self.pool)
+ def testConflictRegister(self):
+ if isinstance(self, SecondaryDescriptorFromDescriptorDB):
+ if api_implementation.Type() == 'cpp':
+ # Cpp extension cannot call Add on a DescriptorPool
+ # that uses a DescriptorDatabase.
+ # TODO(jieluo): Fix python and cpp extension diff.
+ return
+ unittest_fd = descriptor_pb2.FileDescriptorProto.FromString(
+ unittest_pb2.DESCRIPTOR.serialized_pb)
+ conflict_fd = copy.deepcopy(unittest_fd)
+ conflict_fd.name = 'other_file'
+ if api_implementation.Type() == 'cpp':
+ try:
+ self.pool.Add(unittest_fd)
+ self.pool.Add(conflict_fd)
+ except TypeError:
+ pass
+ else:
+ with warnings.catch_warnings(record=True) as w:
+ # Cause all warnings to always be triggered.
+ warnings.simplefilter('always')
+ pool = copy.deepcopy(self.pool)
+ # No warnings to add the same descriptors.
+ file_descriptor = unittest_pb2.DESCRIPTOR
+ pool.AddDescriptor(
+ file_descriptor.message_types_by_name['TestAllTypes'])
+ pool.AddEnumDescriptor(
+ file_descriptor.enum_types_by_name['ForeignEnum'])
+ pool.AddServiceDescriptor(
+ file_descriptor.services_by_name['TestService'])
+ pool.AddExtensionDescriptor(
+ file_descriptor.extensions_by_name['optional_int32_extension'])
+ self.assertEqual(len(w), 0)
+ # Check warnings for conflict descriptors with the same name.
+ pool.Add(unittest_fd)
+ pool.Add(conflict_fd)
+ pool.FindFileByName(unittest_fd.name)
+ pool.FindFileByName(conflict_fd.name)
+ self.assertTrue(len(w))
+ self.assertIs(w[0].category, RuntimeWarning)
+ self.assertIn('Conflict register for file "other_file": ',
+ str(w[0].message))
+ self.assertIn('already defined in file '
+ '"google/protobuf/unittest.proto"',
+ str(w[0].message))
+
class DefaultDescriptorPoolTest(DescriptorPoolTestBase, unittest.TestCase):
diff --git a/python/google/protobuf/internal/descriptor_test.py b/python/google/protobuf/internal/descriptor_test.py
index f1d5934e..02a43d15 100755
--- a/python/google/protobuf/internal/descriptor_test.py
+++ b/python/google/protobuf/internal/descriptor_test.py
@@ -742,6 +742,19 @@ class DescriptorCopyToProtoTest(unittest.TestCase):
deprecated: true
>
>
+ field {
+ name: "deprecated_int32_in_oneof"
+ number: 2
+ label: LABEL_OPTIONAL
+ type: TYPE_INT32
+ options {
+ deprecated: true
+ }
+ oneof_index: 0
+ }
+ oneof_decl {
+ name: "oneof_fields"
+ }
"""
self._InternalTestCopyToProto(
diff --git a/python/google/protobuf/internal/encoder.py b/python/google/protobuf/internal/encoder.py
index 40c62d67..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
@@ -418,7 +418,8 @@ def _VarintBytes(value):
def TagBytes(field_number, wire_type):
"""Encode the given tag and return the bytes. Only called at startup."""
- return six.binary_type( _VarintBytes(wire_format.PackTag(field_number, wire_type)) )
+ return six.binary_type(
+ _VarintBytes(wire_format.PackTag(field_number, wire_type)))
# --------------------------------------------------------------------
# As with sizers (see above), we have a number of common encoder
@@ -523,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
@@ -594,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:
@@ -604,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))
@@ -661,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:
@@ -671,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..7f649406 100644
--- a/python/google/protobuf/internal/json_format_test.py
+++ b/python/google/protobuf/internal/json_format_test.py
@@ -791,9 +791,6 @@ class JsonFormatTest(JsonFormatBase):
json_format.Parse(text, parsed_message, ignore_unknown_fields=True)
def testDuplicateField(self):
- # Duplicate key check is not supported for python2.6
- if sys.version_info < (2, 7):
- return
self.CheckError('{"int32Value": 1,\n"int32Value":2}',
'Failed to load JSON: duplicate key int32Value.')
@@ -983,6 +980,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 a303b1aa..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):
@@ -1480,12 +1480,8 @@ class Proto3Test(BaseTestCase):
submsg = msg.map_int32_foreign_message[5]
self.assertIs(submsg, msg.map_int32_foreign_message.get(5))
- # TODO(jieluo): Fix python and cpp extension diff.
- if api_implementation.Type() == 'cpp':
- with self.assertRaises(TypeError):
- msg.map_int32_foreign_message.get('')
- else:
- self.assertEqual(None, msg.map_int32_foreign_message.get(''))
+ with self.assertRaises(TypeError):
+ msg.map_int32_foreign_message.get('')
def testScalarMap(self):
msg = map_unittest_pb2.TestMap()
@@ -1695,12 +1691,35 @@ class Proto3Test(BaseTestCase):
del msg2.map_int32_foreign_message[222]
self.assertFalse(222 in msg2.map_int32_foreign_message)
- if api_implementation.Type() == 'cpp':
- with self.assertRaises(TypeError):
- del msg2.map_int32_foreign_message['']
- else:
- with self.assertRaises(KeyError):
- del msg2.map_int32_foreign_message['']
+ 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()
diff --git a/python/google/protobuf/internal/no_package.proto b/python/google/protobuf/internal/no_package.proto
new file mode 100644
index 00000000..3546dcc3
--- /dev/null
+++ b/python/google/protobuf/internal/no_package.proto
@@ -0,0 +1,10 @@
+syntax = "proto2";
+
+enum NoPackageEnum {
+ NO_PACKAGE_VALUE_0 = 0;
+ NO_PACKAGE_VALUE_1 = 1;
+}
+
+message NoPackageMessage {
+ optional NoPackageEnum no_package_enum = 1;
+}
diff --git a/python/google/protobuf/internal/text_format_test.py b/python/google/protobuf/internal/text_format_test.py
index a52f133f..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')
@@ -828,6 +878,10 @@ class Proto2Tests(TextFormatBase):
' }\n'
' }\n'
' [unknown_extension]: 5\n'
+ ' [unknown_extension_with_number_field] {\n'
+ ' 1: "some_field"\n'
+ ' 2: -0.451\n'
+ ' }\n'
'}\n')
text_format.Parse(text, message, allow_unknown_extension=True)
golden = 'message_set {\n}\n'
@@ -894,7 +948,6 @@ class Proto2Tests(TextFormatBase):
message = unittest_mset_pb2.TestMessageSetContainer()
malformed = ('message_set {\n'
' unknown_field: true\n'
- ' \n' # Missing '>' here.
'}\n')
six.assertRaisesRegex(self,
text_format.ParseError,
@@ -906,7 +959,7 @@ class Proto2Tests(TextFormatBase):
message,
allow_unknown_extension=True)
- # Parse known extension correcty.
+ # Parse known extension correctly.
message = unittest_mset_pb2.TestMessageSetContainer()
text = ('message_set {\n'
' [protobuf_unittest.TestMessageSetExtension1] {\n'
@@ -967,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')
@@ -1062,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()
@@ -1486,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 291fe4e8..965940b2 100644
--- a/python/google/protobuf/internal/well_known_types_test.py
+++ b/python/google/protobuf/internal/well_known_types_test.py
@@ -101,7 +101,7 @@ class TimeUtilTest(TimeUtilTestBase):
message.FromJsonString('1970-01-01T00:00:00.1Z')
self.assertEqual(0, message.seconds)
self.assertEqual(100000000, message.nanos)
- # Parsing accpets offsets.
+ # Parsing accepts offsets.
message.FromJsonString('1970-01-01T00:00:00-08:00')
self.assertEqual(8 * 3600, message.seconds)
self.assertEqual(0, message.nanos)
@@ -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()