• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# 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      public_deps = [direct_deps[i] for i in file_proto.public_dependency]
323
324      file_descriptor = descriptor.FileDescriptor(
325          pool=self,
326          name=file_proto.name,
327          package=file_proto.package,
328          syntax=file_proto.syntax,
329          options=file_proto.options,
330          serialized_pb=file_proto.SerializeToString(),
331          dependencies=direct_deps,
332          public_dependencies=public_deps)
333      if _USE_C_DESCRIPTORS:
334        # When using C++ descriptors, all objects defined in the file were added
335        # to the C++ database when the FileDescriptor was built above.
336        # Just add them to this descriptor pool.
337        def _AddMessageDescriptor(message_desc):
338          self._descriptors[message_desc.full_name] = message_desc
339          for nested in message_desc.nested_types:
340            _AddMessageDescriptor(nested)
341          for enum_type in message_desc.enum_types:
342            _AddEnumDescriptor(enum_type)
343        def _AddEnumDescriptor(enum_desc):
344          self._enum_descriptors[enum_desc.full_name] = enum_desc
345        for message_type in file_descriptor.message_types_by_name.values():
346          _AddMessageDescriptor(message_type)
347        for enum_type in file_descriptor.enum_types_by_name.values():
348          _AddEnumDescriptor(enum_type)
349      else:
350        scope = {}
351
352        # This loop extracts all the message and enum types from all the
353        # dependencies of the file_proto. This is necessary to create the
354        # scope of available message types when defining the passed in
355        # file proto.
356        for dependency in built_deps:
357          scope.update(self._ExtractSymbols(
358              dependency.message_types_by_name.values()))
359          scope.update((_PrefixWithDot(enum.full_name), enum)
360                       for enum in dependency.enum_types_by_name.values())
361
362        for message_type in file_proto.message_type:
363          message_desc = self._ConvertMessageDescriptor(
364              message_type, file_proto.package, file_descriptor, scope,
365              file_proto.syntax)
366          file_descriptor.message_types_by_name[message_desc.name] = (
367              message_desc)
368
369        for enum_type in file_proto.enum_type:
370          file_descriptor.enum_types_by_name[enum_type.name] = (
371              self._ConvertEnumDescriptor(enum_type, file_proto.package,
372                                          file_descriptor, None, scope))
373
374        for index, extension_proto in enumerate(file_proto.extension):
375          extension_desc = self._MakeFieldDescriptor(
376              extension_proto, file_proto.package, index, is_extension=True)
377          extension_desc.containing_type = self._GetTypeFromScope(
378              file_descriptor.package, extension_proto.extendee, scope)
379          self._SetFieldType(extension_proto, extension_desc,
380                            file_descriptor.package, scope)
381          file_descriptor.extensions_by_name[extension_desc.name] = (
382              extension_desc)
383
384        for desc_proto in file_proto.message_type:
385          self._SetAllFieldTypes(file_proto.package, desc_proto, scope)
386
387        if file_proto.package:
388          desc_proto_prefix = _PrefixWithDot(file_proto.package)
389        else:
390          desc_proto_prefix = ''
391
392        for desc_proto in file_proto.message_type:
393          desc = self._GetTypeFromScope(
394              desc_proto_prefix, desc_proto.name, scope)
395          file_descriptor.message_types_by_name[desc_proto.name] = desc
396
397      self.Add(file_proto)
398      self._file_descriptors[file_proto.name] = file_descriptor
399
400    return self._file_descriptors[file_proto.name]
401
402  def _ConvertMessageDescriptor(self, desc_proto, package=None, file_desc=None,
403                                scope=None, syntax=None):
404    """Adds the proto to the pool in the specified package.
405
406    Args:
407      desc_proto: The descriptor_pb2.DescriptorProto protobuf message.
408      package: The package the proto should be located in.
409      file_desc: The file containing this message.
410      scope: Dict mapping short and full symbols to message and enum types.
411
412    Returns:
413      The added descriptor.
414    """
415
416    if package:
417      desc_name = '.'.join((package, desc_proto.name))
418    else:
419      desc_name = desc_proto.name
420
421    if file_desc is None:
422      file_name = None
423    else:
424      file_name = file_desc.name
425
426    if scope is None:
427      scope = {}
428
429    nested = [
430        self._ConvertMessageDescriptor(
431            nested, desc_name, file_desc, scope, syntax)
432        for nested in desc_proto.nested_type]
433    enums = [
434        self._ConvertEnumDescriptor(enum, desc_name, file_desc, None, scope)
435        for enum in desc_proto.enum_type]
436    fields = [self._MakeFieldDescriptor(field, desc_name, index)
437              for index, field in enumerate(desc_proto.field)]
438    extensions = [
439        self._MakeFieldDescriptor(extension, desc_name, index,
440                                  is_extension=True)
441        for index, extension in enumerate(desc_proto.extension)]
442    oneofs = [
443        descriptor.OneofDescriptor(desc.name, '.'.join((desc_name, desc.name)),
444                                   index, None, [])
445        for index, desc in enumerate(desc_proto.oneof_decl)]
446    extension_ranges = [(r.start, r.end) for r in desc_proto.extension_range]
447    if extension_ranges:
448      is_extendable = True
449    else:
450      is_extendable = False
451    desc = descriptor.Descriptor(
452        name=desc_proto.name,
453        full_name=desc_name,
454        filename=file_name,
455        containing_type=None,
456        fields=fields,
457        oneofs=oneofs,
458        nested_types=nested,
459        enum_types=enums,
460        extensions=extensions,
461        options=desc_proto.options,
462        is_extendable=is_extendable,
463        extension_ranges=extension_ranges,
464        file=file_desc,
465        serialized_start=None,
466        serialized_end=None,
467        syntax=syntax)
468    for nested in desc.nested_types:
469      nested.containing_type = desc
470    for enum in desc.enum_types:
471      enum.containing_type = desc
472    for field_index, field_desc in enumerate(desc_proto.field):
473      if field_desc.HasField('oneof_index'):
474        oneof_index = field_desc.oneof_index
475        oneofs[oneof_index].fields.append(fields[field_index])
476        fields[field_index].containing_oneof = oneofs[oneof_index]
477
478    scope[_PrefixWithDot(desc_name)] = desc
479    self._descriptors[desc_name] = desc
480    return desc
481
482  def _ConvertEnumDescriptor(self, enum_proto, package=None, file_desc=None,
483                             containing_type=None, scope=None):
484    """Make a protobuf EnumDescriptor given an EnumDescriptorProto protobuf.
485
486    Args:
487      enum_proto: The descriptor_pb2.EnumDescriptorProto protobuf message.
488      package: Optional package name for the new message EnumDescriptor.
489      file_desc: The file containing the enum descriptor.
490      containing_type: The type containing this enum.
491      scope: Scope containing available types.
492
493    Returns:
494      The added descriptor
495    """
496
497    if package:
498      enum_name = '.'.join((package, enum_proto.name))
499    else:
500      enum_name = enum_proto.name
501
502    if file_desc is None:
503      file_name = None
504    else:
505      file_name = file_desc.name
506
507    values = [self._MakeEnumValueDescriptor(value, index)
508              for index, value in enumerate(enum_proto.value)]
509    desc = descriptor.EnumDescriptor(name=enum_proto.name,
510                                     full_name=enum_name,
511                                     filename=file_name,
512                                     file=file_desc,
513                                     values=values,
514                                     containing_type=containing_type,
515                                     options=enum_proto.options)
516    scope['.%s' % enum_name] = desc
517    self._enum_descriptors[enum_name] = desc
518    return desc
519
520  def _MakeFieldDescriptor(self, field_proto, message_name, index,
521                           is_extension=False):
522    """Creates a field descriptor from a FieldDescriptorProto.
523
524    For message and enum type fields, this method will do a look up
525    in the pool for the appropriate descriptor for that type. If it
526    is unavailable, it will fall back to the _source function to
527    create it. If this type is still unavailable, construction will
528    fail.
529
530    Args:
531      field_proto: The proto describing the field.
532      message_name: The name of the containing message.
533      index: Index of the field
534      is_extension: Indication that this field is for an extension.
535
536    Returns:
537      An initialized FieldDescriptor object
538    """
539
540    if message_name:
541      full_name = '.'.join((message_name, field_proto.name))
542    else:
543      full_name = field_proto.name
544
545    return descriptor.FieldDescriptor(
546        name=field_proto.name,
547        full_name=full_name,
548        index=index,
549        number=field_proto.number,
550        type=field_proto.type,
551        cpp_type=None,
552        message_type=None,
553        enum_type=None,
554        containing_type=None,
555        label=field_proto.label,
556        has_default_value=False,
557        default_value=None,
558        is_extension=is_extension,
559        extension_scope=None,
560        options=field_proto.options)
561
562  def _SetAllFieldTypes(self, package, desc_proto, scope):
563    """Sets all the descriptor's fields's types.
564
565    This method also sets the containing types on any extensions.
566
567    Args:
568      package: The current package of desc_proto.
569      desc_proto: The message descriptor to update.
570      scope: Enclosing scope of available types.
571    """
572
573    package = _PrefixWithDot(package)
574
575    main_desc = self._GetTypeFromScope(package, desc_proto.name, scope)
576
577    if package == '.':
578      nested_package = _PrefixWithDot(desc_proto.name)
579    else:
580      nested_package = '.'.join([package, desc_proto.name])
581
582    for field_proto, field_desc in zip(desc_proto.field, main_desc.fields):
583      self._SetFieldType(field_proto, field_desc, nested_package, scope)
584
585    for extension_proto, extension_desc in (
586        zip(desc_proto.extension, main_desc.extensions)):
587      extension_desc.containing_type = self._GetTypeFromScope(
588          nested_package, extension_proto.extendee, scope)
589      self._SetFieldType(extension_proto, extension_desc, nested_package, scope)
590
591    for nested_type in desc_proto.nested_type:
592      self._SetAllFieldTypes(nested_package, nested_type, scope)
593
594  def _SetFieldType(self, field_proto, field_desc, package, scope):
595    """Sets the field's type, cpp_type, message_type and enum_type.
596
597    Args:
598      field_proto: Data about the field in proto format.
599      field_desc: The descriptor to modiy.
600      package: The package the field's container is in.
601      scope: Enclosing scope of available types.
602    """
603    if field_proto.type_name:
604      desc = self._GetTypeFromScope(package, field_proto.type_name, scope)
605    else:
606      desc = None
607
608    if not field_proto.HasField('type'):
609      if isinstance(desc, descriptor.Descriptor):
610        field_proto.type = descriptor.FieldDescriptor.TYPE_MESSAGE
611      else:
612        field_proto.type = descriptor.FieldDescriptor.TYPE_ENUM
613
614    field_desc.cpp_type = descriptor.FieldDescriptor.ProtoTypeToCppProtoType(
615        field_proto.type)
616
617    if (field_proto.type == descriptor.FieldDescriptor.TYPE_MESSAGE
618        or field_proto.type == descriptor.FieldDescriptor.TYPE_GROUP):
619      field_desc.message_type = desc
620
621    if field_proto.type == descriptor.FieldDescriptor.TYPE_ENUM:
622      field_desc.enum_type = desc
623
624    if field_proto.label == descriptor.FieldDescriptor.LABEL_REPEATED:
625      field_desc.has_default_value = False
626      field_desc.default_value = []
627    elif field_proto.HasField('default_value'):
628      field_desc.has_default_value = True
629      if (field_proto.type == descriptor.FieldDescriptor.TYPE_DOUBLE or
630          field_proto.type == descriptor.FieldDescriptor.TYPE_FLOAT):
631        field_desc.default_value = float(field_proto.default_value)
632      elif field_proto.type == descriptor.FieldDescriptor.TYPE_STRING:
633        field_desc.default_value = field_proto.default_value
634      elif field_proto.type == descriptor.FieldDescriptor.TYPE_BOOL:
635        field_desc.default_value = field_proto.default_value.lower() == 'true'
636      elif field_proto.type == descriptor.FieldDescriptor.TYPE_ENUM:
637        field_desc.default_value = field_desc.enum_type.values_by_name[
638            field_proto.default_value].number
639      elif field_proto.type == descriptor.FieldDescriptor.TYPE_BYTES:
640        field_desc.default_value = text_encoding.CUnescape(
641            field_proto.default_value)
642      else:
643        # All other types are of the "int" type.
644        field_desc.default_value = int(field_proto.default_value)
645    else:
646      field_desc.has_default_value = False
647      if (field_proto.type == descriptor.FieldDescriptor.TYPE_DOUBLE or
648          field_proto.type == descriptor.FieldDescriptor.TYPE_FLOAT):
649        field_desc.default_value = 0.0
650      elif field_proto.type == descriptor.FieldDescriptor.TYPE_STRING:
651        field_desc.default_value = u''
652      elif field_proto.type == descriptor.FieldDescriptor.TYPE_BOOL:
653        field_desc.default_value = False
654      elif field_proto.type == descriptor.FieldDescriptor.TYPE_ENUM:
655        field_desc.default_value = field_desc.enum_type.values[0].number
656      elif field_proto.type == descriptor.FieldDescriptor.TYPE_BYTES:
657        field_desc.default_value = b''
658      else:
659        # All other types are of the "int" type.
660        field_desc.default_value = 0
661
662    field_desc.type = field_proto.type
663
664  def _MakeEnumValueDescriptor(self, value_proto, index):
665    """Creates a enum value descriptor object from a enum value proto.
666
667    Args:
668      value_proto: The proto describing the enum value.
669      index: The index of the enum value.
670
671    Returns:
672      An initialized EnumValueDescriptor object.
673    """
674
675    return descriptor.EnumValueDescriptor(
676        name=value_proto.name,
677        index=index,
678        number=value_proto.number,
679        options=value_proto.options,
680        type=None)
681
682  def _ExtractSymbols(self, descriptors):
683    """Pulls out all the symbols from descriptor protos.
684
685    Args:
686      descriptors: The messages to extract descriptors from.
687    Yields:
688      A two element tuple of the type name and descriptor object.
689    """
690
691    for desc in descriptors:
692      yield (_PrefixWithDot(desc.full_name), desc)
693      for symbol in self._ExtractSymbols(desc.nested_types):
694        yield symbol
695      for enum in desc.enum_types:
696        yield (_PrefixWithDot(enum.full_name), enum)
697
698  def _GetDeps(self, dependencies):
699    """Recursively finds dependencies for file protos.
700
701    Args:
702      dependencies: The names of the files being depended on.
703
704    Yields:
705      Each direct and indirect dependency.
706    """
707
708    for dependency in dependencies:
709      dep_desc = self.FindFileByName(dependency)
710      yield dep_desc
711      for parent_dep in dep_desc.dependencies:
712        yield parent_dep
713
714  def _GetTypeFromScope(self, package, type_name, scope):
715    """Finds a given type name in the current scope.
716
717    Args:
718      package: The package the proto should be located in.
719      type_name: The name of the type to be found in the scope.
720      scope: Dict mapping short and full symbols to message and enum types.
721
722    Returns:
723      The descriptor for the requested type.
724    """
725    if type_name not in scope:
726      components = _PrefixWithDot(package).split('.')
727      while components:
728        possible_match = '.'.join(components + [type_name])
729        if possible_match in scope:
730          type_name = possible_match
731          break
732        else:
733          components.pop(-1)
734    return scope[type_name]
735
736
737def _PrefixWithDot(name):
738  return name if name.startswith('.') else '.%s' % name
739
740
741if _USE_C_DESCRIPTORS:
742  # TODO(amauryfa): This pool could be constructed from Python code, when we
743  # support a flag like 'use_cpp_generated_pool=True'.
744  # pylint: disable=protected-access
745  _DEFAULT = descriptor._message.default_pool
746else:
747  _DEFAULT = DescriptorPool()
748
749
750def Default():
751  return _DEFAULT
752