1a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson# Protocol Buffers - Google's data interchange format
2a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson# Copyright 2008 Google Inc.  All rights reserved.
3afb4b72037e3f13db208590fc782c4bc8e27f862Jeff Davidson# https://developers.google.com/protocol-buffers/
4a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson#
5a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson# Redistribution and use in source and binary forms, with or without
6a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson# modification, are permitted provided that the following conditions are
7a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson# met:
8a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson#
9a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson#     * Redistributions of source code must retain the above copyright
10a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson# notice, this list of conditions and the following disclaimer.
11a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson#     * Redistributions in binary form must reproduce the above
12a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson# copyright notice, this list of conditions and the following disclaimer
13a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson# in the documentation and/or other materials provided with the
14a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson# distribution.
15a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson#     * Neither the name of Google Inc. nor the names of its
16a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson# contributors may be used to endorse or promote products derived from
17a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson# this software without specific prior written permission.
18a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson#
19a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson
31a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson"""Provides a container for DescriptorProtos."""
32a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson
33a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson__author__ = 'matthewtoia@google.com (Matt Toia)'
34a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson
35a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson
36a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidsonclass Error(Exception):
37a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  pass
38a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson
39a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson
40a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidsonclass DescriptorDatabaseConflictingDefinitionError(Error):
41a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  """Raised when a proto is added with the same name & different descriptor."""
42a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson
43a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson
44a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidsonclass DescriptorDatabase(object):
45a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  """A container accepting FileDescriptorProtos and maps DescriptorProtos."""
46a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson
47a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  def __init__(self):
48a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    self._file_desc_protos_by_file = {}
49a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    self._file_desc_protos_by_symbol = {}
50a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson
51a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  def Add(self, file_desc_proto):
52a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    """Adds the FileDescriptorProto and its types to this database.
53a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson
54a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    Args:
55a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson      file_desc_proto: The FileDescriptorProto to add.
56a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    Raises:
57a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson      DescriptorDatabaseException: if an attempt is made to add a proto
58a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson        with the same name but different definition than an exisiting
59a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson        proto in the database.
60a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    """
61a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    proto_name = file_desc_proto.name
62a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    if proto_name not in self._file_desc_protos_by_file:
63a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson      self._file_desc_protos_by_file[proto_name] = file_desc_proto
64a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    elif self._file_desc_protos_by_file[proto_name] != file_desc_proto:
65a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson      raise DescriptorDatabaseConflictingDefinitionError(
66a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson          '%s already added, but with different descriptor.' % proto_name)
67a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson
68a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    package = file_desc_proto.package
69a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    for message in file_desc_proto.message_type:
70a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson      self._file_desc_protos_by_symbol.update(
71a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson          (name, file_desc_proto) for name in _ExtractSymbols(message, package))
72a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    for enum in file_desc_proto.enum_type:
73a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson      self._file_desc_protos_by_symbol[
74a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson          '.'.join((package, enum.name))] = file_desc_proto
75a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson
76a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  def FindFileByName(self, name):
77a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    """Finds the file descriptor proto by file name.
78a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson
79a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    Typically the file name is a relative path ending to a .proto file. The
80a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    proto with the given name will have to have been added to this database
81a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    using the Add method or else an error will be raised.
82a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson
83a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    Args:
84a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson      name: The file name to find.
85a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson
86a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    Returns:
87a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson      The file descriptor proto matching the name.
88a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson
89a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    Raises:
90a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson      KeyError if no file by the given name was added.
91a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    """
92a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson
93a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    return self._file_desc_protos_by_file[name]
94a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson
95a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  def FindFileContainingSymbol(self, symbol):
96a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    """Finds the file descriptor proto containing the specified symbol.
97a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson
98a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    The symbol should be a fully qualified name including the file descriptor's
99a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    package and any containing messages. Some examples:
100a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson
101a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    'some.package.name.Message'
102a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    'some.package.name.Message.NestedEnum'
103a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson
104a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    The file descriptor proto containing the specified symbol must be added to
105a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    this database using the Add method or else an error will be raised.
106a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson
107a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    Args:
108a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson      symbol: The fully qualified symbol name.
109a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson
110a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    Returns:
111a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson      The file descriptor proto containing the symbol.
112a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson
113a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    Raises:
114a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson      KeyError if no file contains the specified symbol.
115a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    """
116a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson
117a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    return self._file_desc_protos_by_symbol[symbol]
118a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson
119a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson
120a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidsondef _ExtractSymbols(desc_proto, package):
121a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  """Pulls out all the symbols from a descriptor proto.
122a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson
123a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  Args:
124a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    desc_proto: The proto to extract symbols from.
125a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    package: The package containing the descriptor type.
126a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson
127a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  Yields:
128a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    The fully qualified name found in the descriptor.
129a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  """
130a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson
131a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  message_name = '.'.join((package, desc_proto.name))
132a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  yield message_name
133a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson  for nested_type in desc_proto.nested_type:
134a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    for symbol in _ExtractSymbols(nested_type, message_name):
135a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson      yield symbol
136a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson    for enum_type in desc_proto.enum_type:
137a3b2a6da25a76f17c73d31def3952feb0fd2296eJeff Davidson      yield '.'.join((message_name, enum_type.name))
138