1# Protocol Buffers - Google's data interchange format 2# Copyright 2008 Google Inc. All rights reserved. 3# 4# Use of this source code is governed by a BSD-style 5# license that can be found in the LICENSE file or at 6# https://developers.google.com/open-source/licenses/bsd 7 8"""Tests for google.protobuf.descriptor_pool.""" 9 10__author__ = 'matthewtoia@google.com (Matt Toia)' 11 12import copy 13import unittest 14import warnings 15 16from google.protobuf import descriptor 17from google.protobuf import descriptor_database 18from google.protobuf import descriptor_pb2 19from google.protobuf import descriptor_pool 20from google.protobuf import message_factory 21from google.protobuf import symbol_database 22from google.protobuf.internal import api_implementation 23from google.protobuf.internal import descriptor_pool_test1_pb2 24from google.protobuf.internal import descriptor_pool_test2_pb2 25from google.protobuf.internal import factory_test1_pb2 26from google.protobuf.internal import factory_test2_pb2 27from google.protobuf.internal import file_options_test_pb2 28from google.protobuf.internal import more_messages_pb2 29from google.protobuf.internal import no_package_pb2 30from google.protobuf.internal import testing_refleaks 31 32from google.protobuf import duration_pb2 33from google.protobuf import struct_pb2 34from google.protobuf import timestamp_pb2 35from google.protobuf import unittest_features_pb2 36from google.protobuf import unittest_import_pb2 37from google.protobuf import unittest_import_public_pb2 38from google.protobuf import unittest_pb2 39 40# pyformat: disable 41# pyformat: enable 42 43 44warnings.simplefilter('error', DeprecationWarning) 45 46 47class DescriptorPoolTestBase(object): 48 49 def testFindFileByName(self): 50 name1 = 'google/protobuf/internal/factory_test1.proto' 51 file_desc1 = self.pool.FindFileByName(name1) 52 self.assertIsInstance(file_desc1, descriptor.FileDescriptor) 53 self.assertEqual(name1, file_desc1.name) 54 self.assertEqual('google.protobuf.python.internal', file_desc1.package) 55 self.assertIn('Factory1Message', file_desc1.message_types_by_name) 56 57 name2 = 'google/protobuf/internal/factory_test2.proto' 58 file_desc2 = self.pool.FindFileByName(name2) 59 self.assertIsInstance(file_desc2, descriptor.FileDescriptor) 60 self.assertEqual(name2, file_desc2.name) 61 self.assertEqual('google.protobuf.python.internal', file_desc2.package) 62 self.assertIn('Factory2Message', file_desc2.message_types_by_name) 63 64 def testFindFileByNameFailure(self): 65 with self.assertRaises(KeyError): 66 self.pool.FindFileByName('Does not exist') 67 68 def testFindFileContainingSymbol(self): 69 file_desc1 = self.pool.FindFileContainingSymbol( 70 'google.protobuf.python.internal.Factory1Message') 71 self.assertIsInstance(file_desc1, descriptor.FileDescriptor) 72 self.assertEqual('google/protobuf/internal/factory_test1.proto', 73 file_desc1.name) 74 self.assertEqual('google.protobuf.python.internal', file_desc1.package) 75 self.assertIn('Factory1Message', file_desc1.message_types_by_name) 76 77 file_desc2 = self.pool.FindFileContainingSymbol( 78 'google.protobuf.python.internal.Factory2Message') 79 self.assertIsInstance(file_desc2, descriptor.FileDescriptor) 80 self.assertEqual('google/protobuf/internal/factory_test2.proto', 81 file_desc2.name) 82 self.assertEqual('google.protobuf.python.internal', file_desc2.package) 83 self.assertIn('Factory2Message', file_desc2.message_types_by_name) 84 85 # Tests top level extension. 86 file_desc3 = self.pool.FindFileContainingSymbol( 87 'google.protobuf.python.internal.another_field') 88 self.assertIsInstance(file_desc3, descriptor.FileDescriptor) 89 self.assertEqual('google/protobuf/internal/factory_test2.proto', 90 file_desc3.name) 91 92 # Tests nested extension inside a message. 93 file_desc4 = self.pool.FindFileContainingSymbol( 94 'google.protobuf.python.internal.Factory2Message.one_more_field') 95 self.assertIsInstance(file_desc4, descriptor.FileDescriptor) 96 self.assertEqual('google/protobuf/internal/factory_test2.proto', 97 file_desc4.name) 98 99 file_desc5 = self.pool.FindFileContainingSymbol( 100 'protobuf_unittest.TestService') 101 self.assertIsInstance(file_desc5, descriptor.FileDescriptor) 102 self.assertEqual('google/protobuf/unittest.proto', 103 file_desc5.name) 104 # Tests the generated pool. 105 assert descriptor_pool.Default().FindFileContainingSymbol( 106 'google.protobuf.python.internal.Factory2Message.one_more_field') 107 assert descriptor_pool.Default().FindFileContainingSymbol( 108 'google.protobuf.python.internal.another_field') 109 assert descriptor_pool.Default().FindFileContainingSymbol( 110 'protobuf_unittest.TestService') 111 112 # Can find field. 113 file_desc6 = self.pool.FindFileContainingSymbol( 114 'google.protobuf.python.internal.Factory1Message.list_value') 115 self.assertIsInstance(file_desc6, descriptor.FileDescriptor) 116 self.assertEqual('google/protobuf/internal/factory_test1.proto', 117 file_desc6.name) 118 119 # Can find top level Enum value. 120 file_desc7 = self.pool.FindFileContainingSymbol( 121 'google.protobuf.python.internal.FACTORY_1_VALUE_0') 122 self.assertIsInstance(file_desc7, descriptor.FileDescriptor) 123 self.assertEqual('google/protobuf/internal/factory_test1.proto', 124 file_desc7.name) 125 126 # Can find nested Enum value. 127 file_desc8 = self.pool.FindFileContainingSymbol( 128 'protobuf_unittest.TestAllTypes.FOO') 129 self.assertIsInstance(file_desc8, descriptor.FileDescriptor) 130 self.assertEqual('google/protobuf/unittest.proto', 131 file_desc8.name) 132 133 # TODO: Add tests for no package when b/13860351 is fixed. 134 135 self.assertRaises(KeyError, self.pool.FindFileContainingSymbol, 136 'google.protobuf.python.internal.Factory1Message.none_field') 137 138 def testCrossFileMessageTypesByName(self): 139 self.assertIs( 140 descriptor_pool_test1_pb2.DescriptorPoolTest1.DESCRIPTOR, 141 descriptor_pool_test1_pb2.DESCRIPTOR.message_types_by_name[ 142 'DescriptorPoolTest1' 143 ], 144 ) 145 with self.assertRaises(KeyError): 146 descriptor_pool_test2_pb2.DESCRIPTOR.message_types_by_name[ 147 'DescriptorPoolTest1' 148 ] 149 150 def testCrossFileEnumTypesByName(self): 151 self.assertIs( 152 descriptor_pool_test1_pb2.TopLevelEnumTest1.DESCRIPTOR, 153 descriptor_pool_test1_pb2.DESCRIPTOR.enum_types_by_name[ 154 'TopLevelEnumTest1' 155 ], 156 ) 157 with self.assertRaises(KeyError): 158 descriptor_pool_test2_pb2.DESCRIPTOR.enum_types_by_name[ 159 'TopLevelEnumTest1' 160 ] 161 162 def testCrossFileExtensionsByName(self): 163 self.assertIs( 164 descriptor_pool_test1_pb2.top_level_extension_test1, 165 descriptor_pool_test1_pb2.DESCRIPTOR.extensions_by_name[ 166 'top_level_extension_test1' 167 ], 168 ) 169 with self.assertRaises(KeyError): 170 descriptor_pool_test2_pb2.DESCRIPTOR.extensions_by_name[ 171 'top_level_extension_test1' 172 ] 173 174 def testCrossFileServicesByName(self): 175 descriptor_pool_test1_pb2.DESCRIPTOR.services_by_name[ 176 'DescriptorPoolTestService' 177 ], 178 with self.assertRaises(KeyError): 179 descriptor_pool_test2_pb2.DESCRIPTOR.services_by_name[ 180 'DescriptorPoolTestService' 181 ] 182 183 def testFindFileContainingSymbolFailure(self): 184 with self.assertRaises(KeyError): 185 self.pool.FindFileContainingSymbol('Does not exist') 186 187 def testFindMessageTypeByName(self): 188 msg1 = self.pool.FindMessageTypeByName( 189 'google.protobuf.python.internal.Factory1Message') 190 self.assertIsInstance(msg1, descriptor.Descriptor) 191 self.assertEqual('Factory1Message', msg1.name) 192 self.assertEqual('google.protobuf.python.internal.Factory1Message', 193 msg1.full_name) 194 self.assertEqual(None, msg1.containing_type) 195 self.assertFalse(msg1.has_options) 196 197 nested_msg1 = msg1.nested_types[0] 198 self.assertEqual('NestedFactory1Message', nested_msg1.name) 199 self.assertEqual(msg1, nested_msg1.containing_type) 200 201 nested_enum1 = msg1.enum_types[0] 202 self.assertEqual('NestedFactory1Enum', nested_enum1.name) 203 self.assertEqual(msg1, nested_enum1.containing_type) 204 205 self.assertEqual(nested_msg1, msg1.fields_by_name[ 206 'nested_factory_1_message'].message_type) 207 self.assertEqual(nested_enum1, msg1.fields_by_name[ 208 'nested_factory_1_enum'].enum_type) 209 210 msg2 = self.pool.FindMessageTypeByName( 211 'google.protobuf.python.internal.Factory2Message') 212 self.assertIsInstance(msg2, descriptor.Descriptor) 213 self.assertEqual('Factory2Message', msg2.name) 214 self.assertEqual('google.protobuf.python.internal.Factory2Message', 215 msg2.full_name) 216 self.assertIsNone(msg2.containing_type) 217 218 nested_msg2 = msg2.nested_types[0] 219 self.assertEqual('NestedFactory2Message', nested_msg2.name) 220 self.assertEqual(msg2, nested_msg2.containing_type) 221 222 nested_enum2 = msg2.enum_types[0] 223 self.assertEqual('NestedFactory2Enum', nested_enum2.name) 224 self.assertEqual(msg2, nested_enum2.containing_type) 225 226 self.assertEqual(nested_msg2, msg2.fields_by_name[ 227 'nested_factory_2_message'].message_type) 228 self.assertEqual(nested_enum2, msg2.fields_by_name[ 229 'nested_factory_2_enum'].enum_type) 230 231 self.assertTrue(msg2.fields_by_name['int_with_default'].has_default_value) 232 self.assertEqual( 233 1776, msg2.fields_by_name['int_with_default'].default_value) 234 235 self.assertTrue( 236 msg2.fields_by_name['double_with_default'].has_default_value) 237 self.assertEqual( 238 9.99, msg2.fields_by_name['double_with_default'].default_value) 239 240 self.assertTrue( 241 msg2.fields_by_name['string_with_default'].has_default_value) 242 self.assertEqual( 243 'hello world', msg2.fields_by_name['string_with_default'].default_value) 244 245 self.assertTrue(msg2.fields_by_name['bool_with_default'].has_default_value) 246 self.assertFalse(msg2.fields_by_name['bool_with_default'].default_value) 247 248 self.assertTrue(msg2.fields_by_name['enum_with_default'].has_default_value) 249 self.assertEqual( 250 1, msg2.fields_by_name['enum_with_default'].default_value) 251 252 msg3 = self.pool.FindMessageTypeByName( 253 'google.protobuf.python.internal.Factory2Message.NestedFactory2Message') 254 self.assertEqual(nested_msg2, msg3) 255 256 self.assertTrue(msg2.fields_by_name['bytes_with_default'].has_default_value) 257 self.assertEqual( 258 b'a\xfb\x00c', 259 msg2.fields_by_name['bytes_with_default'].default_value) 260 261 self.assertEqual(1, len(msg2.oneofs)) 262 self.assertEqual(1, len(msg2.oneofs_by_name)) 263 self.assertEqual(2, len(msg2.oneofs[0].fields)) 264 for name in ['oneof_int', 'oneof_string']: 265 self.assertEqual(msg2.oneofs[0], 266 msg2.fields_by_name[name].containing_oneof) 267 self.assertIn(msg2.fields_by_name[name], msg2.oneofs[0].fields) 268 269 def testFindTypeErrors(self): 270 self.assertRaises(TypeError, self.pool.FindExtensionByNumber, '') 271 self.assertRaises(KeyError, self.pool.FindMethodByName, '') 272 273 # TODO: Fix python to raise correct errors. 274 if api_implementation.Type() == 'python': 275 error_type = AttributeError 276 else: 277 error_type = TypeError 278 self.assertRaises(error_type, self.pool.FindMessageTypeByName, 0) 279 self.assertRaises(error_type, self.pool.FindFieldByName, 0) 280 self.assertRaises(error_type, self.pool.FindExtensionByName, 0) 281 self.assertRaises(error_type, self.pool.FindEnumTypeByName, 0) 282 self.assertRaises(error_type, self.pool.FindOneofByName, 0) 283 self.assertRaises(error_type, self.pool.FindServiceByName, 0) 284 self.assertRaises(error_type, self.pool.FindMethodByName, 0) 285 self.assertRaises(error_type, self.pool.FindFileContainingSymbol, 0) 286 if api_implementation.Type() == 'python': 287 error_type = KeyError 288 self.assertRaises(error_type, self.pool.FindFileByName, 0) 289 290 def testFindMessageTypeByNameFailure(self): 291 with self.assertRaises(KeyError): 292 self.pool.FindMessageTypeByName('Does not exist') 293 294 def testFindEnumTypeByName(self): 295 enum1 = self.pool.FindEnumTypeByName( 296 'google.protobuf.python.internal.Factory1Enum') 297 self.assertIsInstance(enum1, descriptor.EnumDescriptor) 298 self.assertEqual(0, enum1.values_by_name['FACTORY_1_VALUE_0'].number) 299 self.assertEqual(1, enum1.values_by_name['FACTORY_1_VALUE_1'].number) 300 self.assertFalse(enum1.has_options) 301 302 nested_enum1 = self.pool.FindEnumTypeByName( 303 'google.protobuf.python.internal.Factory1Message.NestedFactory1Enum') 304 self.assertIsInstance(nested_enum1, descriptor.EnumDescriptor) 305 self.assertEqual( 306 0, nested_enum1.values_by_name['NESTED_FACTORY_1_VALUE_0'].number) 307 self.assertEqual( 308 1, nested_enum1.values_by_name['NESTED_FACTORY_1_VALUE_1'].number) 309 310 enum2 = self.pool.FindEnumTypeByName( 311 'google.protobuf.python.internal.Factory2Enum') 312 self.assertIsInstance(enum2, descriptor.EnumDescriptor) 313 self.assertEqual(0, enum2.values_by_name['FACTORY_2_VALUE_0'].number) 314 self.assertEqual(1, enum2.values_by_name['FACTORY_2_VALUE_1'].number) 315 316 nested_enum2 = self.pool.FindEnumTypeByName( 317 'google.protobuf.python.internal.Factory2Message.NestedFactory2Enum') 318 self.assertIsInstance(nested_enum2, descriptor.EnumDescriptor) 319 self.assertEqual( 320 0, nested_enum2.values_by_name['NESTED_FACTORY_2_VALUE_0'].number) 321 self.assertEqual( 322 1, nested_enum2.values_by_name['NESTED_FACTORY_2_VALUE_1'].number) 323 324 def testFindEnumTypeByNameFailure(self): 325 with self.assertRaises(KeyError): 326 self.pool.FindEnumTypeByName('Does not exist') 327 328 def testFindFieldByName(self): 329 field = self.pool.FindFieldByName( 330 'google.protobuf.python.internal.Factory1Message.list_value') 331 self.assertEqual(field.name, 'list_value') 332 self.assertEqual(field.label, field.LABEL_REPEATED) 333 self.assertFalse(field.has_options) 334 335 with self.assertRaises(KeyError): 336 self.pool.FindFieldByName('Does not exist') 337 338 def testFindOneofByName(self): 339 oneof = self.pool.FindOneofByName( 340 'google.protobuf.python.internal.Factory2Message.oneof_field') 341 self.assertEqual(oneof.name, 'oneof_field') 342 with self.assertRaises(KeyError): 343 self.pool.FindOneofByName('Does not exist') 344 345 def testFindExtensionByName(self): 346 # An extension defined in a message. 347 extension = self.pool.FindExtensionByName( 348 'google.protobuf.python.internal.Factory2Message.one_more_field') 349 self.assertEqual(extension.name, 'one_more_field') 350 # An extension defined at file scope. 351 extension = self.pool.FindExtensionByName( 352 'google.protobuf.python.internal.another_field') 353 self.assertEqual(extension.name, 'another_field') 354 self.assertEqual(extension.number, 1002) 355 with self.assertRaises(KeyError): 356 self.pool.FindFieldByName('Does not exist') 357 358 def testFindAllExtensions(self): 359 factory1_message = self.pool.FindMessageTypeByName( 360 'google.protobuf.python.internal.Factory1Message') 361 factory2_message = self.pool.FindMessageTypeByName( 362 'google.protobuf.python.internal.Factory2Message') 363 # An extension defined in a message. 364 one_more_field = factory2_message.extensions_by_name['one_more_field'] 365 # An extension defined at file scope. 366 factory_test2 = self.pool.FindFileByName( 367 'google/protobuf/internal/factory_test2.proto') 368 another_field = factory_test2.extensions_by_name['another_field'] 369 370 extensions = self.pool.FindAllExtensions(factory1_message) 371 expected_extension_numbers = set([one_more_field, another_field]) 372 self.assertEqual(expected_extension_numbers, set(extensions)) 373 # Verify that mutating the returned list does not affect the pool. 374 extensions.append('unexpected_element') 375 # Get the extensions again, the returned value does not contain the 376 # 'unexpected_element'. 377 extensions = self.pool.FindAllExtensions(factory1_message) 378 self.assertEqual(expected_extension_numbers, set(extensions)) 379 380 def testFindExtensionByNumber(self): 381 factory1_message = self.pool.FindMessageTypeByName( 382 'google.protobuf.python.internal.Factory1Message') 383 # Build factory_test2.proto which will put extensions to the pool 384 self.pool.FindFileByName( 385 'google/protobuf/internal/factory_test2.proto') 386 387 # An extension defined in a message. 388 extension = self.pool.FindExtensionByNumber(factory1_message, 1001) 389 self.assertEqual(extension.name, 'one_more_field') 390 # An extension defined at file scope. 391 extension = self.pool.FindExtensionByNumber(factory1_message, 1002) 392 self.assertEqual(extension.name, 'another_field') 393 with self.assertRaises(KeyError): 394 extension = self.pool.FindExtensionByNumber(factory1_message, 1234567) 395 396 def testExtensionsAreNotFields(self): 397 with self.assertRaises(KeyError): 398 self.pool.FindFieldByName('google.protobuf.python.internal.another_field') 399 with self.assertRaises(KeyError): 400 self.pool.FindFieldByName( 401 'google.protobuf.python.internal.Factory2Message.one_more_field') 402 with self.assertRaises(KeyError): 403 self.pool.FindExtensionByName( 404 'google.protobuf.python.internal.Factory1Message.list_value') 405 406 def testFindService(self): 407 service = self.pool.FindServiceByName('protobuf_unittest.TestService') 408 self.assertEqual(service.full_name, 'protobuf_unittest.TestService') 409 with self.assertRaises(KeyError): 410 self.pool.FindServiceByName('Does not exist') 411 412 method = self.pool.FindMethodByName('protobuf_unittest.TestService.Foo') 413 self.assertIs(method.containing_service, service) 414 with self.assertRaises(KeyError): 415 self.pool.FindMethodByName('protobuf_unittest.TestService.Doesnotexist') 416 417 def testUserDefinedDB(self): 418 db = descriptor_database.DescriptorDatabase() 419 self.pool = descriptor_pool.DescriptorPool(db) 420 db.Add(self.factory_test1_fd) 421 db.Add(self.factory_test2_fd) 422 self.testFindMessageTypeByName() 423 424 def testAddSerializedFile(self): 425 if isinstance(self, SecondaryDescriptorFromDescriptorDB): 426 if api_implementation.Type() != 'python': 427 # Cpp extension cannot call Add on a DescriptorPool 428 # that uses a DescriptorDatabase. 429 # TODO: Fix python and cpp extension diff. 430 return 431 self.pool = descriptor_pool.DescriptorPool() 432 file1 = self.pool.AddSerializedFile( 433 self.factory_test1_fd.SerializeToString()) 434 file2 = self.pool.AddSerializedFile( 435 self.factory_test2_fd.SerializeToString()) 436 self.assertEqual(file1.name, 437 'google/protobuf/internal/factory_test1.proto') 438 self.assertEqual(file2.name, 439 'google/protobuf/internal/factory_test2.proto') 440 self.testFindMessageTypeByName() 441 self.pool.AddSerializedFile(timestamp_pb2.DESCRIPTOR.serialized_pb) 442 self.pool.AddSerializedFile(duration_pb2.DESCRIPTOR.serialized_pb) 443 self.pool.AddSerializedFile(struct_pb2.DESCRIPTOR.serialized_pb) 444 file_json = self.pool.AddSerializedFile( 445 more_messages_pb2.DESCRIPTOR.serialized_pb) 446 field = file_json.message_types_by_name['class'].fields_by_name['int_field'] 447 self.assertEqual(field.json_name, 'json_int') 448 449 def testAddSerializedFileTwice(self): 450 if isinstance(self, SecondaryDescriptorFromDescriptorDB): 451 if api_implementation.Type() != 'python': 452 # Cpp extension cannot call Add on a DescriptorPool 453 # that uses a DescriptorDatabase. 454 # TODO: Fix python and cpp extension diff. 455 return 456 self.pool = descriptor_pool.DescriptorPool() 457 file1_first = self.pool.AddSerializedFile( 458 self.factory_test1_fd.SerializeToString()) 459 file1_again = self.pool.AddSerializedFile( 460 self.factory_test1_fd.SerializeToString()) 461 self.assertIs(file1_first, file1_again) 462 463 def testEnumDefaultValue(self): 464 """Test the default value of enums which don't start at zero.""" 465 def _CheckDefaultValue(file_descriptor): 466 default_value = (file_descriptor 467 .message_types_by_name['DescriptorPoolTest1'] 468 .fields_by_name['nested_enum'] 469 .default_value) 470 self.assertEqual(default_value, 471 descriptor_pool_test1_pb2.DescriptorPoolTest1.BETA) 472 # First check what the generated descriptor contains. 473 _CheckDefaultValue(descriptor_pool_test1_pb2.DESCRIPTOR) 474 # Then check the generated pool. Normally this is the same descriptor. 475 file_descriptor = symbol_database.Default().pool.FindFileByName( 476 'google/protobuf/internal/descriptor_pool_test1.proto') 477 self.assertIs(file_descriptor, descriptor_pool_test1_pb2.DESCRIPTOR) 478 _CheckDefaultValue(file_descriptor) 479 480 if isinstance(self, SecondaryDescriptorFromDescriptorDB): 481 if api_implementation.Type() != 'python': 482 # Cpp extension cannot call Add on a DescriptorPool 483 # that uses a DescriptorDatabase. 484 # TODO: Fix python and cpp extension diff. 485 return 486 # Then check the dynamic pool and its internal DescriptorDatabase. 487 descriptor_proto = descriptor_pb2.FileDescriptorProto.FromString( 488 descriptor_pool_test1_pb2.DESCRIPTOR.serialized_pb) 489 self.pool.Add(descriptor_proto) 490 # And do the same check as above 491 file_descriptor = self.pool.FindFileByName( 492 'google/protobuf/internal/descriptor_pool_test1.proto') 493 _CheckDefaultValue(file_descriptor) 494 495 def testDefaultValueForCustomMessages(self): 496 """Check the value returned by non-existent fields.""" 497 def _CheckValueAndType(value, expected_value, expected_type): 498 self.assertEqual(value, expected_value) 499 self.assertIsInstance(value, expected_type) 500 501 def _CheckDefaultValues(msg): 502 try: 503 int64 = long 504 except NameError: # Python3 505 int64 = int 506 try: 507 unicode_type = unicode 508 except NameError: # Python3 509 unicode_type = str 510 _CheckValueAndType(msg.optional_int32, 0, int) 511 _CheckValueAndType(msg.optional_uint64, 0, (int64, int)) 512 _CheckValueAndType(msg.optional_float, 0, (float, int)) 513 _CheckValueAndType(msg.optional_double, 0, (float, int)) 514 _CheckValueAndType(msg.optional_bool, False, bool) 515 _CheckValueAndType(msg.optional_string, u'', unicode_type) 516 _CheckValueAndType(msg.optional_bytes, b'', bytes) 517 _CheckValueAndType(msg.optional_nested_enum, msg.FOO, int) 518 # First for the generated message 519 _CheckDefaultValues(unittest_pb2.TestAllTypes()) 520 # Then for a message built with from the DescriptorPool. 521 pool = descriptor_pool.DescriptorPool() 522 pool.Add(descriptor_pb2.FileDescriptorProto.FromString( 523 unittest_import_public_pb2.DESCRIPTOR.serialized_pb)) 524 pool.Add(descriptor_pb2.FileDescriptorProto.FromString( 525 unittest_import_pb2.DESCRIPTOR.serialized_pb)) 526 pool.Add(descriptor_pb2.FileDescriptorProto.FromString( 527 unittest_pb2.DESCRIPTOR.serialized_pb)) 528 message_class = message_factory.GetMessageClass( 529 pool.FindMessageTypeByName( 530 unittest_pb2.TestAllTypes.DESCRIPTOR.full_name)) 531 _CheckDefaultValues(message_class()) 532 533 def testAddFileDescriptor(self): 534 if isinstance(self, SecondaryDescriptorFromDescriptorDB): 535 if api_implementation.Type() != 'python': 536 # Cpp extension cannot call Add on a DescriptorPool 537 # that uses a DescriptorDatabase. 538 # TODO: Fix python and cpp extension diff. 539 return 540 file_desc = descriptor_pb2.FileDescriptorProto(name='some/file.proto') 541 self.pool.Add(file_desc) 542 self.pool.AddSerializedFile(file_desc.SerializeToString()) 543 544 def testComplexNesting(self): 545 if isinstance(self, SecondaryDescriptorFromDescriptorDB): 546 if api_implementation.Type() != 'python': 547 # Cpp extension cannot call Add on a DescriptorPool 548 # that uses a DescriptorDatabase. 549 # TODO: Fix python and cpp extension diff. 550 return 551 timestamp_desc = descriptor_pb2.FileDescriptorProto.FromString( 552 timestamp_pb2.DESCRIPTOR.serialized_pb) 553 duration_desc = descriptor_pb2.FileDescriptorProto.FromString( 554 duration_pb2.DESCRIPTOR.serialized_pb) 555 struct_desc = descriptor_pb2.FileDescriptorProto.FromString( 556 struct_pb2.DESCRIPTOR.serialized_pb 557 ) 558 more_messages_desc = descriptor_pb2.FileDescriptorProto.FromString( 559 more_messages_pb2.DESCRIPTOR.serialized_pb) 560 test1_desc = descriptor_pb2.FileDescriptorProto.FromString( 561 descriptor_pool_test1_pb2.DESCRIPTOR.serialized_pb) 562 test2_desc = descriptor_pb2.FileDescriptorProto.FromString( 563 descriptor_pool_test2_pb2.DESCRIPTOR.serialized_pb) 564 self.pool.Add(timestamp_desc) 565 self.pool.Add(duration_desc) 566 self.pool.Add(struct_desc) 567 self.pool.Add(more_messages_desc) 568 self.pool.Add(test1_desc) 569 self.pool.Add(test2_desc) 570 TEST1_FILE.CheckFile(self, self.pool) 571 TEST2_FILE.CheckFile(self, self.pool) 572 573 def testConflictRegister(self): 574 if isinstance(self, SecondaryDescriptorFromDescriptorDB): 575 if api_implementation.Type() != 'python': 576 # Cpp extension cannot call Add on a DescriptorPool 577 # that uses a DescriptorDatabase. 578 # TODO: Fix python and cpp extension diff. 579 return 580 unittest_fd = descriptor_pb2.FileDescriptorProto.FromString( 581 unittest_pb2.DESCRIPTOR.serialized_pb) 582 conflict_fd = copy.deepcopy(unittest_fd) 583 conflict_fd.name = 'other_file' 584 if api_implementation.Type() != 'python': 585 pass 586 else: 587 pool = copy.deepcopy(self.pool) 588 file_descriptor = unittest_pb2.DESCRIPTOR 589 pool._AddDescriptor( 590 file_descriptor.message_types_by_name['TestAllTypes']) 591 pool._AddEnumDescriptor( 592 file_descriptor.enum_types_by_name['ForeignEnum']) 593 pool._AddServiceDescriptor( 594 file_descriptor.services_by_name['TestService']) 595 pool._AddExtensionDescriptor( 596 file_descriptor.extensions_by_name['optional_int32_extension']) 597 pool.Add(unittest_fd) 598 with warnings.catch_warnings(record=True) as w: 599 warnings.simplefilter('always') 600 pool.Add(conflict_fd) 601 self.assertTrue(len(w)) 602 self.assertIs(w[0].category, RuntimeWarning) 603 self.assertIn('Conflict register for file "other_file": ', 604 str(w[0].message)) 605 pool.FindFileByName(unittest_fd.name) 606 with self.assertRaises(TypeError): 607 pool.FindFileByName(conflict_fd.name) 608 609 def testTypeNotSet(self): 610 f = descriptor_pb2.FileDescriptorProto( 611 name='google/protobuf/internal/not_type.proto', 612 package='google.protobuf.python.internal', 613 syntax='proto3') 614 f.enum_type.add(name='TestEnum').value.add(name='DEFAULTVALUE', 615 number=0) 616 msg_proto = f.message_type.add(name='TestMessage') 617 msg_proto.nested_type.add(name='Nested') 618 # type may not set if type_name is set in FieldDescriptorProto 619 msg_proto.field.add(name='nested_field', 620 number=1, 621 label=descriptor.FieldDescriptor.LABEL_OPTIONAL, 622 type_name='Nested') 623 msg_proto.field.add(name='enum_field', 624 number=2, 625 label=descriptor.FieldDescriptor.LABEL_REPEATED, 626 type_name='TestEnum') 627 pool = descriptor_pool.DescriptorPool() 628 pool.Add(f) 629 file_des = pool.FindFileByName('google/protobuf/internal/not_type.proto') 630 msg = file_des.message_types_by_name['TestMessage'] 631 nested_field = msg.fields_by_name['nested_field'] 632 self.assertTrue(nested_field.has_presence) 633 # cpp extension and upb do not provide is_packed on FieldDescriptor 634 if api_implementation.Type() == 'python': 635 self.assertFalse(nested_field.is_packed) 636 enum_field = msg.fields_by_name['enum_field'] 637 self.assertFalse(enum_field.has_presence) 638 if api_implementation.Type() == 'python': 639 self.assertTrue(enum_field.is_packed) 640 641@testing_refleaks.TestCase 642class DefaultDescriptorPoolTest(DescriptorPoolTestBase, unittest.TestCase): 643 644 def setUp(self): 645 self.pool = descriptor_pool.Default() 646 self.factory_test1_fd = descriptor_pb2.FileDescriptorProto.FromString( 647 factory_test1_pb2.DESCRIPTOR.serialized_pb) 648 self.factory_test2_fd = descriptor_pb2.FileDescriptorProto.FromString( 649 factory_test2_pb2.DESCRIPTOR.serialized_pb) 650 651 def testFindMethods(self): 652 self.assertIs( 653 self.pool.FindFileByName('google/protobuf/unittest.proto'), 654 unittest_pb2.DESCRIPTOR) 655 self.assertIs( 656 self.pool.FindMessageTypeByName('protobuf_unittest.TestAllTypes'), 657 unittest_pb2.TestAllTypes.DESCRIPTOR) 658 self.assertIs( 659 self.pool.FindFieldByName( 660 'protobuf_unittest.TestAllTypes.optional_int32'), 661 unittest_pb2.TestAllTypes.DESCRIPTOR.fields_by_name['optional_int32']) 662 self.assertIs( 663 self.pool.FindEnumTypeByName('protobuf_unittest.ForeignEnum'), 664 unittest_pb2.ForeignEnum.DESCRIPTOR) 665 self.assertIs( 666 self.pool.FindExtensionByName( 667 'protobuf_unittest.optional_int32_extension'), 668 unittest_pb2.DESCRIPTOR.extensions_by_name['optional_int32_extension']) 669 self.assertIs( 670 self.pool.FindOneofByName('protobuf_unittest.TestAllTypes.oneof_field'), 671 unittest_pb2.TestAllTypes.DESCRIPTOR.oneofs_by_name['oneof_field']) 672 self.assertIs( 673 self.pool.FindServiceByName('protobuf_unittest.TestService'), 674 unittest_pb2.DESCRIPTOR.services_by_name['TestService']) 675 676 677@testing_refleaks.TestCase 678class CreateDescriptorPoolTest(DescriptorPoolTestBase, unittest.TestCase): 679 680 def setUp(self): 681 self.pool = descriptor_pool.DescriptorPool() 682 self.factory_test1_fd = descriptor_pb2.FileDescriptorProto.FromString( 683 factory_test1_pb2.DESCRIPTOR.serialized_pb) 684 self.factory_test2_fd = descriptor_pb2.FileDescriptorProto.FromString( 685 factory_test2_pb2.DESCRIPTOR.serialized_pb) 686 self.pool.Add(self.factory_test1_fd) 687 self.pool.Add(self.factory_test2_fd) 688 689 self.pool.Add(descriptor_pb2.FileDescriptorProto.FromString( 690 unittest_import_public_pb2.DESCRIPTOR.serialized_pb)) 691 self.pool.Add(descriptor_pb2.FileDescriptorProto.FromString( 692 unittest_import_pb2.DESCRIPTOR.serialized_pb)) 693 self.pool.Add(descriptor_pb2.FileDescriptorProto.FromString( 694 unittest_pb2.DESCRIPTOR.serialized_pb)) 695 self.pool.Add(descriptor_pb2.FileDescriptorProto.FromString( 696 no_package_pb2.DESCRIPTOR.serialized_pb)) 697 698 699@testing_refleaks.TestCase 700class SecondaryDescriptorFromDescriptorDB(DescriptorPoolTestBase, 701 unittest.TestCase): 702 703 def setUp(self): 704 self.factory_test1_fd = descriptor_pb2.FileDescriptorProto.FromString( 705 factory_test1_pb2.DESCRIPTOR.serialized_pb) 706 self.factory_test2_fd = descriptor_pb2.FileDescriptorProto.FromString( 707 factory_test2_pb2.DESCRIPTOR.serialized_pb) 708 self.db = descriptor_database.DescriptorDatabase() 709 self.db.Add(self.factory_test1_fd) 710 self.db.Add(self.factory_test2_fd) 711 self.db.Add(descriptor_pb2.FileDescriptorProto.FromString( 712 unittest_import_public_pb2.DESCRIPTOR.serialized_pb)) 713 self.db.Add(descriptor_pb2.FileDescriptorProto.FromString( 714 unittest_import_pb2.DESCRIPTOR.serialized_pb)) 715 self.db.Add(descriptor_pb2.FileDescriptorProto.FromString( 716 unittest_pb2.DESCRIPTOR.serialized_pb)) 717 self.db.Add(descriptor_pb2.FileDescriptorProto.FromString( 718 no_package_pb2.DESCRIPTOR.serialized_pb)) 719 self.pool = descriptor_pool.DescriptorPool(descriptor_db=self.db) 720 721 def testErrorCollector(self): 722 file_proto = descriptor_pb2.FileDescriptorProto() 723 file_proto.package = 'collector' 724 file_proto.name = 'error_file' 725 message_type = file_proto.message_type.add() 726 message_type.name = 'ErrorMessage' 727 field = message_type.field.add() 728 field.number = 1 729 field.name = 'nested_message_field' 730 field.label = descriptor.FieldDescriptor.LABEL_OPTIONAL 731 field.type = descriptor.FieldDescriptor.TYPE_MESSAGE 732 field.type_name = 'SubMessage' 733 oneof = message_type.oneof_decl.add() 734 oneof.name = 'MyOneof' 735 enum_type = file_proto.enum_type.add() 736 enum_type.name = 'MyEnum' 737 enum_value = enum_type.value.add() 738 enum_value.name = 'MyEnumValue' 739 enum_value.number = 0 740 self.db.Add(file_proto) 741 742 self.assertRaisesRegex(KeyError, 'SubMessage', 743 self.pool.FindMessageTypeByName, 744 'collector.ErrorMessage') 745 self.assertRaisesRegex(KeyError, 'SubMessage', self.pool.FindFileByName, 746 'error_file') 747 with self.assertRaises(KeyError) as exc: 748 self.pool.FindFileByName('none_file') 749 self.assertIn(str(exc.exception), ('\'none_file\'', 750 '\"Couldn\'t find file none_file\"')) 751 752 # Pure python _ConvertFileProtoToFileDescriptor() method has side effect 753 # that all the symbols found in the file will load into the pool even the 754 # file can not build. So when FindMessageTypeByName('ErrorMessage') was 755 # called the first time, a KeyError will be raised but call the find 756 # method later will return a descriptor which is not build. 757 # TODO: fix pure python to revert the load if file can not be build 758 if api_implementation.Type() != 'python': 759 error_msg = ('Invalid proto descriptor for file "error_file":\\n ' 760 'collector.ErrorMessage.nested_message_field: "SubMessage" ' 761 'is not defined.\\n collector.ErrorMessage.MyOneof: Oneof ' 762 'must have at least one field.\\n\'') 763 with self.assertRaises(KeyError) as exc: 764 self.pool.FindMessageTypeByName('collector.ErrorMessage') 765 self.assertEqual(str(exc.exception), '\'Couldn\\\'t build file for ' 766 'message collector.ErrorMessage\\n' + error_msg) 767 768 with self.assertRaises(KeyError) as exc: 769 self.pool.FindFieldByName('collector.ErrorMessage.nested_message_field') 770 self.assertEqual(str(exc.exception), '\'Couldn\\\'t build file for field' 771 ' collector.ErrorMessage.nested_message_field\\n' 772 + error_msg) 773 774 with self.assertRaises(KeyError) as exc: 775 self.pool.FindEnumTypeByName('collector.MyEnum') 776 self.assertEqual(str(exc.exception), '\'Couldn\\\'t build file for enum' 777 ' collector.MyEnum\\n' + error_msg) 778 779 with self.assertRaises(KeyError) as exc: 780 self.pool.FindFileContainingSymbol('collector.MyEnumValue') 781 self.assertEqual(str(exc.exception), '\'Couldn\\\'t build file for symbol' 782 ' collector.MyEnumValue\\n' + error_msg) 783 784 with self.assertRaises(KeyError) as exc: 785 self.pool.FindOneofByName('collector.ErrorMessage.MyOneof') 786 self.assertEqual(str(exc.exception), '\'Couldn\\\'t build file for oneof' 787 ' collector.ErrorMessage.MyOneof\\n' + error_msg) 788 789 790class ProtoFile(object): 791 792 def __init__(self, name, package, messages, dependencies=None, 793 public_dependencies=None): 794 self.name = name 795 self.package = package 796 self.messages = messages 797 self.dependencies = dependencies or [] 798 self.public_dependencies = public_dependencies or [] 799 800 def CheckFile(self, test, pool): 801 file_desc = pool.FindFileByName(self.name) 802 test.assertEqual(self.name, file_desc.name) 803 test.assertEqual(self.package, file_desc.package) 804 dependencies_names = [f.name for f in file_desc.dependencies] 805 test.assertEqual(self.dependencies, dependencies_names) 806 public_dependencies_names = [f.name for f in file_desc.public_dependencies] 807 test.assertEqual(self.public_dependencies, public_dependencies_names) 808 for name, msg_type in self.messages.items(): 809 msg_type.CheckType(test, None, name, file_desc) 810 811 812class EnumType(object): 813 814 def __init__(self, values): 815 self.values = values 816 817 def CheckType(self, test, msg_desc, name, file_desc): 818 enum_desc = msg_desc.enum_types_by_name[name] 819 test.assertEqual(name, enum_desc.name) 820 expected_enum_full_name = '.'.join([msg_desc.full_name, name]) 821 test.assertEqual(expected_enum_full_name, enum_desc.full_name) 822 test.assertEqual(msg_desc, enum_desc.containing_type) 823 test.assertEqual(file_desc, enum_desc.file) 824 for index, (value, number) in enumerate(self.values): 825 value_desc = enum_desc.values_by_name[value] 826 test.assertEqual(value, value_desc.name) 827 test.assertEqual(index, value_desc.index) 828 test.assertEqual(number, value_desc.number) 829 test.assertEqual(enum_desc, value_desc.type) 830 test.assertIn(value, msg_desc.enum_values_by_name) 831 832 833class MessageType(object): 834 835 def __init__(self, type_dict, field_list, is_extendable=False, 836 extensions=None): 837 self.type_dict = type_dict 838 self.field_list = field_list 839 self.is_extendable = is_extendable 840 self.extensions = extensions or [] 841 842 def CheckType(self, test, containing_type_desc, name, file_desc): 843 if containing_type_desc is None: 844 desc = file_desc.message_types_by_name[name] 845 expected_full_name = '.'.join([file_desc.package, name]) 846 else: 847 desc = containing_type_desc.nested_types_by_name[name] 848 expected_full_name = '.'.join([containing_type_desc.full_name, name]) 849 850 test.assertEqual(name, desc.name) 851 test.assertEqual(expected_full_name, desc.full_name) 852 test.assertEqual(containing_type_desc, desc.containing_type) 853 test.assertEqual(desc.file, file_desc) 854 test.assertEqual(self.is_extendable, desc.is_extendable) 855 for name, subtype in self.type_dict.items(): 856 subtype.CheckType(test, desc, name, file_desc) 857 858 for index, (name, field) in enumerate(self.field_list): 859 field.CheckField(test, desc, name, index, file_desc) 860 861 for index, (name, field) in enumerate(self.extensions): 862 field.CheckField(test, desc, name, index, file_desc) 863 864 865class EnumField(object): 866 867 def __init__(self, number, type_name, default_value): 868 self.number = number 869 self.type_name = type_name 870 self.default_value = default_value 871 872 def CheckField(self, test, msg_desc, name, index, file_desc): 873 field_desc = msg_desc.fields_by_name[name] 874 enum_desc = msg_desc.enum_types_by_name[self.type_name] 875 test.assertEqual(name, field_desc.name) 876 expected_field_full_name = '.'.join([msg_desc.full_name, name]) 877 test.assertEqual(expected_field_full_name, field_desc.full_name) 878 test.assertEqual(index, field_desc.index) 879 test.assertEqual(self.number, field_desc.number) 880 test.assertEqual(descriptor.FieldDescriptor.TYPE_ENUM, field_desc.type) 881 test.assertEqual(descriptor.FieldDescriptor.CPPTYPE_ENUM, 882 field_desc.cpp_type) 883 test.assertTrue(field_desc.has_default_value) 884 test.assertEqual(enum_desc.values_by_name[self.default_value].number, 885 field_desc.default_value) 886 test.assertFalse(enum_desc.values_by_name[self.default_value].has_options) 887 test.assertEqual(msg_desc, field_desc.containing_type) 888 test.assertEqual(enum_desc, field_desc.enum_type) 889 test.assertEqual(file_desc, enum_desc.file) 890 891 892class MessageField(object): 893 894 def __init__(self, number, type_name): 895 self.number = number 896 self.type_name = type_name 897 898 def CheckField(self, test, msg_desc, name, index, file_desc): 899 field_desc = msg_desc.fields_by_name[name] 900 field_type_desc = msg_desc.nested_types_by_name[self.type_name] 901 test.assertEqual(name, field_desc.name) 902 expected_field_full_name = '.'.join([msg_desc.full_name, name]) 903 test.assertEqual(expected_field_full_name, field_desc.full_name) 904 test.assertEqual(index, field_desc.index) 905 test.assertEqual(self.number, field_desc.number) 906 test.assertEqual(descriptor.FieldDescriptor.TYPE_MESSAGE, field_desc.type) 907 test.assertEqual(descriptor.FieldDescriptor.CPPTYPE_MESSAGE, 908 field_desc.cpp_type) 909 test.assertFalse(field_desc.has_default_value) 910 test.assertEqual(msg_desc, field_desc.containing_type) 911 test.assertEqual(field_type_desc, field_desc.message_type) 912 test.assertEqual(file_desc, field_desc.file) 913 test.assertEqual(field_desc.default_value, None) 914 915 916class StringField(object): 917 918 def __init__(self, number, default_value): 919 self.number = number 920 self.default_value = default_value 921 922 def CheckField(self, test, msg_desc, name, index, file_desc): 923 field_desc = msg_desc.fields_by_name[name] 924 test.assertEqual(name, field_desc.name) 925 expected_field_full_name = '.'.join([msg_desc.full_name, name]) 926 test.assertEqual(expected_field_full_name, field_desc.full_name) 927 test.assertEqual(index, field_desc.index) 928 test.assertEqual(self.number, field_desc.number) 929 test.assertEqual(descriptor.FieldDescriptor.TYPE_STRING, field_desc.type) 930 test.assertEqual(descriptor.FieldDescriptor.CPPTYPE_STRING, 931 field_desc.cpp_type) 932 test.assertTrue(field_desc.has_default_value) 933 test.assertEqual(self.default_value, field_desc.default_value) 934 test.assertEqual(file_desc, field_desc.file) 935 936 937class ExtensionField(object): 938 939 def __init__(self, number, extended_type): 940 self.number = number 941 self.extended_type = extended_type 942 943 def CheckField(self, test, msg_desc, name, index, file_desc): 944 field_desc = msg_desc.extensions_by_name[name] 945 test.assertEqual(name, field_desc.name) 946 expected_field_full_name = '.'.join([msg_desc.full_name, name]) 947 test.assertEqual(expected_field_full_name, field_desc.full_name) 948 test.assertEqual(self.number, field_desc.number) 949 test.assertEqual(index, field_desc.index) 950 test.assertEqual(descriptor.FieldDescriptor.TYPE_MESSAGE, field_desc.type) 951 test.assertEqual(descriptor.FieldDescriptor.CPPTYPE_MESSAGE, 952 field_desc.cpp_type) 953 test.assertFalse(field_desc.has_default_value) 954 test.assertTrue(field_desc.is_extension) 955 test.assertEqual(msg_desc, field_desc.extension_scope) 956 test.assertEqual(msg_desc, field_desc.message_type) 957 test.assertEqual(self.extended_type, field_desc.containing_type.name) 958 test.assertEqual(file_desc, field_desc.file) 959 960 961@testing_refleaks.TestCase 962class AddDescriptorTest(unittest.TestCase): 963 964 def _TestMessage(self, prefix): 965 pool = descriptor_pool.DescriptorPool() 966 pool._AddDescriptor(unittest_pb2.TestAllTypes.DESCRIPTOR) 967 self.assertEqual( 968 'protobuf_unittest.TestAllTypes', 969 pool.FindMessageTypeByName( 970 prefix + 'protobuf_unittest.TestAllTypes').full_name) 971 972 # AddDescriptor is not recursive. 973 with self.assertRaises(KeyError): 974 pool.FindMessageTypeByName( 975 prefix + 'protobuf_unittest.TestAllTypes.NestedMessage') 976 977 pool._AddDescriptor(unittest_pb2.TestAllTypes.NestedMessage.DESCRIPTOR) 978 self.assertEqual( 979 'protobuf_unittest.TestAllTypes.NestedMessage', 980 pool.FindMessageTypeByName( 981 prefix + 'protobuf_unittest.TestAllTypes.NestedMessage').full_name) 982 983 # Files are implicitly also indexed when messages are added. 984 self.assertEqual( 985 'google/protobuf/unittest.proto', 986 pool.FindFileByName( 987 'google/protobuf/unittest.proto').name) 988 989 self.assertEqual( 990 'google/protobuf/unittest.proto', 991 pool.FindFileContainingSymbol( 992 prefix + 'protobuf_unittest.TestAllTypes.NestedMessage').name) 993 994 @unittest.skipIf(api_implementation.Type() != 'python', 995 'Only pure python allows _Add*()') 996 def testMessage(self): 997 self._TestMessage('') 998 self._TestMessage('.') 999 1000 def _TestEnum(self, prefix): 1001 pool = descriptor_pool.DescriptorPool() 1002 pool.AddSerializedFile(unittest_import_public_pb2.DESCRIPTOR.serialized_pb) 1003 pool.AddSerializedFile(unittest_import_pb2.DESCRIPTOR.serialized_pb) 1004 pool.AddSerializedFile(unittest_pb2.DESCRIPTOR.serialized_pb) 1005 self.assertEqual( 1006 'protobuf_unittest.ForeignEnum', 1007 pool.FindEnumTypeByName( 1008 prefix + 'protobuf_unittest.ForeignEnum').full_name) 1009 1010 # AddEnumDescriptor is not recursive. 1011 with self.assertRaises(KeyError): 1012 pool.FindEnumTypeByName( 1013 prefix + 'protobuf_unittest.ForeignEnum.NestedEnum') 1014 1015 self.assertEqual( 1016 'protobuf_unittest.TestAllTypes.NestedEnum', 1017 pool.FindEnumTypeByName( 1018 prefix + 'protobuf_unittest.TestAllTypes.NestedEnum').full_name) 1019 1020 # Files are implicitly also indexed when enums are added. 1021 self.assertEqual( 1022 'google/protobuf/unittest.proto', 1023 pool.FindFileByName( 1024 'google/protobuf/unittest.proto').name) 1025 1026 self.assertEqual( 1027 'google/protobuf/unittest.proto', 1028 pool.FindFileContainingSymbol( 1029 prefix + 'protobuf_unittest.TestAllTypes.NestedEnum').name) 1030 1031 @unittest.skipIf(api_implementation.Type() != 'python', 1032 'Only pure python allows _Add*()') 1033 def testEnum(self): 1034 self._TestEnum('') 1035 self._TestEnum('.') 1036 1037 @unittest.skipIf(api_implementation.Type() != 'python', 1038 'Only pure python allows _Add*()') 1039 def testService(self): 1040 pool = descriptor_pool.DescriptorPool() 1041 with self.assertRaises(KeyError): 1042 pool.FindServiceByName('protobuf_unittest.TestService') 1043 pool._AddServiceDescriptor(unittest_pb2._TESTSERVICE) 1044 self.assertEqual( 1045 'protobuf_unittest.TestService', 1046 pool.FindServiceByName('protobuf_unittest.TestService').full_name) 1047 1048 @unittest.skipIf(api_implementation.Type() != 'python', 1049 'Only pure python allows _Add*()') 1050 def testFile(self): 1051 pool = descriptor_pool.DescriptorPool() 1052 pool._AddFileDescriptor(unittest_pb2.DESCRIPTOR) 1053 self.assertEqual( 1054 'google/protobuf/unittest.proto', 1055 pool.FindFileByName( 1056 'google/protobuf/unittest.proto').name) 1057 1058 # AddFileDescriptor is not recursive; messages and enums within files must 1059 # be explicitly registered. 1060 with self.assertRaises(KeyError): 1061 pool.FindFileContainingSymbol( 1062 'protobuf_unittest.TestAllTypes') 1063 1064 def testEmptyDescriptorPool(self): 1065 # Check that an empty DescriptorPool() contains no messages. 1066 pool = descriptor_pool.DescriptorPool() 1067 proto_file_name = descriptor_pb2.DESCRIPTOR.name 1068 self.assertRaises(KeyError, pool.FindFileByName, proto_file_name) 1069 # Add the above file to the pool 1070 file_descriptor = descriptor_pb2.FileDescriptorProto() 1071 descriptor_pb2.DESCRIPTOR.CopyToProto(file_descriptor) 1072 pool.Add(file_descriptor) 1073 # Now it exists. 1074 self.assertTrue(pool.FindFileByName(proto_file_name)) 1075 1076 def testCustomDescriptorPool(self): 1077 # Create a new pool, and add a file descriptor. 1078 pool = descriptor_pool.DescriptorPool() 1079 file_desc = descriptor_pb2.FileDescriptorProto( 1080 name='some/file.proto', package='package') 1081 file_desc.message_type.add(name='Message') 1082 pool.Add(file_desc) 1083 self.assertEqual(pool.FindFileByName('some/file.proto').name, 1084 'some/file.proto') 1085 self.assertEqual(pool.FindMessageTypeByName('package.Message').name, 1086 'Message') 1087 # Test no package 1088 file_proto = descriptor_pb2.FileDescriptorProto( 1089 name='some/filename/container.proto') 1090 message_proto = file_proto.message_type.add( 1091 name='TopMessage') 1092 message_proto.field.add( 1093 name='bb', 1094 number=1, 1095 type=descriptor_pb2.FieldDescriptorProto.TYPE_INT32, 1096 label=descriptor_pb2.FieldDescriptorProto.LABEL_OPTIONAL) 1097 enum_proto = file_proto.enum_type.add(name='TopEnum') 1098 enum_proto.value.add(name='FOREIGN_FOO', number=4) 1099 file_proto.service.add(name='TopService') 1100 pool = descriptor_pool.DescriptorPool() 1101 pool.Add(file_proto) 1102 self.assertEqual('TopMessage', 1103 pool.FindMessageTypeByName('TopMessage').name) 1104 self.assertEqual('TopEnum', pool.FindEnumTypeByName('TopEnum').name) 1105 self.assertEqual('TopService', pool.FindServiceByName('TopService').name) 1106 1107 def testFileDescriptorOptionsWithCustomDescriptorPool(self): 1108 # Create a descriptor pool, and add a new FileDescriptorProto to it. 1109 pool = descriptor_pool.DescriptorPool() 1110 file_name = 'file_descriptor_options_with_custom_descriptor_pool.proto' 1111 file_descriptor_proto = descriptor_pb2.FileDescriptorProto(name=file_name) 1112 extension_id = file_options_test_pb2.foo_options 1113 file_descriptor_proto.options.Extensions[extension_id].foo_name = 'foo' 1114 pool.Add(file_descriptor_proto) 1115 # The options set on the FileDescriptorProto should be available in the 1116 # descriptor even if they contain extensions that cannot be deserialized 1117 # using the pool. 1118 file_descriptor = pool.FindFileByName(file_name) 1119 options = file_descriptor.GetOptions() 1120 self.assertEqual('foo', options.Extensions[extension_id].foo_name) 1121 # The object returned by GetOptions() is cached. 1122 self.assertIs(options, file_descriptor.GetOptions()) 1123 1124 def testAddTypeError(self): 1125 pool = descriptor_pool.DescriptorPool() 1126 if api_implementation.Type() == 'python': 1127 with self.assertRaises(TypeError): 1128 pool._AddDescriptor(0) 1129 with self.assertRaises(TypeError): 1130 pool._AddEnumDescriptor(0) 1131 with self.assertRaises(TypeError): 1132 pool._AddServiceDescriptor(0) 1133 with self.assertRaises(TypeError): 1134 pool._AddExtensionDescriptor(0) 1135 with self.assertRaises(TypeError): 1136 pool._AddFileDescriptor(0) 1137 1138 1139@testing_refleaks.TestCase 1140class FeatureSetDefaults(unittest.TestCase): 1141 1142 def testDefault(self): 1143 pool = descriptor_pool.DescriptorPool() 1144 file_desc = descriptor_pb2.FileDescriptorProto(name='some/file.proto') 1145 file = pool.AddSerializedFile(file_desc.SerializeToString()) 1146 self.assertFalse( 1147 file._GetFeatures().HasExtension(unittest_features_pb2.test) 1148 ) 1149 1150 def testMergedDefaults(self): 1151 pool = descriptor_pool.DescriptorPool() 1152 fixed = descriptor_pb2.FeatureSet() 1153 fixed.CopyFrom(unittest_features_pb2.DESCRIPTOR._GetFeatures()) 1154 fixed.field_presence = descriptor_pb2.FeatureSet.IMPLICIT 1155 fixed.ClearField('message_encoding') 1156 defaults = descriptor_pb2.FeatureSetDefaults( 1157 defaults=[ 1158 descriptor_pb2.FeatureSetDefaults.FeatureSetEditionDefault( 1159 edition=descriptor_pb2.Edition.EDITION_PROTO2, 1160 fixed_features=fixed, 1161 overridable_features=descriptor_pb2.FeatureSet( 1162 message_encoding=descriptor_pb2.FeatureSet.DELIMITED 1163 ), 1164 ) 1165 ], 1166 minimum_edition=descriptor_pb2.Edition.EDITION_PROTO2, 1167 maximum_edition=descriptor_pb2.Edition.EDITION_2023, 1168 ) 1169 pool.SetFeatureSetDefaults(defaults) 1170 file_desc = descriptor_pb2.FileDescriptorProto(name='some/file.proto') 1171 file = pool.AddSerializedFile(file_desc.SerializeToString()) 1172 self.assertEqual( 1173 file._GetFeatures().message_encoding, 1174 descriptor_pb2.FeatureSet.DELIMITED, 1175 ) 1176 self.assertEqual( 1177 file._GetFeatures().field_presence, descriptor_pb2.FeatureSet.IMPLICIT 1178 ) 1179 1180 def testOverride(self): 1181 pool = descriptor_pool.DescriptorPool() 1182 defaults = descriptor_pb2.FeatureSetDefaults( 1183 defaults=[ 1184 descriptor_pb2.FeatureSetDefaults.FeatureSetEditionDefault( 1185 edition=descriptor_pb2.Edition.EDITION_PROTO2, 1186 overridable_features=unittest_features_pb2.DESCRIPTOR._GetFeatures(), 1187 ) 1188 ], 1189 minimum_edition=descriptor_pb2.Edition.EDITION_PROTO2, 1190 maximum_edition=descriptor_pb2.Edition.EDITION_2023, 1191 ) 1192 defaults.defaults[0].overridable_features.Extensions[ 1193 unittest_features_pb2.test 1194 ].file_feature = unittest_features_pb2.VALUE9 1195 pool.SetFeatureSetDefaults(defaults) 1196 file_desc = descriptor_pb2.FileDescriptorProto(name='some/file.proto') 1197 file = pool.AddSerializedFile(file_desc.SerializeToString()) 1198 self.assertTrue( 1199 file._GetFeatures().HasExtension(unittest_features_pb2.test) 1200 ) 1201 self.assertEqual( 1202 file._GetFeatures().Extensions[unittest_features_pb2.test].file_feature, 1203 unittest_features_pb2.VALUE9, 1204 ) 1205 1206 def testInvalidType(self): 1207 pool = descriptor_pool.DescriptorPool() 1208 with self.assertRaisesRegex(TypeError, 'invalid type'): 1209 pool.SetFeatureSetDefaults('Some data') 1210 1211 def testInvalidMessageType(self): 1212 pool = descriptor_pool.DescriptorPool() 1213 with self.assertRaisesRegex(TypeError, 'invalid type'): 1214 pool.SetFeatureSetDefaults(descriptor_pb2.FileDescriptorProto()) 1215 1216 def testInvalidEditionRange(self): 1217 pool = descriptor_pool.DescriptorPool() 1218 with self.assertRaisesRegex( 1219 ValueError, 'Invalid edition range.*2023.*PROTO2' 1220 ): 1221 pool.SetFeatureSetDefaults( 1222 descriptor_pb2.FeatureSetDefaults( 1223 defaults=[ 1224 descriptor_pb2.FeatureSetDefaults.FeatureSetEditionDefault( 1225 edition=descriptor_pb2.Edition.EDITION_PROTO2, 1226 overridable_features=unittest_features_pb2.DESCRIPTOR._GetFeatures(), 1227 ) 1228 ], 1229 minimum_edition=descriptor_pb2.Edition.EDITION_2023, 1230 maximum_edition=descriptor_pb2.Edition.EDITION_PROTO2, 1231 ) 1232 ) 1233 file_desc = descriptor_pb2.FileDescriptorProto(name='some/file.proto') 1234 file = pool.AddSerializedFile(file_desc.SerializeToString()) 1235 1236 def testNotStrictlyIncreasing(self): 1237 pool = descriptor_pool.DescriptorPool() 1238 with self.assertRaisesRegex( 1239 ValueError, 'not strictly increasing.*PROTO3.*greater.*PROTO2' 1240 ): 1241 pool.SetFeatureSetDefaults( 1242 descriptor_pb2.FeatureSetDefaults( 1243 defaults=[ 1244 descriptor_pb2.FeatureSetDefaults.FeatureSetEditionDefault( 1245 edition=descriptor_pb2.Edition.EDITION_PROTO3, 1246 overridable_features=unittest_features_pb2.DESCRIPTOR._GetFeatures(), 1247 ), 1248 descriptor_pb2.FeatureSetDefaults.FeatureSetEditionDefault( 1249 edition=descriptor_pb2.Edition.EDITION_PROTO2, 1250 overridable_features=unittest_features_pb2.DESCRIPTOR._GetFeatures(), 1251 ), 1252 ], 1253 minimum_edition=descriptor_pb2.Edition.EDITION_PROTO2, 1254 maximum_edition=descriptor_pb2.Edition.EDITION_2023, 1255 ) 1256 ) 1257 1258 def testUnknownEdition(self): 1259 pool = descriptor_pool.DescriptorPool() 1260 with self.assertRaisesRegex(ValueError, 'Invalid edition.*UNKNOWN'): 1261 pool.SetFeatureSetDefaults( 1262 descriptor_pb2.FeatureSetDefaults( 1263 defaults=[ 1264 descriptor_pb2.FeatureSetDefaults.FeatureSetEditionDefault( 1265 edition=descriptor_pb2.Edition.EDITION_UNKNOWN, 1266 overridable_features=unittest_features_pb2.DESCRIPTOR._GetFeatures(), 1267 ), 1268 descriptor_pb2.FeatureSetDefaults.FeatureSetEditionDefault( 1269 edition=descriptor_pb2.Edition.EDITION_PROTO2, 1270 overridable_features=unittest_features_pb2.DESCRIPTOR._GetFeatures(), 1271 ), 1272 ], 1273 minimum_edition=descriptor_pb2.Edition.EDITION_PROTO2, 1274 maximum_edition=descriptor_pb2.Edition.EDITION_2023, 1275 ) 1276 ) 1277 1278 def testChangeAfterBuild(self): 1279 pool = descriptor_pool.DescriptorPool() 1280 file_desc = descriptor_pb2.FileDescriptorProto(name='some/file.proto') 1281 file = pool.AddSerializedFile(file_desc.SerializeToString()) 1282 file._GetFeatures() 1283 defaults = descriptor_pb2.FeatureSetDefaults( 1284 defaults=[ 1285 descriptor_pb2.FeatureSetDefaults.FeatureSetEditionDefault( 1286 edition=descriptor_pb2.Edition.EDITION_PROTO2, 1287 overridable_features=unittest_features_pb2.DESCRIPTOR._GetFeatures(), 1288 ) 1289 ], 1290 minimum_edition=descriptor_pb2.Edition.EDITION_PROTO2, 1291 maximum_edition=descriptor_pb2.Edition.EDITION_2023, 1292 ) 1293 with self.assertRaisesRegex(ValueError, "defaults can't be changed"): 1294 pool.SetFeatureSetDefaults(defaults) 1295 1296 def testChangeDefaultPool(self): 1297 defaults = descriptor_pb2.FeatureSetDefaults( 1298 defaults=[ 1299 descriptor_pb2.FeatureSetDefaults.FeatureSetEditionDefault( 1300 edition=descriptor_pb2.Edition.EDITION_PROTO2, 1301 overridable_features=unittest_features_pb2.DESCRIPTOR._GetFeatures(), 1302 ) 1303 ], 1304 minimum_edition=descriptor_pb2.Edition.EDITION_PROTO2, 1305 maximum_edition=descriptor_pb2.Edition.EDITION_2023, 1306 ) 1307 with self.assertRaisesRegex(ValueError, "defaults can't be changed"): 1308 descriptor_pool.Default().SetFeatureSetDefaults(defaults) 1309 1310 def testNoValidFeatures(self): 1311 pool = descriptor_pool.DescriptorPool() 1312 defaults = descriptor_pb2.FeatureSetDefaults( 1313 defaults=[ 1314 descriptor_pb2.FeatureSetDefaults.FeatureSetEditionDefault( 1315 edition=descriptor_pb2.Edition.EDITION_2023, 1316 overridable_features=unittest_features_pb2.DESCRIPTOR._GetFeatures(), 1317 ) 1318 ], 1319 minimum_edition=descriptor_pb2.Edition.EDITION_PROTO2, 1320 maximum_edition=descriptor_pb2.Edition.EDITION_2023, 1321 ) 1322 pool.SetFeatureSetDefaults(defaults) 1323 file_desc = descriptor_pb2.FileDescriptorProto(name='some/file.proto') 1324 with self.assertRaisesRegex(TypeError, 'No valid default found.*PROTO2'): 1325 file = pool.AddSerializedFile(file_desc.SerializeToString()) 1326 file._GetFeatures() 1327 1328 def testBelowMinimum(self): 1329 pool = descriptor_pool.DescriptorPool() 1330 defaults = descriptor_pb2.FeatureSetDefaults( 1331 defaults=[ 1332 descriptor_pb2.FeatureSetDefaults.FeatureSetEditionDefault( 1333 edition=descriptor_pb2.Edition.EDITION_PROTO3, 1334 overridable_features=unittest_features_pb2.DESCRIPTOR._GetFeatures(), 1335 ) 1336 ], 1337 minimum_edition=descriptor_pb2.Edition.EDITION_PROTO3, 1338 maximum_edition=descriptor_pb2.Edition.EDITION_2023, 1339 ) 1340 pool.SetFeatureSetDefaults(defaults) 1341 file_desc = descriptor_pb2.FileDescriptorProto(name='some/file.proto') 1342 with self.assertRaisesRegex( 1343 TypeError, 'PROTO2.*earlier than the minimum.*PROTO3' 1344 ): 1345 file = pool.AddSerializedFile(file_desc.SerializeToString()) 1346 file._GetFeatures() 1347 1348 def testAboveMaximum(self): 1349 pool = descriptor_pool.DescriptorPool() 1350 defaults = descriptor_pb2.FeatureSetDefaults( 1351 defaults=[ 1352 descriptor_pb2.FeatureSetDefaults.FeatureSetEditionDefault( 1353 edition=descriptor_pb2.Edition.EDITION_PROTO2, 1354 overridable_features=unittest_features_pb2.DESCRIPTOR._GetFeatures(), 1355 ) 1356 ], 1357 minimum_edition=descriptor_pb2.Edition.EDITION_PROTO2, 1358 maximum_edition=descriptor_pb2.Edition.EDITION_PROTO3, 1359 ) 1360 pool.SetFeatureSetDefaults(defaults) 1361 file_desc = descriptor_pb2.FileDescriptorProto( 1362 name='some/file.proto', 1363 syntax='editions', 1364 edition=descriptor_pb2.Edition.EDITION_2023, 1365 ) 1366 with self.assertRaisesRegex( 1367 TypeError, '2023.*later than the maximum.*PROTO3' 1368 ): 1369 file = pool.AddSerializedFile(file_desc.SerializeToString()) 1370 file._GetFeatures() 1371 1372 1373TEST1_FILE = ProtoFile( 1374 'google/protobuf/internal/descriptor_pool_test1.proto', 1375 'google.protobuf.python.internal', 1376 { 1377 'DescriptorPoolTest1': MessageType({ 1378 'NestedEnum': EnumType([('ALPHA', 1), ('BETA', 2)]), 1379 'NestedMessage': MessageType({ 1380 'NestedEnum': EnumType([('EPSILON', 5), ('ZETA', 6)]), 1381 'DeepNestedMessage': MessageType({ 1382 'NestedEnum': EnumType([('ETA', 7), ('THETA', 8)]), 1383 }, [ 1384 ('nested_enum', EnumField(1, 'NestedEnum', 'ETA')), 1385 ('nested_field', StringField(2, 'theta')), 1386 ]), 1387 }, [ 1388 ('nested_enum', EnumField(1, 'NestedEnum', 'ZETA')), 1389 ('nested_field', StringField(2, 'beta')), 1390 ('deep_nested_message', MessageField(3, 'DeepNestedMessage')), 1391 ]) 1392 }, [ 1393 ('nested_enum', EnumField(1, 'NestedEnum', 'BETA')), 1394 ('nested_message', MessageField(2, 'NestedMessage')), 1395 ], is_extendable=True), 1396 1397 'DescriptorPoolTest2': MessageType({ 1398 'NestedEnum': EnumType([('GAMMA', 3), ('DELTA', 4)]), 1399 'NestedMessage': MessageType({ 1400 'NestedEnum': EnumType([('IOTA', 9), ('KAPPA', 10)]), 1401 'DeepNestedMessage': MessageType({ 1402 'NestedEnum': EnumType([('LAMBDA', 11), ('MU', 12)]), 1403 }, [ 1404 ('nested_enum', EnumField(1, 'NestedEnum', 'MU')), 1405 ('nested_field', StringField(2, 'lambda')), 1406 ]), 1407 }, [ 1408 ('nested_enum', EnumField(1, 'NestedEnum', 'IOTA')), 1409 ('nested_field', StringField(2, 'delta')), 1410 ('deep_nested_message', MessageField(3, 'DeepNestedMessage')), 1411 ]) 1412 }, [ 1413 ('nested_enum', EnumField(1, 'NestedEnum', 'GAMMA')), 1414 ('nested_message', MessageField(2, 'NestedMessage')), 1415 ]), 1416 }) 1417 1418 1419TEST2_FILE = ProtoFile( 1420 'google/protobuf/internal/descriptor_pool_test2.proto', 1421 'google.protobuf.python.internal', { 1422 'DescriptorPoolTest3': 1423 MessageType( 1424 { 1425 'NestedEnum': 1426 EnumType([('NU', 13), ('XI', 14)]), 1427 'NestedMessage': 1428 MessageType( 1429 { 1430 'NestedEnum': 1431 EnumType([('OMICRON', 15), ('PI', 16)]), 1432 'DeepNestedMessage': 1433 MessageType( 1434 { 1435 'NestedEnum': 1436 EnumType([('RHO', 17), 1437 ('SIGMA', 18)]), 1438 }, [ 1439 ('nested_enum', 1440 EnumField(1, 'NestedEnum', 'RHO')), 1441 ('nested_field', 1442 StringField(2, 'sigma')), 1443 ]), 1444 }, [ 1445 ('nested_enum', EnumField( 1446 1, 'NestedEnum', 'PI')), 1447 ('nested_field', StringField(2, 'nu')), 1448 ('deep_nested_message', 1449 MessageField(3, 'DeepNestedMessage')), 1450 ]) 1451 }, [ 1452 ('nested_enum', EnumField(1, 'NestedEnum', 'XI')), 1453 ('nested_message', MessageField(2, 'NestedMessage')), 1454 ], 1455 extensions=[ 1456 ('descriptor_pool_test', 1457 ExtensionField(1001, 'DescriptorPoolTest1')), 1458 ]), 1459 }, 1460 dependencies=[ 1461 'google/protobuf/internal/more_messages.proto', 1462 'google/protobuf/internal/descriptor_pool_test1.proto', 1463 ], 1464 public_dependencies=[ 1465 'google/protobuf/internal/more_messages.proto']) 1466 1467 1468if __name__ == '__main__': 1469 unittest.main() 1470