blob: 3e80795c861f3d3abeba4d52d4967ea1c302ee03 [file] [log] [blame]
Brian Silverman9c614bc2016-02-15 20:20:02 -05001# Protocol Buffers - Google's data interchange format
2# Copyright 2008 Google Inc. All rights reserved.
3# https://developers.google.com/protocol-buffers/
4#
5# Redistribution and use in source and binary forms, with or without
6# modification, are permitted provided that the following conditions are
7# met:
8#
9# * Redistributions of source code must retain the above copyright
10# notice, this list of conditions and the following disclaimer.
11# * Redistributions in binary form must reproduce the above
12# copyright notice, this list of conditions and the following disclaimer
13# in the documentation and/or other materials provided with the
14# distribution.
15# * Neither the name of Google Inc. nor the names of its
16# contributors may be used to endorse or promote products derived from
17# this software without specific prior written permission.
18#
19# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
31"""Provides DescriptorPool to use as a container for proto2 descriptors.
32
33The DescriptorPool is used in conjection with a DescriptorDatabase to maintain
34a collection of protocol buffer descriptors for use when dynamically creating
35message types at runtime.
36
37For most applications protocol buffers should be used via modules generated by
38the protocol buffer compiler tool. This should only be used when the type of
39protocol buffers used in an application or library cannot be predetermined.
40
41Below is a straightforward example on how to use this class:
42
43 pool = DescriptorPool()
44 file_descriptor_protos = [ ... ]
45 for file_descriptor_proto in file_descriptor_protos:
46 pool.Add(file_descriptor_proto)
47 my_message_descriptor = pool.FindMessageTypeByName('some.package.MessageType')
48
49The message descriptor can be used in conjunction with the message_factory
50module in order to create a protocol buffer class that can be encoded and
51decoded.
52
53If you want to get a Python class for the specified proto, use the
54helper functions inside google.protobuf.message_factory
55directly instead of this class.
56"""
57
58__author__ = 'matthewtoia@google.com (Matt Toia)'
59
60from google.protobuf import descriptor
61from google.protobuf import descriptor_database
62from google.protobuf import text_encoding
63
64
65_USE_C_DESCRIPTORS = descriptor._USE_C_DESCRIPTORS
66
67
68def _NormalizeFullyQualifiedName(name):
69 """Remove leading period from fully-qualified type name.
70
71 Due to b/13860351 in descriptor_database.py, types in the root namespace are
72 generated with a leading period. This function removes that prefix.
73
74 Args:
75 name: A str, the fully-qualified symbol name.
76
77 Returns:
78 A str, the normalized fully-qualified symbol name.
79 """
80 return name.lstrip('.')
81
82
83class DescriptorPool(object):
84 """A collection of protobufs dynamically constructed by descriptor protos."""
85
86 if _USE_C_DESCRIPTORS:
87
88 def __new__(cls, descriptor_db=None):
89 # pylint: disable=protected-access
90 return descriptor._message.DescriptorPool(descriptor_db)
91
92 def __init__(self, descriptor_db=None):
93 """Initializes a Pool of proto buffs.
94
95 The descriptor_db argument to the constructor is provided to allow
96 specialized file descriptor proto lookup code to be triggered on demand. An
97 example would be an implementation which will read and compile a file
98 specified in a call to FindFileByName() and not require the call to Add()
99 at all. Results from this database will be cached internally here as well.
100
101 Args:
102 descriptor_db: A secondary source of file descriptors.
103 """
104
105 self._internal_db = descriptor_database.DescriptorDatabase()
106 self._descriptor_db = descriptor_db
107 self._descriptors = {}
108 self._enum_descriptors = {}
109 self._file_descriptors = {}
110
111 def Add(self, file_desc_proto):
112 """Adds the FileDescriptorProto and its types to this pool.
113
114 Args:
115 file_desc_proto: The FileDescriptorProto to add.
116 """
117
118 self._internal_db.Add(file_desc_proto)
119
120 def AddSerializedFile(self, serialized_file_desc_proto):
121 """Adds the FileDescriptorProto and its types to this pool.
122
123 Args:
124 serialized_file_desc_proto: A bytes string, serialization of the
125 FileDescriptorProto to add.
126 """
127
128 # pylint: disable=g-import-not-at-top
129 from google.protobuf import descriptor_pb2
130 file_desc_proto = descriptor_pb2.FileDescriptorProto.FromString(
131 serialized_file_desc_proto)
132 self.Add(file_desc_proto)
133
134 def AddDescriptor(self, desc):
135 """Adds a Descriptor to the pool, non-recursively.
136
137 If the Descriptor contains nested messages or enums, the caller must
138 explicitly register them. This method also registers the FileDescriptor
139 associated with the message.
140
141 Args:
142 desc: A Descriptor.
143 """
144 if not isinstance(desc, descriptor.Descriptor):
145 raise TypeError('Expected instance of descriptor.Descriptor.')
146
147 self._descriptors[desc.full_name] = desc
148 self.AddFileDescriptor(desc.file)
149
150 def AddEnumDescriptor(self, enum_desc):
151 """Adds an EnumDescriptor to the pool.
152
153 This method also registers the FileDescriptor associated with the message.
154
155 Args:
156 enum_desc: An EnumDescriptor.
157 """
158
159 if not isinstance(enum_desc, descriptor.EnumDescriptor):
160 raise TypeError('Expected instance of descriptor.EnumDescriptor.')
161
162 self._enum_descriptors[enum_desc.full_name] = enum_desc
163 self.AddFileDescriptor(enum_desc.file)
164
165 def AddFileDescriptor(self, file_desc):
166 """Adds a FileDescriptor to the pool, non-recursively.
167
168 If the FileDescriptor contains messages or enums, the caller must explicitly
169 register them.
170
171 Args:
172 file_desc: A FileDescriptor.
173 """
174
175 if not isinstance(file_desc, descriptor.FileDescriptor):
176 raise TypeError('Expected instance of descriptor.FileDescriptor.')
177 self._file_descriptors[file_desc.name] = file_desc
178
179 def FindFileByName(self, file_name):
180 """Gets a FileDescriptor by file name.
181
182 Args:
183 file_name: The path to the file to get a descriptor for.
184
185 Returns:
186 A FileDescriptor for the named file.
187
188 Raises:
189 KeyError: if the file can not be found in the pool.
190 """
191
192 try:
193 return self._file_descriptors[file_name]
194 except KeyError:
195 pass
196
197 try:
198 file_proto = self._internal_db.FindFileByName(file_name)
199 except KeyError as error:
200 if self._descriptor_db:
201 file_proto = self._descriptor_db.FindFileByName(file_name)
202 else:
203 raise error
204 if not file_proto:
205 raise KeyError('Cannot find a file named %s' % file_name)
206 return self._ConvertFileProtoToFileDescriptor(file_proto)
207
208 def FindFileContainingSymbol(self, symbol):
209 """Gets the FileDescriptor for the file containing the specified symbol.
210
211 Args:
212 symbol: The name of the symbol to search for.
213
214 Returns:
215 A FileDescriptor that contains the specified symbol.
216
217 Raises:
218 KeyError: if the file can not be found in the pool.
219 """
220
221 symbol = _NormalizeFullyQualifiedName(symbol)
222 try:
223 return self._descriptors[symbol].file
224 except KeyError:
225 pass
226
227 try:
228 return self._enum_descriptors[symbol].file
229 except KeyError:
230 pass
231
232 try:
233 file_proto = self._internal_db.FindFileContainingSymbol(symbol)
234 except KeyError as error:
235 if self._descriptor_db:
236 file_proto = self._descriptor_db.FindFileContainingSymbol(symbol)
237 else:
238 raise error
239 if not file_proto:
240 raise KeyError('Cannot find a file containing %s' % symbol)
241 return self._ConvertFileProtoToFileDescriptor(file_proto)
242
243 def FindMessageTypeByName(self, full_name):
244 """Loads the named descriptor from the pool.
245
246 Args:
247 full_name: The full name of the descriptor to load.
248
249 Returns:
250 The descriptor for the named type.
251 """
252
253 full_name = _NormalizeFullyQualifiedName(full_name)
254 if full_name not in self._descriptors:
255 self.FindFileContainingSymbol(full_name)
256 return self._descriptors[full_name]
257
258 def FindEnumTypeByName(self, full_name):
259 """Loads the named enum descriptor from the pool.
260
261 Args:
262 full_name: The full name of the enum descriptor to load.
263
264 Returns:
265 The enum descriptor for the named type.
266 """
267
268 full_name = _NormalizeFullyQualifiedName(full_name)
269 if full_name not in self._enum_descriptors:
270 self.FindFileContainingSymbol(full_name)
271 return self._enum_descriptors[full_name]
272
273 def FindFieldByName(self, full_name):
274 """Loads the named field descriptor from the pool.
275
276 Args:
277 full_name: The full name of the field descriptor to load.
278
279 Returns:
280 The field descriptor for the named field.
281 """
282 full_name = _NormalizeFullyQualifiedName(full_name)
283 message_name, _, field_name = full_name.rpartition('.')
284 message_descriptor = self.FindMessageTypeByName(message_name)
285 return message_descriptor.fields_by_name[field_name]
286
287 def FindExtensionByName(self, full_name):
288 """Loads the named extension descriptor from the pool.
289
290 Args:
291 full_name: The full name of the extension descriptor to load.
292
293 Returns:
294 A FieldDescriptor, describing the named extension.
295 """
296 full_name = _NormalizeFullyQualifiedName(full_name)
297 message_name, _, extension_name = full_name.rpartition('.')
298 try:
299 # Most extensions are nested inside a message.
300 scope = self.FindMessageTypeByName(message_name)
301 except KeyError:
302 # Some extensions are defined at file scope.
303 scope = self.FindFileContainingSymbol(full_name)
304 return scope.extensions_by_name[extension_name]
305
306 def _ConvertFileProtoToFileDescriptor(self, file_proto):
307 """Creates a FileDescriptor from a proto or returns a cached copy.
308
309 This method also has the side effect of loading all the symbols found in
310 the file into the appropriate dictionaries in the pool.
311
312 Args:
313 file_proto: The proto to convert.
314
315 Returns:
316 A FileDescriptor matching the passed in proto.
317 """
318
319 if file_proto.name not in self._file_descriptors:
320 built_deps = list(self._GetDeps(file_proto.dependency))
321 direct_deps = [self.FindFileByName(n) for n in file_proto.dependency]
322
323 file_descriptor = descriptor.FileDescriptor(
324 pool=self,
325 name=file_proto.name,
326 package=file_proto.package,
327 syntax=file_proto.syntax,
328 options=file_proto.options,
329 serialized_pb=file_proto.SerializeToString(),
330 dependencies=direct_deps)
331 if _USE_C_DESCRIPTORS:
332 # When using C++ descriptors, all objects defined in the file were added
333 # to the C++ database when the FileDescriptor was built above.
334 # Just add them to this descriptor pool.
335 def _AddMessageDescriptor(message_desc):
336 self._descriptors[message_desc.full_name] = message_desc
337 for nested in message_desc.nested_types:
338 _AddMessageDescriptor(nested)
339 for enum_type in message_desc.enum_types:
340 _AddEnumDescriptor(enum_type)
341 def _AddEnumDescriptor(enum_desc):
342 self._enum_descriptors[enum_desc.full_name] = enum_desc
343 for message_type in file_descriptor.message_types_by_name.values():
344 _AddMessageDescriptor(message_type)
345 for enum_type in file_descriptor.enum_types_by_name.values():
346 _AddEnumDescriptor(enum_type)
347 else:
348 scope = {}
349
350 # This loop extracts all the message and enum types from all the
351 # dependencies of the file_proto. This is necessary to create the
352 # scope of available message types when defining the passed in
353 # file proto.
354 for dependency in built_deps:
355 scope.update(self._ExtractSymbols(
356 dependency.message_types_by_name.values()))
357 scope.update((_PrefixWithDot(enum.full_name), enum)
358 for enum in dependency.enum_types_by_name.values())
359
360 for message_type in file_proto.message_type:
361 message_desc = self._ConvertMessageDescriptor(
362 message_type, file_proto.package, file_descriptor, scope,
363 file_proto.syntax)
364 file_descriptor.message_types_by_name[message_desc.name] = (
365 message_desc)
366
367 for enum_type in file_proto.enum_type:
368 file_descriptor.enum_types_by_name[enum_type.name] = (
369 self._ConvertEnumDescriptor(enum_type, file_proto.package,
370 file_descriptor, None, scope))
371
372 for index, extension_proto in enumerate(file_proto.extension):
373 extension_desc = self._MakeFieldDescriptor(
374 extension_proto, file_proto.package, index, is_extension=True)
375 extension_desc.containing_type = self._GetTypeFromScope(
376 file_descriptor.package, extension_proto.extendee, scope)
377 self._SetFieldType(extension_proto, extension_desc,
378 file_descriptor.package, scope)
379 file_descriptor.extensions_by_name[extension_desc.name] = (
380 extension_desc)
381
382 for desc_proto in file_proto.message_type:
383 self._SetAllFieldTypes(file_proto.package, desc_proto, scope)
384
385 if file_proto.package:
386 desc_proto_prefix = _PrefixWithDot(file_proto.package)
387 else:
388 desc_proto_prefix = ''
389
390 for desc_proto in file_proto.message_type:
391 desc = self._GetTypeFromScope(
392 desc_proto_prefix, desc_proto.name, scope)
393 file_descriptor.message_types_by_name[desc_proto.name] = desc
394
395 self.Add(file_proto)
396 self._file_descriptors[file_proto.name] = file_descriptor
397
398 return self._file_descriptors[file_proto.name]
399
400 def _ConvertMessageDescriptor(self, desc_proto, package=None, file_desc=None,
401 scope=None, syntax=None):
402 """Adds the proto to the pool in the specified package.
403
404 Args:
405 desc_proto: The descriptor_pb2.DescriptorProto protobuf message.
406 package: The package the proto should be located in.
407 file_desc: The file containing this message.
408 scope: Dict mapping short and full symbols to message and enum types.
409
410 Returns:
411 The added descriptor.
412 """
413
414 if package:
415 desc_name = '.'.join((package, desc_proto.name))
416 else:
417 desc_name = desc_proto.name
418
419 if file_desc is None:
420 file_name = None
421 else:
422 file_name = file_desc.name
423
424 if scope is None:
425 scope = {}
426
427 nested = [
428 self._ConvertMessageDescriptor(
429 nested, desc_name, file_desc, scope, syntax)
430 for nested in desc_proto.nested_type]
431 enums = [
432 self._ConvertEnumDescriptor(enum, desc_name, file_desc, None, scope)
433 for enum in desc_proto.enum_type]
434 fields = [self._MakeFieldDescriptor(field, desc_name, index)
435 for index, field in enumerate(desc_proto.field)]
436 extensions = [
437 self._MakeFieldDescriptor(extension, desc_name, index,
438 is_extension=True)
439 for index, extension in enumerate(desc_proto.extension)]
440 oneofs = [
441 descriptor.OneofDescriptor(desc.name, '.'.join((desc_name, desc.name)),
442 index, None, [])
443 for index, desc in enumerate(desc_proto.oneof_decl)]
444 extension_ranges = [(r.start, r.end) for r in desc_proto.extension_range]
445 if extension_ranges:
446 is_extendable = True
447 else:
448 is_extendable = False
449 desc = descriptor.Descriptor(
450 name=desc_proto.name,
451 full_name=desc_name,
452 filename=file_name,
453 containing_type=None,
454 fields=fields,
455 oneofs=oneofs,
456 nested_types=nested,
457 enum_types=enums,
458 extensions=extensions,
459 options=desc_proto.options,
460 is_extendable=is_extendable,
461 extension_ranges=extension_ranges,
462 file=file_desc,
463 serialized_start=None,
464 serialized_end=None,
465 syntax=syntax)
466 for nested in desc.nested_types:
467 nested.containing_type = desc
468 for enum in desc.enum_types:
469 enum.containing_type = desc
470 for field_index, field_desc in enumerate(desc_proto.field):
471 if field_desc.HasField('oneof_index'):
472 oneof_index = field_desc.oneof_index
473 oneofs[oneof_index].fields.append(fields[field_index])
474 fields[field_index].containing_oneof = oneofs[oneof_index]
475
476 scope[_PrefixWithDot(desc_name)] = desc
477 self._descriptors[desc_name] = desc
478 return desc
479
480 def _ConvertEnumDescriptor(self, enum_proto, package=None, file_desc=None,
481 containing_type=None, scope=None):
482 """Make a protobuf EnumDescriptor given an EnumDescriptorProto protobuf.
483
484 Args:
485 enum_proto: The descriptor_pb2.EnumDescriptorProto protobuf message.
486 package: Optional package name for the new message EnumDescriptor.
487 file_desc: The file containing the enum descriptor.
488 containing_type: The type containing this enum.
489 scope: Scope containing available types.
490
491 Returns:
492 The added descriptor
493 """
494
495 if package:
496 enum_name = '.'.join((package, enum_proto.name))
497 else:
498 enum_name = enum_proto.name
499
500 if file_desc is None:
501 file_name = None
502 else:
503 file_name = file_desc.name
504
505 values = [self._MakeEnumValueDescriptor(value, index)
506 for index, value in enumerate(enum_proto.value)]
507 desc = descriptor.EnumDescriptor(name=enum_proto.name,
508 full_name=enum_name,
509 filename=file_name,
510 file=file_desc,
511 values=values,
512 containing_type=containing_type,
513 options=enum_proto.options)
514 scope['.%s' % enum_name] = desc
515 self._enum_descriptors[enum_name] = desc
516 return desc
517
518 def _MakeFieldDescriptor(self, field_proto, message_name, index,
519 is_extension=False):
520 """Creates a field descriptor from a FieldDescriptorProto.
521
522 For message and enum type fields, this method will do a look up
523 in the pool for the appropriate descriptor for that type. If it
524 is unavailable, it will fall back to the _source function to
525 create it. If this type is still unavailable, construction will
526 fail.
527
528 Args:
529 field_proto: The proto describing the field.
530 message_name: The name of the containing message.
531 index: Index of the field
532 is_extension: Indication that this field is for an extension.
533
534 Returns:
535 An initialized FieldDescriptor object
536 """
537
538 if message_name:
539 full_name = '.'.join((message_name, field_proto.name))
540 else:
541 full_name = field_proto.name
542
543 return descriptor.FieldDescriptor(
544 name=field_proto.name,
545 full_name=full_name,
546 index=index,
547 number=field_proto.number,
548 type=field_proto.type,
549 cpp_type=None,
550 message_type=None,
551 enum_type=None,
552 containing_type=None,
553 label=field_proto.label,
554 has_default_value=False,
555 default_value=None,
556 is_extension=is_extension,
557 extension_scope=None,
558 options=field_proto.options)
559
560 def _SetAllFieldTypes(self, package, desc_proto, scope):
561 """Sets all the descriptor's fields's types.
562
563 This method also sets the containing types on any extensions.
564
565 Args:
566 package: The current package of desc_proto.
567 desc_proto: The message descriptor to update.
568 scope: Enclosing scope of available types.
569 """
570
571 package = _PrefixWithDot(package)
572
573 main_desc = self._GetTypeFromScope(package, desc_proto.name, scope)
574
575 if package == '.':
576 nested_package = _PrefixWithDot(desc_proto.name)
577 else:
578 nested_package = '.'.join([package, desc_proto.name])
579
580 for field_proto, field_desc in zip(desc_proto.field, main_desc.fields):
581 self._SetFieldType(field_proto, field_desc, nested_package, scope)
582
583 for extension_proto, extension_desc in (
584 zip(desc_proto.extension, main_desc.extensions)):
585 extension_desc.containing_type = self._GetTypeFromScope(
586 nested_package, extension_proto.extendee, scope)
587 self._SetFieldType(extension_proto, extension_desc, nested_package, scope)
588
589 for nested_type in desc_proto.nested_type:
590 self._SetAllFieldTypes(nested_package, nested_type, scope)
591
592 def _SetFieldType(self, field_proto, field_desc, package, scope):
593 """Sets the field's type, cpp_type, message_type and enum_type.
594
595 Args:
596 field_proto: Data about the field in proto format.
597 field_desc: The descriptor to modiy.
598 package: The package the field's container is in.
599 scope: Enclosing scope of available types.
600 """
601 if field_proto.type_name:
602 desc = self._GetTypeFromScope(package, field_proto.type_name, scope)
603 else:
604 desc = None
605
606 if not field_proto.HasField('type'):
607 if isinstance(desc, descriptor.Descriptor):
608 field_proto.type = descriptor.FieldDescriptor.TYPE_MESSAGE
609 else:
610 field_proto.type = descriptor.FieldDescriptor.TYPE_ENUM
611
612 field_desc.cpp_type = descriptor.FieldDescriptor.ProtoTypeToCppProtoType(
613 field_proto.type)
614
615 if (field_proto.type == descriptor.FieldDescriptor.TYPE_MESSAGE
616 or field_proto.type == descriptor.FieldDescriptor.TYPE_GROUP):
617 field_desc.message_type = desc
618
619 if field_proto.type == descriptor.FieldDescriptor.TYPE_ENUM:
620 field_desc.enum_type = desc
621
622 if field_proto.label == descriptor.FieldDescriptor.LABEL_REPEATED:
623 field_desc.has_default_value = False
624 field_desc.default_value = []
625 elif field_proto.HasField('default_value'):
626 field_desc.has_default_value = True
627 if (field_proto.type == descriptor.FieldDescriptor.TYPE_DOUBLE or
628 field_proto.type == descriptor.FieldDescriptor.TYPE_FLOAT):
629 field_desc.default_value = float(field_proto.default_value)
630 elif field_proto.type == descriptor.FieldDescriptor.TYPE_STRING:
631 field_desc.default_value = field_proto.default_value
632 elif field_proto.type == descriptor.FieldDescriptor.TYPE_BOOL:
633 field_desc.default_value = field_proto.default_value.lower() == 'true'
634 elif field_proto.type == descriptor.FieldDescriptor.TYPE_ENUM:
635 field_desc.default_value = field_desc.enum_type.values_by_name[
636 field_proto.default_value].number
637 elif field_proto.type == descriptor.FieldDescriptor.TYPE_BYTES:
638 field_desc.default_value = text_encoding.CUnescape(
639 field_proto.default_value)
640 else:
641 # All other types are of the "int" type.
642 field_desc.default_value = int(field_proto.default_value)
643 else:
644 field_desc.has_default_value = False
645 if (field_proto.type == descriptor.FieldDescriptor.TYPE_DOUBLE or
646 field_proto.type == descriptor.FieldDescriptor.TYPE_FLOAT):
647 field_desc.default_value = 0.0
648 elif field_proto.type == descriptor.FieldDescriptor.TYPE_STRING:
649 field_desc.default_value = u''
650 elif field_proto.type == descriptor.FieldDescriptor.TYPE_BOOL:
651 field_desc.default_value = False
652 elif field_proto.type == descriptor.FieldDescriptor.TYPE_ENUM:
653 field_desc.default_value = field_desc.enum_type.values[0].number
654 elif field_proto.type == descriptor.FieldDescriptor.TYPE_BYTES:
655 field_desc.default_value = b''
656 else:
657 # All other types are of the "int" type.
658 field_desc.default_value = 0
659
660 field_desc.type = field_proto.type
661
662 def _MakeEnumValueDescriptor(self, value_proto, index):
663 """Creates a enum value descriptor object from a enum value proto.
664
665 Args:
666 value_proto: The proto describing the enum value.
667 index: The index of the enum value.
668
669 Returns:
670 An initialized EnumValueDescriptor object.
671 """
672
673 return descriptor.EnumValueDescriptor(
674 name=value_proto.name,
675 index=index,
676 number=value_proto.number,
677 options=value_proto.options,
678 type=None)
679
680 def _ExtractSymbols(self, descriptors):
681 """Pulls out all the symbols from descriptor protos.
682
683 Args:
684 descriptors: The messages to extract descriptors from.
685 Yields:
686 A two element tuple of the type name and descriptor object.
687 """
688
689 for desc in descriptors:
690 yield (_PrefixWithDot(desc.full_name), desc)
691 for symbol in self._ExtractSymbols(desc.nested_types):
692 yield symbol
693 for enum in desc.enum_types:
694 yield (_PrefixWithDot(enum.full_name), enum)
695
696 def _GetDeps(self, dependencies):
697 """Recursively finds dependencies for file protos.
698
699 Args:
700 dependencies: The names of the files being depended on.
701
702 Yields:
703 Each direct and indirect dependency.
704 """
705
706 for dependency in dependencies:
707 dep_desc = self.FindFileByName(dependency)
708 yield dep_desc
709 for parent_dep in dep_desc.dependencies:
710 yield parent_dep
711
712 def _GetTypeFromScope(self, package, type_name, scope):
713 """Finds a given type name in the current scope.
714
715 Args:
716 package: The package the proto should be located in.
717 type_name: The name of the type to be found in the scope.
718 scope: Dict mapping short and full symbols to message and enum types.
719
720 Returns:
721 The descriptor for the requested type.
722 """
723 if type_name not in scope:
724 components = _PrefixWithDot(package).split('.')
725 while components:
726 possible_match = '.'.join(components + [type_name])
727 if possible_match in scope:
728 type_name = possible_match
729 break
730 else:
731 components.pop(-1)
732 return scope[type_name]
733
734
735def _PrefixWithDot(name):
736 return name if name.startswith('.') else '.%s' % name
737
738
739if _USE_C_DESCRIPTORS:
740 # TODO(amauryfa): This pool could be constructed from Python code, when we
741 # support a flag like 'use_cpp_generated_pool=True'.
742 # pylint: disable=protected-access
743 _DEFAULT = descriptor._message.default_pool
744else:
745 _DEFAULT = DescriptorPool()
746
747
748def Default():
749 return _DEFAULT