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        for index, service_proto in enumerate(file_proto.service):
398          file_descriptor.services_by_name[service_proto.name] = (
399              self._MakeServiceDescriptor(service_proto, index, scope,
400                                          file_proto.package, file_descriptor))
401
402      self.Add(file_proto)
403      self._file_descriptors[file_proto.name] = file_descriptor
404
405    return self._file_descriptors[file_proto.name]
406
407  def _ConvertMessageDescriptor(self, desc_proto, package=None, file_desc=None,
408                                scope=None, syntax=None):
409    """Adds the proto to the pool in the specified package.
410
411    Args:
412      desc_proto: The descriptor_pb2.DescriptorProto protobuf message.
413      package: The package the proto should be located in.
414      file_desc: The file containing this message.
415      scope: Dict mapping short and full symbols to message and enum types.
416
417    Returns:
418      The added descriptor.
419    """
420
421    if package:
422      desc_name = '.'.join((package, desc_proto.name))
423    else:
424      desc_name = desc_proto.name
425
426    if file_desc is None:
427      file_name = None
428    else:
429      file_name = file_desc.name
430
431    if scope is None:
432      scope = {}
433
434    nested = [
435        self._ConvertMessageDescriptor(
436            nested, desc_name, file_desc, scope, syntax)
437        for nested in desc_proto.nested_type]
438    enums = [
439        self._ConvertEnumDescriptor(enum, desc_name, file_desc, None, scope)
440        for enum in desc_proto.enum_type]
441    fields = [self._MakeFieldDescriptor(field, desc_name, index)
442              for index, field in enumerate(desc_proto.field)]
443    extensions = [
444        self._MakeFieldDescriptor(extension, desc_name, index,
445                                  is_extension=True)
446        for index, extension in enumerate(desc_proto.extension)]
447    oneofs = [
448        descriptor.OneofDescriptor(desc.name, '.'.join((desc_name, desc.name)),
449                                   index, None, [], desc.options)
450        for index, desc in enumerate(desc_proto.oneof_decl)]
451    extension_ranges = [(r.start, r.end) for r in desc_proto.extension_range]
452    if extension_ranges:
453      is_extendable = True
454    else:
455      is_extendable = False
456    desc = descriptor.Descriptor(
457        name=desc_proto.name,
458        full_name=desc_name,
459        filename=file_name,
460        containing_type=None,
461        fields=fields,
462        oneofs=oneofs,
463        nested_types=nested,
464        enum_types=enums,
465        extensions=extensions,
466        options=desc_proto.options,
467        is_extendable=is_extendable,
468        extension_ranges=extension_ranges,
469        file=file_desc,
470        serialized_start=None,
471        serialized_end=None,
472        syntax=syntax)
473    for nested in desc.nested_types:
474      nested.containing_type = desc
475    for enum in desc.enum_types:
476      enum.containing_type = desc
477    for field_index, field_desc in enumerate(desc_proto.field):
478      if field_desc.HasField('oneof_index'):
479        oneof_index = field_desc.oneof_index
480        oneofs[oneof_index].fields.append(fields[field_index])
481        fields[field_index].containing_oneof = oneofs[oneof_index]
482
483    scope[_PrefixWithDot(desc_name)] = desc
484    self._descriptors[desc_name] = desc
485    return desc
486
487  def _ConvertEnumDescriptor(self, enum_proto, package=None, file_desc=None,
488                             containing_type=None, scope=None):
489    """Make a protobuf EnumDescriptor given an EnumDescriptorProto protobuf.
490
491    Args:
492      enum_proto: The descriptor_pb2.EnumDescriptorProto protobuf message.
493      package: Optional package name for the new message EnumDescriptor.
494      file_desc: The file containing the enum descriptor.
495      containing_type: The type containing this enum.
496      scope: Scope containing available types.
497
498    Returns:
499      The added descriptor
500    """
501
502    if package:
503      enum_name = '.'.join((package, enum_proto.name))
504    else:
505      enum_name = enum_proto.name
506
507    if file_desc is None:
508      file_name = None
509    else:
510      file_name = file_desc.name
511
512    values = [self._MakeEnumValueDescriptor(value, index)
513              for index, value in enumerate(enum_proto.value)]
514    desc = descriptor.EnumDescriptor(name=enum_proto.name,
515                                     full_name=enum_name,
516                                     filename=file_name,
517                                     file=file_desc,
518                                     values=values,
519                                     containing_type=containing_type,
520                                     options=enum_proto.options)
521    scope['.%s' % enum_name] = desc
522    self._enum_descriptors[enum_name] = desc
523    return desc
524
525  def _MakeFieldDescriptor(self, field_proto, message_name, index,
526                           is_extension=False):
527    """Creates a field descriptor from a FieldDescriptorProto.
528
529    For message and enum type fields, this method will do a look up
530    in the pool for the appropriate descriptor for that type. If it
531    is unavailable, it will fall back to the _source function to
532    create it. If this type is still unavailable, construction will
533    fail.
534
535    Args:
536      field_proto: The proto describing the field.
537      message_name: The name of the containing message.
538      index: Index of the field
539      is_extension: Indication that this field is for an extension.
540
541    Returns:
542      An initialized FieldDescriptor object
543    """
544
545    if message_name:
546      full_name = '.'.join((message_name, field_proto.name))
547    else:
548      full_name = field_proto.name
549
550    return descriptor.FieldDescriptor(
551        name=field_proto.name,
552        full_name=full_name,
553        index=index,
554        number=field_proto.number,
555        type=field_proto.type,
556        cpp_type=None,
557        message_type=None,
558        enum_type=None,
559        containing_type=None,
560        label=field_proto.label,
561        has_default_value=False,
562        default_value=None,
563        is_extension=is_extension,
564        extension_scope=None,
565        options=field_proto.options)
566
567  def _SetAllFieldTypes(self, package, desc_proto, scope):
568    """Sets all the descriptor's fields's types.
569
570    This method also sets the containing types on any extensions.
571
572    Args:
573      package: The current package of desc_proto.
574      desc_proto: The message descriptor to update.
575      scope: Enclosing scope of available types.
576    """
577
578    package = _PrefixWithDot(package)
579
580    main_desc = self._GetTypeFromScope(package, desc_proto.name, scope)
581
582    if package == '.':
583      nested_package = _PrefixWithDot(desc_proto.name)
584    else:
585      nested_package = '.'.join([package, desc_proto.name])
586
587    for field_proto, field_desc in zip(desc_proto.field, main_desc.fields):
588      self._SetFieldType(field_proto, field_desc, nested_package, scope)
589
590    for extension_proto, extension_desc in (
591        zip(desc_proto.extension, main_desc.extensions)):
592      extension_desc.containing_type = self._GetTypeFromScope(
593          nested_package, extension_proto.extendee, scope)
594      self._SetFieldType(extension_proto, extension_desc, nested_package, scope)
595
596    for nested_type in desc_proto.nested_type:
597      self._SetAllFieldTypes(nested_package, nested_type, scope)
598
599  def _SetFieldType(self, field_proto, field_desc, package, scope):
600    """Sets the field's type, cpp_type, message_type and enum_type.
601
602    Args:
603      field_proto: Data about the field in proto format.
604      field_desc: The descriptor to modiy.
605      package: The package the field's container is in.
606      scope: Enclosing scope of available types.
607    """
608    if field_proto.type_name:
609      desc = self._GetTypeFromScope(package, field_proto.type_name, scope)
610    else:
611      desc = None
612
613    if not field_proto.HasField('type'):
614      if isinstance(desc, descriptor.Descriptor):
615        field_proto.type = descriptor.FieldDescriptor.TYPE_MESSAGE
616      else:
617        field_proto.type = descriptor.FieldDescriptor.TYPE_ENUM
618
619    field_desc.cpp_type = descriptor.FieldDescriptor.ProtoTypeToCppProtoType(
620        field_proto.type)
621
622    if (field_proto.type == descriptor.FieldDescriptor.TYPE_MESSAGE
623        or field_proto.type == descriptor.FieldDescriptor.TYPE_GROUP):
624      field_desc.message_type = desc
625
626    if field_proto.type == descriptor.FieldDescriptor.TYPE_ENUM:
627      field_desc.enum_type = desc
628
629    if field_proto.label == descriptor.FieldDescriptor.LABEL_REPEATED:
630      field_desc.has_default_value = False
631      field_desc.default_value = []
632    elif field_proto.HasField('default_value'):
633      field_desc.has_default_value = True
634      if (field_proto.type == descriptor.FieldDescriptor.TYPE_DOUBLE or
635          field_proto.type == descriptor.FieldDescriptor.TYPE_FLOAT):
636        field_desc.default_value = float(field_proto.default_value)
637      elif field_proto.type == descriptor.FieldDescriptor.TYPE_STRING:
638        field_desc.default_value = field_proto.default_value
639      elif field_proto.type == descriptor.FieldDescriptor.TYPE_BOOL:
640        field_desc.default_value = field_proto.default_value.lower() == 'true'
641      elif field_proto.type == descriptor.FieldDescriptor.TYPE_ENUM:
642        field_desc.default_value = field_desc.enum_type.values_by_name[
643            field_proto.default_value].number
644      elif field_proto.type == descriptor.FieldDescriptor.TYPE_BYTES:
645        field_desc.default_value = text_encoding.CUnescape(
646            field_proto.default_value)
647      else:
648        # All other types are of the "int" type.
649        field_desc.default_value = int(field_proto.default_value)
650    else:
651      field_desc.has_default_value = False
652      if (field_proto.type == descriptor.FieldDescriptor.TYPE_DOUBLE or
653          field_proto.type == descriptor.FieldDescriptor.TYPE_FLOAT):
654        field_desc.default_value = 0.0
655      elif field_proto.type == descriptor.FieldDescriptor.TYPE_STRING:
656        field_desc.default_value = u''
657      elif field_proto.type == descriptor.FieldDescriptor.TYPE_BOOL:
658        field_desc.default_value = False
659      elif field_proto.type == descriptor.FieldDescriptor.TYPE_ENUM:
660        field_desc.default_value = field_desc.enum_type.values[0].number
661      elif field_proto.type == descriptor.FieldDescriptor.TYPE_BYTES:
662        field_desc.default_value = b''
663      else:
664        # All other types are of the "int" type.
665        field_desc.default_value = 0
666
667    field_desc.type = field_proto.type
668
669  def _MakeEnumValueDescriptor(self, value_proto, index):
670    """Creates a enum value descriptor object from a enum value proto.
671
672    Args:
673      value_proto: The proto describing the enum value.
674      index: The index of the enum value.
675
676    Returns:
677      An initialized EnumValueDescriptor object.
678    """
679
680    return descriptor.EnumValueDescriptor(
681        name=value_proto.name,
682        index=index,
683        number=value_proto.number,
684        options=value_proto.options,
685        type=None)
686
687  def _MakeServiceDescriptor(self, service_proto, service_index, scope,
688                             package, file_desc):
689    """Make a protobuf ServiceDescriptor given a ServiceDescriptorProto.
690
691    Args:
692      service_proto: The descriptor_pb2.ServiceDescriptorProto protobuf message.
693      service_index: The index of the service in the File.
694      scope: Dict mapping short and full symbols to message and enum types.
695      package: Optional package name for the new message EnumDescriptor.
696      file_desc: The file containing the service descriptor.
697
698    Returns:
699      The added descriptor.
700    """
701
702    if package:
703      service_name = '.'.join((package, service_proto.name))
704    else:
705      service_name = service_proto.name
706
707    methods = [self._MakeMethodDescriptor(method_proto, service_name, package,
708                                          scope, index)
709               for index, method_proto in enumerate(service_proto.method)]
710    desc = descriptor.ServiceDescriptor(name=service_proto.name,
711                                        full_name=service_name,
712                                        index=service_index,
713                                        methods=methods,
714                                        options=service_proto.options,
715                                        file=file_desc)
716    return desc
717
718  def _MakeMethodDescriptor(self, method_proto, service_name, package, scope,
719                            index):
720    """Creates a method descriptor from a MethodDescriptorProto.
721
722    Args:
723      method_proto: The proto describing the method.
724      service_name: The name of the containing service.
725      package: Optional package name to look up for types.
726      scope: Scope containing available types.
727      index: Index of the method in the service.
728
729    Returns:
730      An initialized MethodDescriptor object.
731    """
732    full_name = '.'.join((service_name, method_proto.name))
733    input_type = self._GetTypeFromScope(
734        package, method_proto.input_type, scope)
735    output_type = self._GetTypeFromScope(
736        package, method_proto.output_type, scope)
737    return descriptor.MethodDescriptor(name=method_proto.name,
738                                       full_name=full_name,
739                                       index=index,
740                                       containing_service=None,
741                                       input_type=input_type,
742                                       output_type=output_type,
743                                       options=method_proto.options)
744
745  def _ExtractSymbols(self, descriptors):
746    """Pulls out all the symbols from descriptor protos.
747
748    Args:
749      descriptors: The messages to extract descriptors from.
750    Yields:
751      A two element tuple of the type name and descriptor object.
752    """
753
754    for desc in descriptors:
755      yield (_PrefixWithDot(desc.full_name), desc)
756      for symbol in self._ExtractSymbols(desc.nested_types):
757        yield symbol
758      for enum in desc.enum_types:
759        yield (_PrefixWithDot(enum.full_name), enum)
760
761  def _GetDeps(self, dependencies):
762    """Recursively finds dependencies for file protos.
763
764    Args:
765      dependencies: The names of the files being depended on.
766
767    Yields:
768      Each direct and indirect dependency.
769    """
770
771    for dependency in dependencies:
772      dep_desc = self.FindFileByName(dependency)
773      yield dep_desc
774      for parent_dep in dep_desc.dependencies:
775        yield parent_dep
776
777  def _GetTypeFromScope(self, package, type_name, scope):
778    """Finds a given type name in the current scope.
779
780    Args:
781      package: The package the proto should be located in.
782      type_name: The name of the type to be found in the scope.
783      scope: Dict mapping short and full symbols to message and enum types.
784
785    Returns:
786      The descriptor for the requested type.
787    """
788    if type_name not in scope:
789      components = _PrefixWithDot(package).split('.')
790      while components:
791        possible_match = '.'.join(components + [type_name])
792        if possible_match in scope:
793          type_name = possible_match
794          break
795        else:
796          components.pop(-1)
797    return scope[type_name]
798
799
800def _PrefixWithDot(name):
801  return name if name.startswith('.') else '.%s' % name
802
803
804if _USE_C_DESCRIPTORS:
805  # TODO(amauryfa): This pool could be constructed from Python code, when we
806  # support a flag like 'use_cpp_generated_pool=True'.
807  # pylint: disable=protected-access
808  _DEFAULT = descriptor._message.default_pool
809else:
810  _DEFAULT = DescriptorPool()
811
812
813def Default():
814  return _DEFAULT
815