| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919 | # Protocol Buffers - Google's data interchange format# Copyright 2008 Google Inc.  All rights reserved.# https://developers.google.com/protocol-buffers/## Redistribution and use in source and binary forms, with or without# modification, are permitted provided that the following conditions are# met:##     * Redistributions of source code must retain the above copyright# notice, this list of conditions and the following disclaimer.#     * Redistributions in binary form must reproduce the above# copyright notice, this list of conditions and the following disclaimer# in the documentation and/or other materials provided with the# distribution.#     * Neither the name of Google Inc. nor the names of its# contributors may be used to endorse or promote products derived from# this software without specific prior written permission.## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.# Copyright 2007 Google Inc. All Rights Reserved."""Contains routines for printing protocol messages in text format."""__author__ = 'kenton@google.com (Kenton Varda)'import ioimport reimport sixif six.PY3:  long = intfrom google.protobuf.internal import type_checkersfrom google.protobuf import descriptorfrom google.protobuf import text_encoding__all__ = ['MessageToString', 'PrintMessage', 'PrintField',           'PrintFieldValue', 'Merge']_INTEGER_CHECKERS = (type_checkers.Uint32ValueChecker(),                     type_checkers.Int32ValueChecker(),                     type_checkers.Uint64ValueChecker(),                     type_checkers.Int64ValueChecker())_FLOAT_INFINITY = re.compile('-?inf(?:inity)?f?', re.IGNORECASE)_FLOAT_NAN = re.compile('nanf?', re.IGNORECASE)_FLOAT_TYPES = frozenset([descriptor.FieldDescriptor.CPPTYPE_FLOAT,                          descriptor.FieldDescriptor.CPPTYPE_DOUBLE])class Error(Exception):  """Top-level module error for text_format."""class ParseError(Error):  """Thrown in case of ASCII parsing error."""def MessageToString(message, as_utf8=False, as_one_line=False,                    pointy_brackets=False, use_index_order=False,                    float_format=None):  """Convert protobuf message to text format.  Floating point values can be formatted compactly with 15 digits of  precision (which is the most that IEEE 754 "double" can guarantee)  using float_format='.15g'.  Args:    message: The protocol buffers message.    as_utf8: Produce text output in UTF8 format.    as_one_line: Don't introduce newlines between fields.    pointy_brackets: If True, use angle brackets instead of curly braces for      nesting.    use_index_order: If True, print fields of a proto message using the order      defined in source code instead of the field number. By default, use the      field number order.    float_format: If set, use this to specify floating point number formatting      (per the "Format Specification Mini-Language"); otherwise, str() is used.  Returns:    A string of the text formatted protocol buffer message.  """  out = io.BytesIO()  PrintMessage(message, out, as_utf8=as_utf8, as_one_line=as_one_line,               pointy_brackets=pointy_brackets,               use_index_order=use_index_order,               float_format=float_format)  result = out.getvalue()  out.close()  if as_one_line:    return result.rstrip()  return resultdef _IsMapEntry(field):  return (field.type == descriptor.FieldDescriptor.TYPE_MESSAGE and          field.message_type.has_options and          field.message_type.GetOptions().map_entry)def PrintMessage(message, out, indent=0, as_utf8=False, as_one_line=False,                 pointy_brackets=False, use_index_order=False,                 float_format=None):  fields = message.ListFields()  if use_index_order:    fields.sort(key=lambda x: x[0].index)  for field, value in fields:    if _IsMapEntry(field):      for key in sorted(value):        # This is slow for maps with submessage entires because it copies the        # entire tree.  Unfortunately this would take significant refactoring        # of this file to work around.        #        # TODO(haberman): refactor and optimize if this becomes an issue.        entry_submsg = field.message_type._concrete_class(            key=key, value=value[key])        PrintField(field, entry_submsg, out, indent, as_utf8, as_one_line,                   pointy_brackets=pointy_brackets,                   use_index_order=use_index_order, float_format=float_format)    elif field.label == descriptor.FieldDescriptor.LABEL_REPEATED:      for element in value:        PrintField(field, element, out, indent, as_utf8, as_one_line,                   pointy_brackets=pointy_brackets,                   use_index_order=use_index_order,                   float_format=float_format)    else:      PrintField(field, value, out, indent, as_utf8, as_one_line,                 pointy_brackets=pointy_brackets,                 use_index_order=use_index_order,                 float_format=float_format)def PrintField(field, value, out, indent=0, as_utf8=False, as_one_line=False,               pointy_brackets=False, use_index_order=False, float_format=None):  """Print a single field name/value pair.  For repeated fields, the value  should be a single element."""  out.write(' ' * indent)  if field.is_extension:    out.write('[')    if (field.containing_type.GetOptions().message_set_wire_format and        field.type == descriptor.FieldDescriptor.TYPE_MESSAGE and        field.message_type == field.extension_scope and        field.label == descriptor.FieldDescriptor.LABEL_OPTIONAL):      out.write(field.message_type.full_name)    else:      out.write(field.full_name)    out.write(']')  elif field.type == descriptor.FieldDescriptor.TYPE_GROUP:    # For groups, use the capitalized name.    out.write(field.message_type.name)  else:    if isinstance(field.name, six.text_type):      name = field.name.encode('utf-8')    else:      name = field.name    out.write(name)  if field.cpp_type != descriptor.FieldDescriptor.CPPTYPE_MESSAGE:    # The colon is optional in this case, but our cross-language golden files    # don't include it.    out.write(': ')  PrintFieldValue(field, value, out, indent, as_utf8, as_one_line,                  pointy_brackets=pointy_brackets,                  use_index_order=use_index_order,                  float_format=float_format)  if as_one_line:    out.write(' ')  else:    out.write('\n')def PrintFieldValue(field, value, out, indent=0, as_utf8=False,                    as_one_line=False, pointy_brackets=False,                    use_index_order=False,                    float_format=None):  """Print a single field value (not including name).  For repeated fields,  the value should be a single element."""  if pointy_brackets:    openb = '<'    closeb = '>'  else:    openb = '{'    closeb = '}'  if field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE:    if as_one_line:      out.write(' %s ' % openb)      PrintMessage(value, out, indent, as_utf8, as_one_line,                   pointy_brackets=pointy_brackets,                   use_index_order=use_index_order,                   float_format=float_format)      out.write(closeb)    else:      out.write(' %s\n' % openb)      PrintMessage(value, out, indent + 2, as_utf8, as_one_line,                   pointy_brackets=pointy_brackets,                   use_index_order=use_index_order,                   float_format=float_format)      out.write(' ' * indent + closeb)  elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_ENUM:    enum_value = field.enum_type.values_by_number.get(value, None)    if enum_value is not None:      out.write(enum_value.name)    else:      out.write(str(value))  elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_STRING:    out.write('\"')    if isinstance(value, six.text_type):      out_value = value.encode('utf-8')    else:      out_value = value    if field.type == descriptor.FieldDescriptor.TYPE_BYTES:      # We need to escape non-UTF8 chars in TYPE_BYTES field.      out_as_utf8 = False    else:      out_as_utf8 = as_utf8    out.write(text_encoding.CEscape(out_value, out_as_utf8))    out.write('\"')  elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_BOOL:    if value:      out.write('true')    else:      out.write('false')  elif field.cpp_type in _FLOAT_TYPES and float_format is not None:    out.write('{1:{0}}'.format(float_format, value))  else:    out.write(str(value))def Parse(text, message):  """Parses an ASCII representation of a protocol message into a message.  Args:    text: Message ASCII representation.    message: A protocol buffer message to merge into.  Returns:    The same message passed as argument.  Raises:    ParseError: On ASCII parsing problems.  """  if not isinstance(text, str): text = text.decode('utf-8')  return ParseLines(text.split('\n'), message)def Merge(text, message):  """Parses an ASCII representation of a protocol message into a message.  Like Parse(), but allows repeated values for a non-repeated field, and uses  the last one.  Args:    text: Message ASCII representation.    message: A protocol buffer message to merge into.  Returns:    The same message passed as argument.  Raises:    ParseError: On ASCII parsing problems.  """  return MergeLines(text.split('\n'), message)def ParseLines(lines, message):  """Parses an ASCII representation of a protocol message into a message.  Args:    lines: An iterable of lines of a message's ASCII representation.    message: A protocol buffer message to merge into.  Returns:    The same message passed as argument.  Raises:    ParseError: On ASCII parsing problems.  """  _ParseOrMerge(lines, message, False)  return messagedef MergeLines(lines, message):  """Parses an ASCII representation of a protocol message into a message.  Args:    lines: An iterable of lines of a message's ASCII representation.    message: A protocol buffer message to merge into.  Returns:    The same message passed as argument.  Raises:    ParseError: On ASCII parsing problems.  """  _ParseOrMerge(lines, message, True)  return messagedef _ParseOrMerge(lines, message, allow_multiple_scalars):  """Converts an ASCII representation of a protocol message into a message.  Args:    lines: Lines of a message's ASCII representation.    message: A protocol buffer message to merge into.    allow_multiple_scalars: Determines if repeated values for a non-repeated      field are permitted, e.g., the string "foo: 1 foo: 2" for a      required/optional field named "foo".  Raises:    ParseError: On ASCII parsing problems.  """  tokenizer = _Tokenizer(lines)  while not tokenizer.AtEnd():    _MergeField(tokenizer, message, allow_multiple_scalars)def _MergeField(tokenizer, message, allow_multiple_scalars):  """Merges a single protocol message field into a message.  Args:    tokenizer: A tokenizer to parse the field name and values.    message: A protocol message to record the data.    allow_multiple_scalars: Determines if repeated values for a non-repeated      field are permitted, e.g., the string "foo: 1 foo: 2" for a      required/optional field named "foo".  Raises:    ParseError: In case of ASCII parsing problems.  """  message_descriptor = message.DESCRIPTOR  if (hasattr(message_descriptor, 'syntax') and      message_descriptor.syntax == 'proto3'):    # Proto3 doesn't represent presence so we can't test if multiple    # scalars have occurred.  We have to allow them.    allow_multiple_scalars = True  if tokenizer.TryConsume('['):    name = [tokenizer.ConsumeIdentifier()]    while tokenizer.TryConsume('.'):      name.append(tokenizer.ConsumeIdentifier())    name = '.'.join(name)    if not message_descriptor.is_extendable:      raise tokenizer.ParseErrorPreviousToken(          'Message type "%s" does not have extensions.' %          message_descriptor.full_name)    # pylint: disable=protected-access    field = message.Extensions._FindExtensionByName(name)    # pylint: enable=protected-access    if not field:      raise tokenizer.ParseErrorPreviousToken(          'Extension "%s" not registered.' % name)    elif message_descriptor != field.containing_type:      raise tokenizer.ParseErrorPreviousToken(          'Extension "%s" does not extend message type "%s".' % (              name, message_descriptor.full_name))    tokenizer.Consume(']')  else:    name = tokenizer.ConsumeIdentifier()    field = message_descriptor.fields_by_name.get(name, None)    # Group names are expected to be capitalized as they appear in the    # .proto file, which actually matches their type names, not their field    # names.    if not field:      field = message_descriptor.fields_by_name.get(name.lower(), None)      if field and field.type != descriptor.FieldDescriptor.TYPE_GROUP:        field = None    if (field and field.type == descriptor.FieldDescriptor.TYPE_GROUP and        field.message_type.name != name):      field = None    if not field:      raise tokenizer.ParseErrorPreviousToken(          'Message type "%s" has no field named "%s".' % (              message_descriptor.full_name, name))  if field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE:    is_map_entry = _IsMapEntry(field)    tokenizer.TryConsume(':')    if tokenizer.TryConsume('<'):      end_token = '>'    else:      tokenizer.Consume('{')      end_token = '}'    if field.label == descriptor.FieldDescriptor.LABEL_REPEATED:      if field.is_extension:        sub_message = message.Extensions[field].add()      elif is_map_entry:        sub_message = field.message_type._concrete_class()      else:        sub_message = getattr(message, field.name).add()    else:      if field.is_extension:        sub_message = message.Extensions[field]      else:        sub_message = getattr(message, field.name)      sub_message.SetInParent()    while not tokenizer.TryConsume(end_token):      if tokenizer.AtEnd():        raise tokenizer.ParseErrorPreviousToken('Expected "%s".' % (end_token))      _MergeField(tokenizer, sub_message, allow_multiple_scalars)    if is_map_entry:      value_cpptype = field.message_type.fields_by_name['value'].cpp_type      if value_cpptype == descriptor.FieldDescriptor.CPPTYPE_MESSAGE:        value = getattr(message, field.name)[sub_message.key]        value.MergeFrom(sub_message.value)      else:        getattr(message, field.name)[sub_message.key] = sub_message.value  else:    _MergeScalarField(tokenizer, message, field, allow_multiple_scalars)  # For historical reasons, fields may optionally be separated by commas or  # semicolons.  if not tokenizer.TryConsume(','):    tokenizer.TryConsume(';')def _MergeScalarField(tokenizer, message, field, allow_multiple_scalars):  """Merges a single protocol message scalar field into a message.  Args:    tokenizer: A tokenizer to parse the field value.    message: A protocol message to record the data.    field: The descriptor of the field to be merged.    allow_multiple_scalars: Determines if repeated values for a non-repeated      field are permitted, e.g., the string "foo: 1 foo: 2" for a      required/optional field named "foo".  Raises:    ParseError: In case of ASCII parsing problems.    RuntimeError: On runtime errors.  """  tokenizer.Consume(':')  value = None  if field.type in (descriptor.FieldDescriptor.TYPE_INT32,                    descriptor.FieldDescriptor.TYPE_SINT32,                    descriptor.FieldDescriptor.TYPE_SFIXED32):    value = tokenizer.ConsumeInt32()  elif field.type in (descriptor.FieldDescriptor.TYPE_INT64,                      descriptor.FieldDescriptor.TYPE_SINT64,                      descriptor.FieldDescriptor.TYPE_SFIXED64):    value = tokenizer.ConsumeInt64()  elif field.type in (descriptor.FieldDescriptor.TYPE_UINT32,                      descriptor.FieldDescriptor.TYPE_FIXED32):    value = tokenizer.ConsumeUint32()  elif field.type in (descriptor.FieldDescriptor.TYPE_UINT64,                      descriptor.FieldDescriptor.TYPE_FIXED64):    value = tokenizer.ConsumeUint64()  elif field.type in (descriptor.FieldDescriptor.TYPE_FLOAT,                      descriptor.FieldDescriptor.TYPE_DOUBLE):    value = tokenizer.ConsumeFloat()  elif field.type == descriptor.FieldDescriptor.TYPE_BOOL:    value = tokenizer.ConsumeBool()  elif field.type == descriptor.FieldDescriptor.TYPE_STRING:    value = tokenizer.ConsumeString()  elif field.type == descriptor.FieldDescriptor.TYPE_BYTES:    value = tokenizer.ConsumeByteString()  elif field.type == descriptor.FieldDescriptor.TYPE_ENUM:    value = tokenizer.ConsumeEnum(field)  else:    raise RuntimeError('Unknown field type %d' % field.type)  if field.label == descriptor.FieldDescriptor.LABEL_REPEATED:    if field.is_extension:      message.Extensions[field].append(value)    else:      getattr(message, field.name).append(value)  else:    if field.is_extension:      if not allow_multiple_scalars and message.HasExtension(field):        raise tokenizer.ParseErrorPreviousToken(            'Message type "%s" should not have multiple "%s" extensions.' %            (message.DESCRIPTOR.full_name, field.full_name))      else:        message.Extensions[field] = value    else:      if not allow_multiple_scalars and message.HasField(field.name):        raise tokenizer.ParseErrorPreviousToken(            'Message type "%s" should not have multiple "%s" fields.' %            (message.DESCRIPTOR.full_name, field.name))      else:        setattr(message, field.name, value)class _Tokenizer(object):  """Protocol buffer ASCII representation tokenizer.  This class handles the lower level string parsing by splitting it into  meaningful tokens.  It was directly ported from the Java protocol buffer API.  """  _WHITESPACE = re.compile('(\\s|(#.*$))+', re.MULTILINE)  _TOKEN = re.compile(      '[a-zA-Z_][0-9a-zA-Z_+-]*|'           # an identifier      '[0-9+-][0-9a-zA-Z_.+-]*|'            # a number      '\"([^\"\n\\\\]|\\\\.)*(\"|\\\\?$)|'  # a double-quoted string      '\'([^\'\n\\\\]|\\\\.)*(\'|\\\\?$)')  # a single-quoted string  _IDENTIFIER = re.compile(r'\w+')  def __init__(self, lines):    self._position = 0    self._line = -1    self._column = 0    self._token_start = None    self.token = ''    self._lines = iter(lines)    self._current_line = ''    self._previous_line = 0    self._previous_column = 0    self._more_lines = True    self._SkipWhitespace()    self.NextToken()  def AtEnd(self):    """Checks the end of the text was reached.    Returns:      True iff the end was reached.    """    return not self.token  def _PopLine(self):    while len(self._current_line) <= self._column:      try:        self._current_line = next(self._lines)      except StopIteration:        self._current_line = ''        self._more_lines = False        return      else:        self._line += 1        self._column = 0  def _SkipWhitespace(self):    while True:      self._PopLine()      match = self._WHITESPACE.match(self._current_line, self._column)      if not match:        break      length = len(match.group(0))      self._column += length  def TryConsume(self, token):    """Tries to consume a given piece of text.    Args:      token: Text to consume.    Returns:      True iff the text was consumed.    """    if self.token == token:      self.NextToken()      return True    return False  def Consume(self, token):    """Consumes a piece of text.    Args:      token: Text to consume.    Raises:      ParseError: If the text couldn't be consumed.    """    if not self.TryConsume(token):      raise self._ParseError('Expected "%s".' % token)  def ConsumeIdentifier(self):    """Consumes protocol message field identifier.    Returns:      Identifier string.    Raises:      ParseError: If an identifier couldn't be consumed.    """    result = self.token    if not self._IDENTIFIER.match(result):      raise self._ParseError('Expected identifier.')    self.NextToken()    return result  def ConsumeInt32(self):    """Consumes a signed 32bit integer number.    Returns:      The integer parsed.    Raises:      ParseError: If a signed 32bit integer couldn't be consumed.    """    try:      result = ParseInteger(self.token, is_signed=True, is_long=False)    except ValueError as e:      raise self._ParseError(str(e))    self.NextToken()    return result  def ConsumeUint32(self):    """Consumes an unsigned 32bit integer number.    Returns:      The integer parsed.    Raises:      ParseError: If an unsigned 32bit integer couldn't be consumed.    """    try:      result = ParseInteger(self.token, is_signed=False, is_long=False)    except ValueError as e:      raise self._ParseError(str(e))    self.NextToken()    return result  def ConsumeInt64(self):    """Consumes a signed 64bit integer number.    Returns:      The integer parsed.    Raises:      ParseError: If a signed 64bit integer couldn't be consumed.    """    try:      result = ParseInteger(self.token, is_signed=True, is_long=True)    except ValueError as e:      raise self._ParseError(str(e))    self.NextToken()    return result  def ConsumeUint64(self):    """Consumes an unsigned 64bit integer number.    Returns:      The integer parsed.    Raises:      ParseError: If an unsigned 64bit integer couldn't be consumed.    """    try:      result = ParseInteger(self.token, is_signed=False, is_long=True)    except ValueError as e:      raise self._ParseError(str(e))    self.NextToken()    return result  def ConsumeFloat(self):    """Consumes an floating point number.    Returns:      The number parsed.    Raises:      ParseError: If a floating point number couldn't be consumed.    """    try:      result = ParseFloat(self.token)    except ValueError as e:      raise self._ParseError(str(e))    self.NextToken()    return result  def ConsumeBool(self):    """Consumes a boolean value.    Returns:      The bool parsed.    Raises:      ParseError: If a boolean value couldn't be consumed.    """    try:      result = ParseBool(self.token)    except ValueError as e:      raise self._ParseError(str(e))    self.NextToken()    return result  def ConsumeString(self):    """Consumes a string value.    Returns:      The string parsed.    Raises:      ParseError: If a string value couldn't be consumed.    """    the_bytes = self.ConsumeByteString()    try:      return six.text_type(the_bytes, 'utf-8')    except UnicodeDecodeError as e:      raise self._StringParseError(e)  def ConsumeByteString(self):    """Consumes a byte array value.    Returns:      The array parsed (as a string).    Raises:      ParseError: If a byte array value couldn't be consumed.    """    the_list = [self._ConsumeSingleByteString()]    while self.token and self.token[0] in ('\'', '"'):      the_list.append(self._ConsumeSingleByteString())    return b''.join(the_list)  def _ConsumeSingleByteString(self):    """Consume one token of a string literal.    String literals (whether bytes or text) can come in multiple adjacent    tokens which are automatically concatenated, like in C or Python.  This    method only consumes one token.    Raises:      ParseError: When the wrong format data is found.    """    text = self.token    if len(text) < 1 or text[0] not in ('\'', '"'):      raise self._ParseError('Expected string but found: %r' % (text,))    if len(text) < 2 or text[-1] != text[0]:      raise self._ParseError('String missing ending quote: %r' % (text,))    try:      result = text_encoding.CUnescape(text[1:-1])    except ValueError as e:      raise self._ParseError(str(e))    self.NextToken()    return result  def ConsumeEnum(self, field):    try:      result = ParseEnum(field, self.token)    except ValueError as e:      raise self._ParseError(str(e))    self.NextToken()    return result  def ParseErrorPreviousToken(self, message):    """Creates and *returns* a ParseError for the previously read token.    Args:      message: A message to set for the exception.    Returns:      A ParseError instance.    """    return ParseError('%d:%d : %s' % (        self._previous_line + 1, self._previous_column + 1, message))  def _ParseError(self, message):    """Creates and *returns* a ParseError for the current token."""    return ParseError('%d:%d : %s' % (        self._line + 1, self._column + 1, message))  def _StringParseError(self, e):    return self._ParseError('Couldn\'t parse string: ' + str(e))  def NextToken(self):    """Reads the next meaningful token."""    self._previous_line = self._line    self._previous_column = self._column    self._column += len(self.token)    self._SkipWhitespace()    if not self._more_lines:      self.token = ''      return    match = self._TOKEN.match(self._current_line, self._column)    if match:      token = match.group(0)      self.token = token    else:      self.token = self._current_line[self._column]def ParseInteger(text, is_signed=False, is_long=False):  """Parses an integer.  Args:    text: The text to parse.    is_signed: True if a signed integer must be parsed.    is_long: True if a long integer must be parsed.  Returns:    The integer value.  Raises:    ValueError: Thrown Iff the text is not a valid integer.  """  # Do the actual parsing. Exception handling is propagated to caller.  try:    # We force 32-bit values to int and 64-bit values to long to make    # alternate implementations where the distinction is more significant    # (e.g. the C++ implementation) simpler.    if is_long:      result = long(text, 0)    else:      result = int(text, 0)  except ValueError:    raise ValueError('Couldn\'t parse integer: %s' % text)  # Check if the integer is sane. Exceptions handled by callers.  checker = _INTEGER_CHECKERS[2 * int(is_long) + int(is_signed)]  checker.CheckValue(result)  return resultdef ParseFloat(text):  """Parse a floating point number.  Args:    text: Text to parse.  Returns:    The number parsed.  Raises:    ValueError: If a floating point number couldn't be parsed.  """  try:    # Assume Python compatible syntax.    return float(text)  except ValueError:    # Check alternative spellings.    if _FLOAT_INFINITY.match(text):      if text[0] == '-':        return float('-inf')      else:        return float('inf')    elif _FLOAT_NAN.match(text):      return float('nan')    else:      # assume '1.0f' format      try:        return float(text.rstrip('f'))      except ValueError:        raise ValueError('Couldn\'t parse float: %s' % text)def ParseBool(text):  """Parse a boolean value.  Args:    text: Text to parse.  Returns:    Boolean values parsed  Raises:    ValueError: If text is not a valid boolean.  """  if text in ('true', 't', '1'):    return True  elif text in ('false', 'f', '0'):    return False  else:    raise ValueError('Expected "true" or "false".')def ParseEnum(field, value):  """Parse an enum value.  The value can be specified by a number (the enum value), or by  a string literal (the enum name).  Args:    field: Enum field descriptor.    value: String value.  Returns:    Enum value number.  Raises:    ValueError: If the enum value could not be parsed.  """  enum_descriptor = field.enum_type  try:    number = int(value, 0)  except ValueError:    # Identifier.    enum_value = enum_descriptor.values_by_name.get(value, None)    if enum_value is None:      raise ValueError(          'Enum type "%s" has no value named %s.' % (              enum_descriptor.full_name, value))  else:    # Numeric value.    enum_value = enum_descriptor.values_by_number.get(number, None)    if enum_value is None:      raise ValueError(          'Enum type "%s" has no value with number %d.' % (              enum_descriptor.full_name, number))  return enum_value.number
 |