15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Protocol Buffers - Google's data interchange format
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Copyright 2008 Google Inc.  All rights reserved.
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# http://code.google.com/p/protobuf/
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Redistribution and use in source and binary forms, with or without
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# modification, are permitted provided that the following conditions are
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# met:
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#     * Redistributions of source code must retain the above copyright
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# notice, this list of conditions and the following disclaimer.
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#     * Redistributions in binary form must reproduce the above
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# copyright notice, this list of conditions and the following disclaimer
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# in the documentation and/or other materials provided with the
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# distribution.
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#     * Neither the name of Google Inc. nor the names of its
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# contributors may be used to endorse or promote products derived from
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# this software without specific prior written permission.
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# This code is meant to work on Python 2.4 and above only.
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# TODO(robinson): Helpers for verbose, common checks like seeing if a
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# descriptor's cpp_type is CPPTYPE_MESSAGE.
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)"""Contains a metaclass and helper functions used to create
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)protocol message classes from Descriptor objects at runtime.
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Recall that a metaclass is the "type" of a class.
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)(A class is to a metaclass what an instance is to a class.)
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)In this case, we use the GeneratedProtocolMessageType metaclass
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)to inject all the useful functionality into the classes
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)output by the protocol compiler at compile-time.
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)The upshot of all this is that the real implementation
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)details for ALL pure-Python protocol buffers are *here in
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)this file*.
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)"""
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)__author__ = 'robinson@google.com (Will Robinson)'
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)try:
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  from cStringIO import StringIO
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)except ImportError:
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  from StringIO import StringIO
57ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdochimport copy_reg
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import struct
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import weakref
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# We use "as" to avoid name collisions with variables.
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)from google.protobuf.internal import containers
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)from google.protobuf.internal import decoder
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)from google.protobuf.internal import encoder
65ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdochfrom google.protobuf.internal import enum_type_wrapper
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)from google.protobuf.internal import message_listener as message_listener_mod
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)from google.protobuf.internal import type_checkers
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)from google.protobuf.internal import wire_format
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)from google.protobuf import descriptor as descriptor_mod
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)from google.protobuf import message as message_mod
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)from google.protobuf import text_format
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)_FieldDescriptor = descriptor_mod.FieldDescriptor
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
76ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdochdef NewMessage(bases, descriptor, dictionary):
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  _AddClassAttributesForNestedExtensions(descriptor, dictionary)
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  _AddSlots(descriptor, dictionary)
79ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  return bases
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def InitMessage(descriptor, cls):
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cls._decoders_by_tag = {}
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cls._extensions_by_name = {}
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cls._extensions_by_number = {}
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (descriptor.has_options and
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      descriptor.GetOptions().message_set_wire_format):
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cls._decoders_by_tag[decoder.MESSAGE_SET_ITEM_TAG] = (
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        decoder.MessageSetItemDecoder(cls._extensions_by_number))
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # Attach stuff to each FieldDescriptor for quick lookup later on.
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for field in descriptor.fields:
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    _AttachFieldHelpers(cls, field)
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  _AddEnumValues(descriptor, cls)
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  _AddInitMethod(descriptor, cls)
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  _AddPropertiesForFields(descriptor, cls)
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  _AddPropertiesForExtensions(descriptor, cls)
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  _AddStaticMethods(cls)
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  _AddMessageMethods(descriptor, cls)
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  _AddPrivateHelperMethods(cls)
102ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  copy_reg.pickle(cls, lambda obj: (cls, (), obj.__getstate__()))
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Stateless helpers for GeneratedProtocolMessageType below.
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Outside clients should not access these directly.
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# I opted not to make any of these methods on the metaclass, to make it more
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# clear that I'm not really using any state there and to keep clients from
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# thinking that they have direct access to these construction helpers.
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def _PropertyName(proto_field_name):
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Returns the name of the public property attribute which
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  clients can use to get and (in some cases) set the value
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  of a protocol message field.
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Args:
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    proto_field_name: The protocol message field name, exactly
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      as it appears (or would appear) in a .proto file.
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # TODO(robinson): Escape Python keywords (e.g., yield), and test this support.
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # nnorwitz makes my day by writing:
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # """
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # FYI.  See the keyword module in the stdlib. This could be as simple as:
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  #
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # if keyword.iskeyword(proto_field_name):
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  #   return proto_field_name + "_"
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # return proto_field_name
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # """
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # Kenton says:  The above is a BAD IDEA.  People rely on being able to use
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  #   getattr() and setattr() to reflectively manipulate field values.  If we
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  #   rename the properties, then every such user has to also make sure to apply
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  #   the same transformation.  Note that currently if you name a field "yield",
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  #   you can still access it just fine using getattr/setattr -- it's not even
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  #   that cumbersome to do so.
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # TODO(kenton):  Remove this method entirely if/when everyone agrees with my
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  #   position.
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return proto_field_name
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def _VerifyExtensionHandle(message, extension_handle):
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Verify that the given extension handle is valid."""
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if not isinstance(extension_handle, _FieldDescriptor):
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    raise KeyError('HasExtension() expects an extension handle, got: %s' %
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   extension_handle)
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if not extension_handle.is_extension:
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    raise KeyError('"%s" is not an extension.' % extension_handle.full_name)
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
152ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  if not extension_handle.containing_type:
153ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    raise KeyError('"%s" is missing a containing_type.'
154ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch                   % extension_handle.full_name)
155ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if extension_handle.containing_type is not message.DESCRIPTOR:
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    raise KeyError('Extension "%s" extends message type "%s", but this '
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   'message is of type "%s".' %
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   (extension_handle.full_name,
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    extension_handle.containing_type.full_name,
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    message.DESCRIPTOR.full_name))
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def _AddSlots(message_descriptor, dictionary):
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Adds a __slots__ entry to dictionary, containing the names of all valid
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  attributes for this message type.
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Args:
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    message_descriptor: A Descriptor instance describing this message type.
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    dictionary: Class dictionary to which we'll add a '__slots__' entry.
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dictionary['__slots__'] = ['_cached_byte_size',
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             '_cached_byte_size_dirty',
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             '_fields',
175ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch                             '_unknown_fields',
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             '_is_present_in_parent',
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             '_listener',
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             '_listener_for_children',
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             '__weakref__']
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def _IsMessageSetExtension(field):
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return (field.is_extension and
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          field.containing_type.has_options and
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          field.containing_type.GetOptions().message_set_wire_format and
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          field.type == _FieldDescriptor.TYPE_MESSAGE and
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          field.message_type == field.extension_scope and
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          field.label == _FieldDescriptor.LABEL_OPTIONAL)
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def _AttachFieldHelpers(cls, field_descriptor):
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  is_repeated = (field_descriptor.label == _FieldDescriptor.LABEL_REPEATED)
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  is_packed = (field_descriptor.has_options and
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               field_descriptor.GetOptions().packed)
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if _IsMessageSetExtension(field_descriptor):
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    field_encoder = encoder.MessageSetItemEncoder(field_descriptor.number)
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sizer = encoder.MessageSetItemSizer(field_descriptor.number)
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else:
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    field_encoder = type_checkers.TYPE_TO_ENCODER[field_descriptor.type](
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        field_descriptor.number, is_repeated, is_packed)
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sizer = type_checkers.TYPE_TO_SIZER[field_descriptor.type](
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        field_descriptor.number, is_repeated, is_packed)
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  field_descriptor._encoder = field_encoder
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  field_descriptor._sizer = sizer
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  field_descriptor._default_constructor = _DefaultValueConstructorForField(
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      field_descriptor)
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def AddDecoder(wiretype, is_packed):
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    tag_bytes = encoder.TagBytes(field_descriptor.number, wiretype)
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cls._decoders_by_tag[tag_bytes] = (
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        type_checkers.TYPE_TO_DECODER[field_descriptor.type](
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            field_descriptor.number, is_repeated, is_packed,
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            field_descriptor, field_descriptor._default_constructor))
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AddDecoder(type_checkers.FIELD_TYPE_TO_WIRE_TYPE[field_descriptor.type],
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             False)
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if is_repeated and wire_format.IsTypePackable(field_descriptor.type):
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # To support wire compatibility of adding packed = true, add a decoder for
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # packed values regardless of the field's options.
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    AddDecoder(wire_format.WIRETYPE_LENGTH_DELIMITED, True)
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def _AddClassAttributesForNestedExtensions(descriptor, dictionary):
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  extension_dict = descriptor.extensions_by_name
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for extension_name, extension_field in extension_dict.iteritems():
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    assert extension_name not in dictionary
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    dictionary[extension_name] = extension_field
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def _AddEnumValues(descriptor, cls):
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Sets class-level attributes for all enum fields defined in this message.
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
236ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  Also exporting a class-level object that can name enum values.
237ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Args:
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    descriptor: Descriptor object for this message type.
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cls: Class we're constructing for this message type.
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for enum_type in descriptor.enum_types:
243ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    setattr(cls, enum_type.name, enum_type_wrapper.EnumTypeWrapper(enum_type))
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for enum_value in enum_type.values:
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      setattr(cls, enum_value.name, enum_value.number)
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def _DefaultValueConstructorForField(field):
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Returns a function which returns a default value for a field.
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Args:
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    field: FieldDescriptor object for this field.
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  The returned function has one argument:
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    message: Message instance containing this field, or a weakref proxy
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      of same.
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  That function in turn returns a default value for this field.  The default
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    value may refer back to |message| via a weak reference.
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if field.label == _FieldDescriptor.LABEL_REPEATED:
263ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    if field.has_default_value and field.default_value != []:
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      raise ValueError('Repeated field default value not empty list: %s' % (
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          field.default_value))
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if field.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE:
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # We can't look at _concrete_class yet since it might not have
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # been set.  (Depends on order in which we initialize the classes).
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      message_type = field.message_type
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      def MakeRepeatedMessageDefault(message):
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return containers.RepeatedCompositeFieldContainer(
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            message._listener_for_children, field.message_type)
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return MakeRepeatedMessageDefault
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else:
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      type_checker = type_checkers.GetTypeChecker(field.cpp_type, field.type)
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      def MakeRepeatedScalarDefault(message):
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return containers.RepeatedScalarFieldContainer(
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            message._listener_for_children, type_checker)
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return MakeRepeatedScalarDefault
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if field.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE:
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # _concrete_class may not yet be initialized.
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    message_type = field.message_type
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    def MakeSubMessageDefault(message):
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      result = message_type._concrete_class()
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      result._SetListener(message._listener_for_children)
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return result
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return MakeSubMessageDefault
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def MakeScalarDefault(message):
291ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    # TODO(protobuf-team): This may be broken since there may not be
292ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    # default_value.  Combine with has_default_value somehow.
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return field.default_value
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return MakeScalarDefault
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def _AddInitMethod(message_descriptor, cls):
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Adds an __init__ method to cls."""
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fields = message_descriptor.fields
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def init(self, **kwargs):
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._cached_byte_size = 0
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._cached_byte_size_dirty = len(kwargs) > 0
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._fields = {}
304ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    # _unknown_fields is () when empty for efficiency, and will be turned into
305ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    # a list if fields are added.
306ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    self._unknown_fields = ()
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._is_present_in_parent = False
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._listener = message_listener_mod.NullMessageListener()
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._listener_for_children = _Listener(self)
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for field_name, field_value in kwargs.iteritems():
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      field = _GetFieldByName(message_descriptor, field_name)
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if field is None:
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        raise TypeError("%s() got an unexpected keyword argument '%s'" %
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        (message_descriptor.name, field_name))
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if field.label == _FieldDescriptor.LABEL_REPEATED:
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        copy = field._default_constructor(self)
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if field.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE:  # Composite
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          for val in field_value:
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            copy.add().MergeFrom(val)
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        else:  # Scalar
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          copy.extend(field_value)
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self._fields[field] = copy
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      elif field.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE:
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        copy = field._default_constructor(self)
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        copy.MergeFrom(field_value)
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self._fields[field] = copy
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      else:
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        setattr(self, field_name, field_value)
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  init.__module__ = None
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  init.__doc__ = None
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cls.__init__ = init
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def _GetFieldByName(message_descriptor, field_name):
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Returns a field descriptor by field name.
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Args:
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    message_descriptor: A Descriptor describing all fields in message.
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    field_name: The name of the field to retrieve.
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Returns:
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    The field descriptor associated with the field name.
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  try:
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return message_descriptor.fields_by_name[field_name]
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  except KeyError:
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    raise ValueError('Protocol message has no "%s" field.' % field_name)
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def _AddPropertiesForFields(descriptor, cls):
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Adds properties for all fields in this protocol message type."""
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for field in descriptor.fields:
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    _AddPropertiesForField(field, cls)
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if descriptor.is_extendable:
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # _ExtensionDict is just an adaptor with no state so we allocate a new one
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # every time it is accessed.
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cls.Extensions = property(lambda self: _ExtensionDict(self))
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def _AddPropertiesForField(field, cls):
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Adds a public property for a protocol message field.
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Clients can use this property to get and (in the case
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  of non-repeated scalar fields) directly set the value
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  of a protocol message field.
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Args:
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    field: A FieldDescriptor for this field.
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cls: The class we're constructing.
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # Catch it if we add other types that we should
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # handle specially here.
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert _FieldDescriptor.MAX_CPPTYPE == 10
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  constant_name = field.name.upper() + "_FIELD_NUMBER"
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  setattr(cls, constant_name, field.number)
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if field.label == _FieldDescriptor.LABEL_REPEATED:
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    _AddPropertiesForRepeatedField(field, cls)
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  elif field.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE:
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    _AddPropertiesForNonRepeatedCompositeField(field, cls)
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else:
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    _AddPropertiesForNonRepeatedScalarField(field, cls)
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def _AddPropertiesForRepeatedField(field, cls):
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Adds a public property for a "repeated" protocol message field.  Clients
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  can use this property to get the value of the field, which will be either a
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  _RepeatedScalarFieldContainer or _RepeatedCompositeFieldContainer (see
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  below).
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Note that when clients add values to these containers, we perform
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  type-checking in the case of repeated scalar fields, and we also set any
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  necessary "has" bits as a side-effect.
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Args:
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    field: A FieldDescriptor for this field.
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cls: The class we're constructing.
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  proto_field_name = field.name
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  property_name = _PropertyName(proto_field_name)
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def getter(self):
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    field_value = self._fields.get(field)
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if field_value is None:
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # Construct a new object to represent this field.
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      field_value = field._default_constructor(self)
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # Atomically check if another thread has preempted us and, if not, swap
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # in the new object we just created.  If someone has preempted us, we
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # take that object and discard ours.
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # WARNING:  We are relying on setdefault() being atomic.  This is true
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      #   in CPython but we haven't investigated others.  This warning appears
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      #   in several other locations in this file.
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      field_value = self._fields.setdefault(field, field_value)
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return field_value
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  getter.__module__ = None
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  getter.__doc__ = 'Getter for %s.' % proto_field_name
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # We define a setter just so we can throw an exception with a more
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # helpful error message.
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def setter(self, new_value):
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    raise AttributeError('Assignment not allowed to repeated field '
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         '"%s" in protocol message object.' % proto_field_name)
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  doc = 'Magic attribute generated for "%s" proto field.' % proto_field_name
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  setattr(cls, property_name, property(getter, setter, doc=doc))
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def _AddPropertiesForNonRepeatedScalarField(field, cls):
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Adds a public property for a nonrepeated, scalar protocol message field.
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Clients can use this property to get and directly set the value of the field.
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Note that when the client sets the value of a field by using this property,
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  all necessary "has" bits are set as a side-effect, and we also perform
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  type-checking.
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Args:
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    field: A FieldDescriptor for this field.
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cls: The class we're constructing.
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  proto_field_name = field.name
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  property_name = _PropertyName(proto_field_name)
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  type_checker = type_checkers.GetTypeChecker(field.cpp_type, field.type)
4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  default_value = field.default_value
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  valid_values = set()
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def getter(self):
448ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    # TODO(protobuf-team): This may be broken since there may not be
449ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    # default_value.  Combine with has_default_value somehow.
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self._fields.get(field, default_value)
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  getter.__module__ = None
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  getter.__doc__ = 'Getter for %s.' % proto_field_name
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def setter(self, new_value):
4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    type_checker.CheckValue(new_value)
4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._fields[field] = new_value
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Check _cached_byte_size_dirty inline to improve performance, since scalar
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # setters are called frequently.
4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if not self._cached_byte_size_dirty:
4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self._Modified()
4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  setter.__module__ = None
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  setter.__doc__ = 'Setter for %s.' % proto_field_name
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # Add a property to encapsulate the getter/setter.
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  doc = 'Magic attribute generated for "%s" proto field.' % proto_field_name
4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  setattr(cls, property_name, property(getter, setter, doc=doc))
4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def _AddPropertiesForNonRepeatedCompositeField(field, cls):
4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Adds a public property for a nonrepeated, composite protocol message field.
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  A composite field is a "group" or "message" field.
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Clients can use this property to get the value of the field, but cannot
4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assign to the property directly.
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Args:
4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    field: A FieldDescriptor for this field.
4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cls: The class we're constructing.
4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """
4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # TODO(robinson): Remove duplication with similar method
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # for non-repeated scalars.
4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  proto_field_name = field.name
4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  property_name = _PropertyName(proto_field_name)
484ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
485ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  # TODO(komarek): Can anyone explain to me why we cache the message_type this
486ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  # way, instead of referring to field.message_type inside of getter(self)?
487ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  # What if someone sets message_type later on (which makes for simpler
488ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  # dyanmic proto descriptor and class creation code).
4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  message_type = field.message_type
4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def getter(self):
4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    field_value = self._fields.get(field)
4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if field_value is None:
4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # Construct a new object to represent this field.
495ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      field_value = message_type._concrete_class()  # use field.message_type?
4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      field_value._SetListener(self._listener_for_children)
4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # Atomically check if another thread has preempted us and, if not, swap
4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # in the new object we just created.  If someone has preempted us, we
5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # take that object and discard ours.
5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # WARNING:  We are relying on setdefault() being atomic.  This is true
5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      #   in CPython but we haven't investigated others.  This warning appears
5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      #   in several other locations in this file.
5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      field_value = self._fields.setdefault(field, field_value)
5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return field_value
5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  getter.__module__ = None
5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  getter.__doc__ = 'Getter for %s.' % proto_field_name
5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # We define a setter just so we can throw an exception with a more
5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # helpful error message.
5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def setter(self, new_value):
5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    raise AttributeError('Assignment not allowed to composite field '
5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         '"%s" in protocol message object.' % proto_field_name)
5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # Add a property to encapsulate the getter.
5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  doc = 'Magic attribute generated for "%s" proto field.' % proto_field_name
5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  setattr(cls, property_name, property(getter, setter, doc=doc))
5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def _AddPropertiesForExtensions(descriptor, cls):
5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Adds properties for all fields in this protocol message type."""
5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  extension_dict = descriptor.extensions_by_name
5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for extension_name, extension_field in extension_dict.iteritems():
5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    constant_name = extension_name.upper() + "_FIELD_NUMBER"
5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    setattr(cls, constant_name, extension_field.number)
5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def _AddStaticMethods(cls):
5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # TODO(robinson): This probably needs to be thread-safe(?)
5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def RegisterExtension(extension_handle):
5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    extension_handle.containing_type = cls.DESCRIPTOR
5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    _AttachFieldHelpers(cls, extension_handle)
5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Try to insert our extension, failing if an extension with the same number
5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # already exists.
5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    actual_handle = cls._extensions_by_number.setdefault(
5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        extension_handle.number, extension_handle)
5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if actual_handle is not extension_handle:
5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      raise AssertionError(
5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          'Extensions "%s" and "%s" both try to extend message type "%s" with '
5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          'field number %d.' %
5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          (extension_handle.full_name, actual_handle.full_name,
5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           cls.DESCRIPTOR.full_name, extension_handle.number))
5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cls._extensions_by_name[extension_handle.full_name] = extension_handle
5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    handle = extension_handle  # avoid line wrapping
5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if _IsMessageSetExtension(handle):
5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # MessageSet extension.  Also register under type name.
5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cls._extensions_by_name[
5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          extension_handle.message_type.full_name] = extension_handle
5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cls.RegisterExtension = staticmethod(RegisterExtension)
5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def FromString(s):
5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    message = cls()
5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    message.MergeFromString(s)
5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return message
5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cls.FromString = staticmethod(FromString)
5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def _IsPresent(item):
5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Given a (FieldDescriptor, value) tuple from _fields, return true if the
5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  value should be included in the list returned by ListFields()."""
5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if item[0].label == _FieldDescriptor.LABEL_REPEATED:
5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return bool(item[1])
5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  elif item[0].cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE:
5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return item[1]._is_present_in_parent
5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else:
5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return True
5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def _AddListFieldsMethod(message_descriptor, cls):
5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Helper for _AddMessageMethods()."""
5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def ListFields(self):
5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    all_fields = [item for item in self._fields.iteritems() if _IsPresent(item)]
5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    all_fields.sort(key = lambda item: item[0].number)
5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return all_fields
5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cls.ListFields = ListFields
5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def _AddHasFieldMethod(message_descriptor, cls):
5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Helper for _AddMessageMethods()."""
5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  singular_fields = {}
5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for field in message_descriptor.fields:
5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if field.label != _FieldDescriptor.LABEL_REPEATED:
5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      singular_fields[field.name] = field
5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def HasField(self, field_name):
5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    try:
5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      field = singular_fields[field_name]
5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    except KeyError:
5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      raise ValueError(
5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          'Protocol message has no singular "%s" field.' % field_name)
5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if field.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE:
6015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      value = self._fields.get(field)
6025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return value is not None and value._is_present_in_parent
6035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else:
6045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return field in self._fields
6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cls.HasField = HasField
6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def _AddClearFieldMethod(message_descriptor, cls):
6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Helper for _AddMessageMethods()."""
6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def ClearField(self, field_name):
6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    try:
6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      field = message_descriptor.fields_by_name[field_name]
6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    except KeyError:
6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      raise ValueError('Protocol message has no "%s" field.' % field_name)
6155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if field in self._fields:
6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # Note:  If the field is a sub-message, its listener will still point
6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      #   at us.  That's fine, because the worst than can happen is that it
6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      #   will call _Modified() and invalidate our byte size.  Big deal.
6205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      del self._fields[field]
6215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Always call _Modified() -- even if nothing was changed, this is
6235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # a mutating method, and thus calling it should cause the field to become
6245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # present in the parent message.
6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._Modified()
6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cls.ClearField = ClearField
6285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def _AddClearExtensionMethod(cls):
6315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Helper for _AddMessageMethods()."""
6325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def ClearExtension(self, extension_handle):
6335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    _VerifyExtensionHandle(self, extension_handle)
6345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Similar to ClearField(), above.
6365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if extension_handle in self._fields:
6375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      del self._fields[extension_handle]
6385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._Modified()
6395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cls.ClearExtension = ClearExtension
6405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def _AddClearMethod(message_descriptor, cls):
6435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Helper for _AddMessageMethods()."""
6445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def Clear(self):
6455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Clear fields.
6465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._fields = {}
647ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    self._unknown_fields = ()
6485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._Modified()
6495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cls.Clear = Clear
6505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def _AddHasExtensionMethod(cls):
6535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Helper for _AddMessageMethods()."""
6545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def HasExtension(self, extension_handle):
6555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    _VerifyExtensionHandle(self, extension_handle)
6565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if extension_handle.label == _FieldDescriptor.LABEL_REPEATED:
6575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      raise KeyError('"%s" is repeated.' % extension_handle.full_name)
6585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if extension_handle.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE:
6605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      value = self._fields.get(extension_handle)
6615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return value is not None and value._is_present_in_parent
6625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else:
6635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return extension_handle in self._fields
6645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cls.HasExtension = HasExtension
6655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def _AddEqualsMethod(message_descriptor, cls):
6685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Helper for _AddMessageMethods()."""
6695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def __eq__(self, other):
6705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (not isinstance(other, message_mod.Message) or
6715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        other.DESCRIPTOR != self.DESCRIPTOR):
6725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return False
6735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if self is other:
6755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return True
6765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
677ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    if not self.ListFields() == other.ListFields():
678ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      return False
679ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
680ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    # Sort unknown fields because their order shouldn't affect equality test.
681ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    unknown_fields = list(self._unknown_fields)
682ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    unknown_fields.sort()
683ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    other_unknown_fields = list(other._unknown_fields)
684ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    other_unknown_fields.sort()
685ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
686ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    return unknown_fields == other_unknown_fields
6875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cls.__eq__ = __eq__
6895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def _AddStrMethod(message_descriptor, cls):
6925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Helper for _AddMessageMethods()."""
6935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def __str__(self):
6945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return text_format.MessageToString(self)
6955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cls.__str__ = __str__
6965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def _AddUnicodeMethod(unused_message_descriptor, cls):
6995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Helper for _AddMessageMethods()."""
7005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def __unicode__(self):
7025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return text_format.MessageToString(self, as_utf8=True).decode('utf-8')
7035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cls.__unicode__ = __unicode__
7045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def _AddSetListenerMethod(cls):
7075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Helper for _AddMessageMethods()."""
7085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def SetListener(self, listener):
7095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if listener is None:
7105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self._listener = message_listener_mod.NullMessageListener()
7115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else:
7125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self._listener = listener
7135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cls._SetListener = SetListener
7145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def _BytesForNonRepeatedElement(value, field_number, field_type):
7175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Returns the number of bytes needed to serialize a non-repeated element.
7185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  The returned byte count includes space for tag information and any
7195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  other additional space associated with serializing value.
7205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Args:
7225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    value: Value we're serializing.
7235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    field_number: Field number of this value.  (Since the field number
7245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      is stored as part of a varint-encoded tag, this has an impact
7255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      on the total bytes required to serialize the value).
7265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    field_type: The type of the field.  One of the TYPE_* constants
7275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      within FieldDescriptor.
7285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """
7295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  try:
7305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    fn = type_checkers.TYPE_TO_BYTE_SIZE_FN[field_type]
7315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return fn(field_number, value)
7325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  except KeyError:
7335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    raise message_mod.EncodeError('Unrecognized field type: %d' % field_type)
7345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def _AddByteSizeMethod(message_descriptor, cls):
7375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Helper for _AddMessageMethods()."""
7385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def ByteSize(self):
7405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if not self._cached_byte_size_dirty:
7415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return self._cached_byte_size
7425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    size = 0
7445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for field_descriptor, field_value in self.ListFields():
7455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      size += field_descriptor._sizer(field_value)
7465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
747ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    for tag_bytes, value_bytes in self._unknown_fields:
748ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      size += len(tag_bytes) + len(value_bytes)
749ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
7505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._cached_byte_size = size
7515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._cached_byte_size_dirty = False
7525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._listener_for_children.dirty = False
7535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return size
7545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cls.ByteSize = ByteSize
7565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def _AddSerializeToStringMethod(message_descriptor, cls):
7595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Helper for _AddMessageMethods()."""
7605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def SerializeToString(self):
7625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Check if the message has all of its required fields set.
7635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    errors = []
7645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if not self.IsInitialized():
7655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      raise message_mod.EncodeError(
766ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch          'Message %s is missing required fields: %s' % (
767ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch          self.DESCRIPTOR.full_name, ','.join(self.FindInitializationErrors())))
7685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self.SerializePartialToString()
7695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cls.SerializeToString = SerializeToString
7705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def _AddSerializePartialToStringMethod(message_descriptor, cls):
7735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Helper for _AddMessageMethods()."""
7745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def SerializePartialToString(self):
7765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    out = StringIO()
7775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._InternalSerialize(out.write)
7785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return out.getvalue()
7795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cls.SerializePartialToString = SerializePartialToString
7805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def InternalSerialize(self, write_bytes):
7825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for field_descriptor, field_value in self.ListFields():
7835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      field_descriptor._encoder(write_bytes, field_value)
784ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    for tag_bytes, value_bytes in self._unknown_fields:
785ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      write_bytes(tag_bytes)
786ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      write_bytes(value_bytes)
7875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cls._InternalSerialize = InternalSerialize
7885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def _AddMergeFromStringMethod(message_descriptor, cls):
7915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Helper for _AddMessageMethods()."""
7925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def MergeFromString(self, serialized):
7935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    length = len(serialized)
7945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    try:
7955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if self._InternalParse(serialized, 0, length) != length:
7965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        # The only reason _InternalParse would return early is if it
7975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        # encountered an end-group tag.
7985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        raise message_mod.DecodeError('Unexpected end-group tag.')
7995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    except IndexError:
8005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      raise message_mod.DecodeError('Truncated message.')
8015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    except struct.error, e:
8025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      raise message_mod.DecodeError(e)
8035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return length   # Return this for legacy reasons.
8045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cls.MergeFromString = MergeFromString
8055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  local_ReadTag = decoder.ReadTag
8075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  local_SkipField = decoder.SkipField
8085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  decoders_by_tag = cls._decoders_by_tag
8095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def InternalParse(self, buffer, pos, end):
8115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._Modified()
8125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    field_dict = self._fields
813ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    unknown_field_list = self._unknown_fields
8145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    while pos != end:
8155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (tag_bytes, new_pos) = local_ReadTag(buffer, pos)
8165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      field_decoder = decoders_by_tag.get(tag_bytes)
8175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if field_decoder is None:
818ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch        value_start_pos = new_pos
8195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        new_pos = local_SkipField(buffer, new_pos, end, tag_bytes)
8205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if new_pos == -1:
8215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          return pos
822ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch        if not unknown_field_list:
823ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch          unknown_field_list = self._unknown_fields = []
824ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch        unknown_field_list.append((tag_bytes, buffer[value_start_pos:new_pos]))
8255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        pos = new_pos
8265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      else:
8275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        pos = field_decoder(buffer, new_pos, end, self, field_dict)
8285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return pos
8295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cls._InternalParse = InternalParse
8305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def _AddIsInitializedMethod(message_descriptor, cls):
8335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Adds the IsInitialized and FindInitializationError methods to the
8345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  protocol message class."""
8355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  required_fields = [field for field in message_descriptor.fields
8375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           if field.label == _FieldDescriptor.LABEL_REQUIRED]
8385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def IsInitialized(self, errors=None):
8405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Checks if all required fields of a message are set.
8415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
8435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      errors:  A list which, if provided, will be populated with the field
8445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               paths of all missing required fields.
8455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
8475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      True iff the specified message has all required fields set.
8485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
8495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Performance is critical so we avoid HasField() and ListFields().
8515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for field in required_fields:
8535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (field not in self._fields or
8545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          (field.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE and
8555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           not self._fields[field]._is_present_in_parent)):
8565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if errors is not None:
8575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          errors.extend(self.FindInitializationErrors())
8585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return False
8595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for field, value in self._fields.iteritems():
8615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if field.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE:
8625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if field.label == _FieldDescriptor.LABEL_REPEATED:
8635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          for element in value:
8645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            if not element.IsInitialized():
8655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              if errors is not None:
8665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                errors.extend(self.FindInitializationErrors())
8675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)              return False
8685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        elif value._is_present_in_parent and not value.IsInitialized():
8695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          if errors is not None:
8705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            errors.extend(self.FindInitializationErrors())
8715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          return False
8725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return True
8745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cls.IsInitialized = IsInitialized
8765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def FindInitializationErrors(self):
8785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Finds required fields which are not initialized.
8795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
8815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      A list of strings.  Each string is a path to an uninitialized field from
8825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      the top-level message, e.g. "foo.bar[5].baz".
8835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
8845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    errors = []  # simplify things
8865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for field in required_fields:
8885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if not self.HasField(field.name):
8895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        errors.append(field.name)
8905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for field, value in self.ListFields():
8925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if field.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE:
8935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if field.is_extension:
8945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          name = "(%s)" % field.full_name
8955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        else:
8965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          name = field.name
8975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if field.label == _FieldDescriptor.LABEL_REPEATED:
8995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          for i in xrange(len(value)):
9005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            element = value[i]
9015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            prefix = "%s[%d]." % (name, i)
9025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            sub_errors = element.FindInitializationErrors()
9035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            errors += [ prefix + error for error in sub_errors ]
9045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        else:
9055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          prefix = name + "."
9065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          sub_errors = value.FindInitializationErrors()
9075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          errors += [ prefix + error for error in sub_errors ]
9085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return errors
9105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cls.FindInitializationErrors = FindInitializationErrors
9125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def _AddMergeFromMethod(cls):
9155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  LABEL_REPEATED = _FieldDescriptor.LABEL_REPEATED
9165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CPPTYPE_MESSAGE = _FieldDescriptor.CPPTYPE_MESSAGE
9175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def MergeFrom(self, msg):
9195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if not isinstance(msg, cls):
9205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      raise TypeError(
921ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch          "Parameter to MergeFrom() must be instance of same class: "
922ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch          "expected %s got %s." % (cls.__name__, type(msg).__name__))
9235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    assert msg is not self
9255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._Modified()
9265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    fields = self._fields
9285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for field, value in msg._fields.iteritems():
9305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if field.label == LABEL_REPEATED:
9315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        field_value = fields.get(field)
9325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if field_value is None:
9335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          # Construct a new object to represent this field.
9345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          field_value = field._default_constructor(self)
9355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          fields[field] = field_value
9365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        field_value.MergeFrom(value)
9375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      elif field.cpp_type == CPPTYPE_MESSAGE:
9385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if value._is_present_in_parent:
9395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          field_value = fields.get(field)
9405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          if field_value is None:
9415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            # Construct a new object to represent this field.
9425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            field_value = field._default_constructor(self)
9435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            fields[field] = field_value
9445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          field_value.MergeFrom(value)
9455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      else:
9465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        self._fields[field] = value
947ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
948ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch    if msg._unknown_fields:
949ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      if not self._unknown_fields:
950ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch        self._unknown_fields = []
951ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      self._unknown_fields.extend(msg._unknown_fields)
952ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
9535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cls.MergeFrom = MergeFrom
9545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def _AddMessageMethods(message_descriptor, cls):
9575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Adds implementations of all Message methods to cls."""
9585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  _AddListFieldsMethod(message_descriptor, cls)
9595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  _AddHasFieldMethod(message_descriptor, cls)
9605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  _AddClearFieldMethod(message_descriptor, cls)
9615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if message_descriptor.is_extendable:
9625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    _AddClearExtensionMethod(cls)
9635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    _AddHasExtensionMethod(cls)
9645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  _AddClearMethod(message_descriptor, cls)
9655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  _AddEqualsMethod(message_descriptor, cls)
9665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  _AddStrMethod(message_descriptor, cls)
9675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  _AddUnicodeMethod(message_descriptor, cls)
9685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  _AddSetListenerMethod(cls)
9695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  _AddByteSizeMethod(message_descriptor, cls)
9705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  _AddSerializeToStringMethod(message_descriptor, cls)
9715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  _AddSerializePartialToStringMethod(message_descriptor, cls)
9725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  _AddMergeFromStringMethod(message_descriptor, cls)
9735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  _AddIsInitializedMethod(message_descriptor, cls)
9745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  _AddMergeFromMethod(cls)
9755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def _AddPrivateHelperMethods(cls):
9785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Adds implementation of private helper methods to cls."""
9795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def Modified(self):
9815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Sets the _cached_byte_size_dirty bit to true,
9825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    and propagates this to our listener iff this was a state change.
9835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
9845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Note:  Some callers check _cached_byte_size_dirty before calling
9865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    #   _Modified() as an extra optimization.  So, if this method is ever
9875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    #   changed such that it does stuff even when _cached_byte_size_dirty is
9885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    #   already true, the callers need to be updated.
9895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if not self._cached_byte_size_dirty:
9905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self._cached_byte_size_dirty = True
9915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self._listener_for_children.dirty = True
9925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self._is_present_in_parent = True
9935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self._listener.Modified()
9945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cls._Modified = Modified
9965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cls.SetInParent = Modified
9975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class _Listener(object):
10005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """MessageListener implementation that a parent message registers with its
10025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  child message.
10035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  In order to support semantics like:
10055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    foo.bar.baz.qux = 23
10075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    assert foo.HasField('bar')
10085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ...child objects must have back references to their parents.
10105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  This helper class is at the heart of this support.
10115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """
10125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def __init__(self, parent_message):
10145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Args:
10155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      parent_message: The message whose _Modified() method we should call when
10165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        we receive Modified() messages.
10175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
10185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # This listener establishes a back reference from a child (contained) object
10195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # to its parent (containing) object.  We make this a weak reference to avoid
10205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # creating cyclic garbage when the client finishes with the 'parent' object
10215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # in the tree.
10225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if isinstance(parent_message, weakref.ProxyType):
10235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self._parent_message_weakref = parent_message
10245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else:
10255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self._parent_message_weakref = weakref.proxy(parent_message)
10265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # As an optimization, we also indicate directly on the listener whether
10285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # or not the parent message is dirty.  This way we can avoid traversing
10295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # up the tree in the common case.
10305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.dirty = False
10315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def Modified(self):
10335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if self.dirty:
10345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return
10355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    try:
10365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # Propagate the signal to our parents iff this is the first field set.
10375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self._parent_message_weakref._Modified()
10385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    except ReferenceError:
10395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # We can get here if a client has kept a reference to a child object,
10405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # and is now setting a field on it, but the child's parent has been
10415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # garbage-collected.  This is not an error.
10425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pass
10435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# TODO(robinson): Move elsewhere?  This file is getting pretty ridiculous...
10465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# TODO(robinson): Unify error handling of "unknown extension" crap.
10475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# TODO(robinson): Support iteritems()-style iteration over all
10485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# extensions with the "has" bits turned on?
10495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class _ExtensionDict(object):
10505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Dict-like container for supporting an indexable "Extensions"
10525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  field on proto instances.
10535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Note that in all cases we expect extension handles to be
10555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FieldDescriptors.
10565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """
10575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def __init__(self, extended_message):
10595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """extended_message: Message instance for which we are the Extensions dict.
10605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
10615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._extended_message = extended_message
10635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def __getitem__(self, extension_handle):
10655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Returns the current value of the given extension handle."""
10665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    _VerifyExtensionHandle(self._extended_message, extension_handle)
10685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    result = self._extended_message._fields.get(extension_handle)
10705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if result is not None:
10715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return result
10725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if extension_handle.label == _FieldDescriptor.LABEL_REPEATED:
10745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      result = extension_handle._default_constructor(self._extended_message)
10755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    elif extension_handle.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE:
10765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      result = extension_handle.message_type._concrete_class()
10775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      try:
10785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        result._SetListener(self._extended_message._listener_for_children)
10795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      except ReferenceError:
10805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        pass
10815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else:
10825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # Singular scalar -- just return the default without inserting into the
10835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      # dict.
10845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return extension_handle.default_value
10855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Atomically check if another thread has preempted us and, if not, swap
10875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # in the new object we just created.  If someone has preempted us, we
10885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # take that object and discard ours.
10895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # WARNING:  We are relying on setdefault() being atomic.  This is true
10905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    #   in CPython but we haven't investigated others.  This warning appears
10915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    #   in several other locations in this file.
10925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    result = self._extended_message._fields.setdefault(
10935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        extension_handle, result)
10945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return result
10965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def __eq__(self, other):
10985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if not isinstance(other, self.__class__):
10995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return False
11005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    my_fields = self._extended_message.ListFields()
11025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    other_fields = other._extended_message.ListFields()
11035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Get rid of non-extension fields.
11055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    my_fields    = [ field for field in my_fields    if field.is_extension ]
11065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    other_fields = [ field for field in other_fields if field.is_extension ]
11075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return my_fields == other_fields
11095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def __ne__(self, other):
11115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return not self == other
11125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def __hash__(self):
11145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    raise TypeError('unhashable object')
11155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # Note that this is only meaningful for non-repeated, scalar extension
11175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # fields.  Note also that we may have to call _Modified() when we do
11185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # successfully set a field this way, to set any necssary "has" bits in the
11195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # ancestors of the extended message.
11205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def __setitem__(self, extension_handle, value):
11215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """If extension_handle specifies a non-repeated, scalar extension
11225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    field, sets the value of that field.
11235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
11245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    _VerifyExtensionHandle(self._extended_message, extension_handle)
11265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (extension_handle.label == _FieldDescriptor.LABEL_REPEATED or
11285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        extension_handle.cpp_type == _FieldDescriptor.CPPTYPE_MESSAGE):
11295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      raise TypeError(
11305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          'Cannot assign to extension "%s" because it is a repeated or '
11315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          'composite type.' % extension_handle.full_name)
11325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # It's slightly wasteful to lookup the type checker each time,
11345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # but we expect this to be a vanishingly uncommon case anyway.
11355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    type_checker = type_checkers.GetTypeChecker(
11365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        extension_handle.cpp_type, extension_handle.type)
11375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    type_checker.CheckValue(value)
11385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._extended_message._fields[extension_handle] = value
11395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self._extended_message._Modified()
11405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def _FindExtensionByName(self, name):
11425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """Tries to find a known extension with the specified name.
11435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Args:
11455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      name: Extension full name.
11465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Returns:
11485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      Extension field descriptor.
11495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    """
11505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return self._extended_message._extensions_by_name.get(name, None)
1151