1# Protocol Buffers - Google's data interchange format
2# Copyright 2008 Google Inc.  All rights reserved.
3# https://developers.google.com/protocol-buffers/
4#
5# Redistribution and use in source and binary forms, with or without
6# modification, are permitted provided that the following conditions are
7# met:
8#
9#     * Redistributions of source code must retain the above copyright
10# notice, this list of conditions and the following disclaimer.
11#     * Redistributions in binary form must reproduce the above
12# copyright notice, this list of conditions and the following disclaimer
13# in the documentation and/or other materials provided with the
14# distribution.
15#     * Neither the name of Google Inc. nor the names of its
16# contributors may be used to endorse or promote products derived from
17# this software without specific prior written permission.
18#
19# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
31"""Contains container classes to represent different protocol buffer types.
32
33This file defines container classes which represent categories of protocol
34buffer field types which need extra maintenance. Currently these categories
35are:
36
37-   Repeated scalar fields - These are all repeated fields which aren't
38    composite (e.g. they are of simple types like int32, string, etc).
39-   Repeated composite fields - Repeated fields which are composite. This
40    includes groups and nested messages.
41"""
42
43__author__ = 'petar@google.com (Petar Petrov)'
44
45import sys
46try:
47  # This fallback applies for all versions of Python before 3.3
48  import collections.abc as collections_abc
49except ImportError:
50  import collections as collections_abc
51
52if sys.version_info[0] < 3:
53  # We would use collections_abc.MutableMapping all the time, but in Python 2
54  # it doesn't define __slots__.  This causes two significant problems:
55  #
56  # 1. we can't disallow arbitrary attribute assignment, even if our derived
57  #    classes *do* define __slots__.
58  #
59  # 2. we can't safely derive a C type from it without __slots__ defined (the
60  #    interpreter expects to find a dict at tp_dictoffset, which we can't
61  #    robustly provide.  And we don't want an instance dict anyway.
62  #
63  # So this is the Python 2.7 definition of Mapping/MutableMapping functions
64  # verbatim, except that:
65  # 1. We declare __slots__.
66  # 2. We don't declare this as a virtual base class.  The classes defined
67  #    in collections_abc are the interesting base classes, not us.
68  #
69  # Note: deriving from object is critical.  It is the only thing that makes
70  # this a true type, allowing us to derive from it in C++ cleanly and making
71  # __slots__ properly disallow arbitrary element assignment.
72
73  class Mapping(object):
74    __slots__ = ()
75
76    def get(self, key, default=None):
77      try:
78        return self[key]
79      except KeyError:
80        return default
81
82    def __contains__(self, key):
83      try:
84        self[key]
85      except KeyError:
86        return False
87      else:
88        return True
89
90    def iterkeys(self):
91      return iter(self)
92
93    def itervalues(self):
94      for key in self:
95        yield self[key]
96
97    def iteritems(self):
98      for key in self:
99        yield (key, self[key])
100
101    def keys(self):
102      return list(self)
103
104    def items(self):
105      return [(key, self[key]) for key in self]
106
107    def values(self):
108      return [self[key] for key in self]
109
110    # Mappings are not hashable by default, but subclasses can change this
111    __hash__ = None
112
113    def __eq__(self, other):
114      if not isinstance(other, collections_abc.Mapping):
115        return NotImplemented
116      return dict(self.items()) == dict(other.items())
117
118    def __ne__(self, other):
119      return not (self == other)
120
121  class MutableMapping(Mapping):
122    __slots__ = ()
123
124    __marker = object()
125
126    def pop(self, key, default=__marker):
127      try:
128        value = self[key]
129      except KeyError:
130        if default is self.__marker:
131          raise
132        return default
133      else:
134        del self[key]
135        return value
136
137    def popitem(self):
138      try:
139        key = next(iter(self))
140      except StopIteration:
141        raise KeyError
142      value = self[key]
143      del self[key]
144      return key, value
145
146    def clear(self):
147      try:
148        while True:
149          self.popitem()
150      except KeyError:
151        pass
152
153    def update(*args, **kwds):
154      if len(args) > 2:
155        raise TypeError("update() takes at most 2 positional "
156                        "arguments ({} given)".format(len(args)))
157      elif not args:
158        raise TypeError("update() takes at least 1 argument (0 given)")
159      self = args[0]
160      other = args[1] if len(args) >= 2 else ()
161
162      if isinstance(other, Mapping):
163        for key in other:
164          self[key] = other[key]
165      elif hasattr(other, "keys"):
166        for key in other.keys():
167          self[key] = other[key]
168      else:
169        for key, value in other:
170          self[key] = value
171      for key, value in kwds.items():
172        self[key] = value
173
174    def setdefault(self, key, default=None):
175      try:
176        return self[key]
177      except KeyError:
178        self[key] = default
179      return default
180
181  collections_abc.Mapping.register(Mapping)
182  collections_abc.MutableMapping.register(MutableMapping)
183
184else:
185  # In Python 3 we can just use MutableMapping directly, because it defines
186  # __slots__.
187  MutableMapping = collections_abc.MutableMapping
188
189
190class BaseContainer(object):
191
192  """Base container class."""
193
194  # Minimizes memory usage and disallows assignment to other attributes.
195  __slots__ = ['_message_listener', '_values']
196
197  def __init__(self, message_listener):
198    """
199    Args:
200      message_listener: A MessageListener implementation.
201        The RepeatedScalarFieldContainer will call this object's
202        Modified() method when it is modified.
203    """
204    self._message_listener = message_listener
205    self._values = []
206
207  def __getitem__(self, key):
208    """Retrieves item by the specified key."""
209    return self._values[key]
210
211  def __len__(self):
212    """Returns the number of elements in the container."""
213    return len(self._values)
214
215  def __ne__(self, other):
216    """Checks if another instance isn't equal to this one."""
217    # The concrete classes should define __eq__.
218    return not self == other
219
220  def __hash__(self):
221    raise TypeError('unhashable object')
222
223  def __repr__(self):
224    return repr(self._values)
225
226  def sort(self, *args, **kwargs):
227    # Continue to support the old sort_function keyword argument.
228    # This is expected to be a rare occurrence, so use LBYL to avoid
229    # the overhead of actually catching KeyError.
230    if 'sort_function' in kwargs:
231      kwargs['cmp'] = kwargs.pop('sort_function')
232    self._values.sort(*args, **kwargs)
233
234
235collections_abc.MutableSequence.register(BaseContainer)
236
237
238class RepeatedScalarFieldContainer(BaseContainer):
239  """Simple, type-checked, list-like container for holding repeated scalars."""
240
241  # Disallows assignment to other attributes.
242  __slots__ = ['_type_checker']
243
244  def __init__(self, message_listener, type_checker):
245    """Args:
246
247      message_listener: A MessageListener implementation. The
248      RepeatedScalarFieldContainer will call this object's Modified() method
249      when it is modified.
250      type_checker: A type_checkers.ValueChecker instance to run on elements
251      inserted into this container.
252    """
253    super(RepeatedScalarFieldContainer, self).__init__(message_listener)
254    self._type_checker = type_checker
255
256  def append(self, value):
257    """Appends an item to the list. Similar to list.append()."""
258    self._values.append(self._type_checker.CheckValue(value))
259    if not self._message_listener.dirty:
260      self._message_listener.Modified()
261
262  def insert(self, key, value):
263    """Inserts the item at the specified position. Similar to list.insert()."""
264    self._values.insert(key, self._type_checker.CheckValue(value))
265    if not self._message_listener.dirty:
266      self._message_listener.Modified()
267
268  def extend(self, elem_seq):
269    """Extends by appending the given iterable. Similar to list.extend()."""
270
271    if elem_seq is None:
272      return
273    try:
274      elem_seq_iter = iter(elem_seq)
275    except TypeError:
276      if not elem_seq:
277        # silently ignore falsy inputs :-/.
278        # TODO(user): Deprecate this behavior. b/18413862
279        return
280      raise
281
282    new_values = [self._type_checker.CheckValue(elem) for elem in elem_seq_iter]
283    if new_values:
284      self._values.extend(new_values)
285    self._message_listener.Modified()
286
287  def MergeFrom(self, other):
288    """Appends the contents of another repeated field of the same type to this
289    one. We do not check the types of the individual fields.
290    """
291    self._values.extend(other._values)
292    self._message_listener.Modified()
293
294  def remove(self, elem):
295    """Removes an item from the list. Similar to list.remove()."""
296    self._values.remove(elem)
297    self._message_listener.Modified()
298
299  def pop(self, key=-1):
300    """Removes and returns an item at a given index. Similar to list.pop()."""
301    value = self._values[key]
302    self.__delitem__(key)
303    return value
304
305  def __setitem__(self, key, value):
306    """Sets the item on the specified position."""
307    if isinstance(key, slice):  # PY3
308      if key.step is not None:
309        raise ValueError('Extended slices not supported')
310      self.__setslice__(key.start, key.stop, value)
311    else:
312      self._values[key] = self._type_checker.CheckValue(value)
313      self._message_listener.Modified()
314
315  def __getslice__(self, start, stop):
316    """Retrieves the subset of items from between the specified indices."""
317    return self._values[start:stop]
318
319  def __setslice__(self, start, stop, values):
320    """Sets the subset of items from between the specified indices."""
321    new_values = []
322    for value in values:
323      new_values.append(self._type_checker.CheckValue(value))
324    self._values[start:stop] = new_values
325    self._message_listener.Modified()
326
327  def __delitem__(self, key):
328    """Deletes the item at the specified position."""
329    del self._values[key]
330    self._message_listener.Modified()
331
332  def __delslice__(self, start, stop):
333    """Deletes the subset of items from between the specified indices."""
334    del self._values[start:stop]
335    self._message_listener.Modified()
336
337  def __eq__(self, other):
338    """Compares the current instance with another one."""
339    if self is other:
340      return True
341    # Special case for the same type which should be common and fast.
342    if isinstance(other, self.__class__):
343      return other._values == self._values
344    # We are presumably comparing against some other sequence type.
345    return other == self._values
346
347
348class RepeatedCompositeFieldContainer(BaseContainer):
349
350  """Simple, list-like container for holding repeated composite fields."""
351
352  # Disallows assignment to other attributes.
353  __slots__ = ['_message_descriptor']
354
355  def __init__(self, message_listener, message_descriptor):
356    """
357    Note that we pass in a descriptor instead of the generated directly,
358    since at the time we construct a _RepeatedCompositeFieldContainer we
359    haven't yet necessarily initialized the type that will be contained in the
360    container.
361
362    Args:
363      message_listener: A MessageListener implementation.
364        The RepeatedCompositeFieldContainer will call this object's
365        Modified() method when it is modified.
366      message_descriptor: A Descriptor instance describing the protocol type
367        that should be present in this container.  We'll use the
368        _concrete_class field of this descriptor when the client calls add().
369    """
370    super(RepeatedCompositeFieldContainer, self).__init__(message_listener)
371    self._message_descriptor = message_descriptor
372
373  def add(self, **kwargs):
374    """Adds a new element at the end of the list and returns it. Keyword
375    arguments may be used to initialize the element.
376    """
377    new_element = self._message_descriptor._concrete_class(**kwargs)
378    new_element._SetListener(self._message_listener)
379    self._values.append(new_element)
380    if not self._message_listener.dirty:
381      self._message_listener.Modified()
382    return new_element
383
384  def append(self, value):
385    """Appends one element by copying the message."""
386    new_element = self._message_descriptor._concrete_class()
387    new_element._SetListener(self._message_listener)
388    new_element.CopyFrom(value)
389    self._values.append(new_element)
390    if not self._message_listener.dirty:
391      self._message_listener.Modified()
392
393  def insert(self, key, value):
394    """Inserts the item at the specified position by copying."""
395    new_element = self._message_descriptor._concrete_class()
396    new_element._SetListener(self._message_listener)
397    new_element.CopyFrom(value)
398    self._values.insert(key, new_element)
399    if not self._message_listener.dirty:
400      self._message_listener.Modified()
401
402  def extend(self, elem_seq):
403    """Extends by appending the given sequence of elements of the same type
404
405    as this one, copying each individual message.
406    """
407    message_class = self._message_descriptor._concrete_class
408    listener = self._message_listener
409    values = self._values
410    for message in elem_seq:
411      new_element = message_class()
412      new_element._SetListener(listener)
413      new_element.MergeFrom(message)
414      values.append(new_element)
415    listener.Modified()
416
417  def MergeFrom(self, other):
418    """Appends the contents of another repeated field of the same type to this
419    one, copying each individual message.
420    """
421    self.extend(other._values)
422
423  def remove(self, elem):
424    """Removes an item from the list. Similar to list.remove()."""
425    self._values.remove(elem)
426    self._message_listener.Modified()
427
428  def pop(self, key=-1):
429    """Removes and returns an item at a given index. Similar to list.pop()."""
430    value = self._values[key]
431    self.__delitem__(key)
432    return value
433
434  def __getslice__(self, start, stop):
435    """Retrieves the subset of items from between the specified indices."""
436    return self._values[start:stop]
437
438  def __delitem__(self, key):
439    """Deletes the item at the specified position."""
440    del self._values[key]
441    self._message_listener.Modified()
442
443  def __delslice__(self, start, stop):
444    """Deletes the subset of items from between the specified indices."""
445    del self._values[start:stop]
446    self._message_listener.Modified()
447
448  def __eq__(self, other):
449    """Compares the current instance with another one."""
450    if self is other:
451      return True
452    if not isinstance(other, self.__class__):
453      raise TypeError('Can only compare repeated composite fields against '
454                      'other repeated composite fields.')
455    return self._values == other._values
456
457
458class ScalarMap(MutableMapping):
459
460  """Simple, type-checked, dict-like container for holding repeated scalars."""
461
462  # Disallows assignment to other attributes.
463  __slots__ = ['_key_checker', '_value_checker', '_values', '_message_listener',
464               '_entry_descriptor']
465
466  def __init__(self, message_listener, key_checker, value_checker,
467               entry_descriptor):
468    """
469    Args:
470      message_listener: A MessageListener implementation.
471        The ScalarMap will call this object's Modified() method when it
472        is modified.
473      key_checker: A type_checkers.ValueChecker instance to run on keys
474        inserted into this container.
475      value_checker: A type_checkers.ValueChecker instance to run on values
476        inserted into this container.
477      entry_descriptor: The MessageDescriptor of a map entry: key and value.
478    """
479    self._message_listener = message_listener
480    self._key_checker = key_checker
481    self._value_checker = value_checker
482    self._entry_descriptor = entry_descriptor
483    self._values = {}
484
485  def __getitem__(self, key):
486    try:
487      return self._values[key]
488    except KeyError:
489      key = self._key_checker.CheckValue(key)
490      val = self._value_checker.DefaultValue()
491      self._values[key] = val
492      return val
493
494  def __contains__(self, item):
495    # We check the key's type to match the strong-typing flavor of the API.
496    # Also this makes it easier to match the behavior of the C++ implementation.
497    self._key_checker.CheckValue(item)
498    return item in self._values
499
500  # We need to override this explicitly, because our defaultdict-like behavior
501  # will make the default implementation (from our base class) always insert
502  # the key.
503  def get(self, key, default=None):
504    if key in self:
505      return self[key]
506    else:
507      return default
508
509  def __setitem__(self, key, value):
510    checked_key = self._key_checker.CheckValue(key)
511    checked_value = self._value_checker.CheckValue(value)
512    self._values[checked_key] = checked_value
513    self._message_listener.Modified()
514
515  def __delitem__(self, key):
516    del self._values[key]
517    self._message_listener.Modified()
518
519  def __len__(self):
520    return len(self._values)
521
522  def __iter__(self):
523    return iter(self._values)
524
525  def __repr__(self):
526    return repr(self._values)
527
528  def MergeFrom(self, other):
529    self._values.update(other._values)
530    self._message_listener.Modified()
531
532  def InvalidateIterators(self):
533    # It appears that the only way to reliably invalidate iterators to
534    # self._values is to ensure that its size changes.
535    original = self._values
536    self._values = original.copy()
537    original[None] = None
538
539  # This is defined in the abstract base, but we can do it much more cheaply.
540  def clear(self):
541    self._values.clear()
542    self._message_listener.Modified()
543
544  def GetEntryClass(self):
545    return self._entry_descriptor._concrete_class
546
547
548class MessageMap(MutableMapping):
549
550  """Simple, type-checked, dict-like container for with submessage values."""
551
552  # Disallows assignment to other attributes.
553  __slots__ = ['_key_checker', '_values', '_message_listener',
554               '_message_descriptor', '_entry_descriptor']
555
556  def __init__(self, message_listener, message_descriptor, key_checker,
557               entry_descriptor):
558    """
559    Args:
560      message_listener: A MessageListener implementation.
561        The ScalarMap will call this object's Modified() method when it
562        is modified.
563      key_checker: A type_checkers.ValueChecker instance to run on keys
564        inserted into this container.
565      value_checker: A type_checkers.ValueChecker instance to run on values
566        inserted into this container.
567      entry_descriptor: The MessageDescriptor of a map entry: key and value.
568    """
569    self._message_listener = message_listener
570    self._message_descriptor = message_descriptor
571    self._key_checker = key_checker
572    self._entry_descriptor = entry_descriptor
573    self._values = {}
574
575  def __getitem__(self, key):
576    key = self._key_checker.CheckValue(key)
577    try:
578      return self._values[key]
579    except KeyError:
580      new_element = self._message_descriptor._concrete_class()
581      new_element._SetListener(self._message_listener)
582      self._values[key] = new_element
583      self._message_listener.Modified()
584
585      return new_element
586
587  def get_or_create(self, key):
588    """get_or_create() is an alias for getitem (ie. map[key]).
589
590    Args:
591      key: The key to get or create in the map.
592
593    This is useful in cases where you want to be explicit that the call is
594    mutating the map.  This can avoid lint errors for statements like this
595    that otherwise would appear to be pointless statements:
596
597      msg.my_map[key]
598    """
599    return self[key]
600
601  # We need to override this explicitly, because our defaultdict-like behavior
602  # will make the default implementation (from our base class) always insert
603  # the key.
604  def get(self, key, default=None):
605    if key in self:
606      return self[key]
607    else:
608      return default
609
610  def __contains__(self, item):
611    item = self._key_checker.CheckValue(item)
612    return item in self._values
613
614  def __setitem__(self, key, value):
615    raise ValueError('May not set values directly, call my_map[key].foo = 5')
616
617  def __delitem__(self, key):
618    key = self._key_checker.CheckValue(key)
619    del self._values[key]
620    self._message_listener.Modified()
621
622  def __len__(self):
623    return len(self._values)
624
625  def __iter__(self):
626    return iter(self._values)
627
628  def __repr__(self):
629    return repr(self._values)
630
631  def MergeFrom(self, other):
632    for key in other:
633      # According to documentation: "When parsing from the wire or when merging,
634      # if there are duplicate map keys the last key seen is used".
635      if key in self:
636        del self[key]
637      self[key].CopyFrom(other[key])
638    # self._message_listener.Modified() not required here, because
639    # mutations to submessages already propagate.
640
641  def InvalidateIterators(self):
642    # It appears that the only way to reliably invalidate iterators to
643    # self._values is to ensure that its size changes.
644    original = self._values
645    self._values = original.copy()
646    original[None] = None
647
648  # This is defined in the abstract base, but we can do it much more cheaply.
649  def clear(self):
650    self._values.clear()
651    self._message_listener.Modified()
652
653  def GetEntryClass(self):
654    return self._entry_descriptor._concrete_class
655
656
657class _UnknownField(object):
658
659  """A parsed unknown field."""
660
661  # Disallows assignment to other attributes.
662  __slots__ = ['_field_number', '_wire_type', '_data']
663
664  def __init__(self, field_number, wire_type, data):
665    self._field_number = field_number
666    self._wire_type = wire_type
667    self._data = data
668    return
669
670  def __lt__(self, other):
671    # pylint: disable=protected-access
672    return self._field_number < other._field_number
673
674  def __eq__(self, other):
675    if self is other:
676      return True
677    # pylint: disable=protected-access
678    return (self._field_number == other._field_number and
679            self._wire_type == other._wire_type and
680            self._data == other._data)
681
682
683class UnknownFieldRef(object):
684
685  def __init__(self, parent, index):
686    self._parent = parent
687    self._index = index
688    return
689
690  def _check_valid(self):
691    if not self._parent:
692      raise ValueError('UnknownField does not exist. '
693                       'The parent message might be cleared.')
694    if self._index >= len(self._parent):
695      raise ValueError('UnknownField does not exist. '
696                       'The parent message might be cleared.')
697
698  @property
699  def field_number(self):
700    self._check_valid()
701    # pylint: disable=protected-access
702    return self._parent._internal_get(self._index)._field_number
703
704  @property
705  def wire_type(self):
706    self._check_valid()
707    # pylint: disable=protected-access
708    return self._parent._internal_get(self._index)._wire_type
709
710  @property
711  def data(self):
712    self._check_valid()
713    # pylint: disable=protected-access
714    return self._parent._internal_get(self._index)._data
715
716
717class UnknownFieldSet(object):
718
719  """UnknownField container"""
720
721  # Disallows assignment to other attributes.
722  __slots__ = ['_values']
723
724  def __init__(self):
725    self._values = []
726
727  def __getitem__(self, index):
728    if self._values is None:
729      raise ValueError('UnknownFields does not exist. '
730                       'The parent message might be cleared.')
731    size = len(self._values)
732    if index < 0:
733      index += size
734    if index < 0 or index >= size:
735      raise IndexError('index %d out of range'.index)
736
737    return UnknownFieldRef(self, index)
738
739  def _internal_get(self, index):
740    return self._values[index]
741
742  def __len__(self):
743    if self._values is None:
744      raise ValueError('UnknownFields does not exist. '
745                       'The parent message might be cleared.')
746    return len(self._values)
747
748  def _add(self, field_number, wire_type, data):
749    unknown_field = _UnknownField(field_number, wire_type, data)
750    self._values.append(unknown_field)
751    return unknown_field
752
753  def __iter__(self):
754    for i in range(len(self)):
755      yield UnknownFieldRef(self, i)
756
757  def _extend(self, other):
758    if other is None:
759      return
760    # pylint: disable=protected-access
761    self._values.extend(other._values)
762
763  def __eq__(self, other):
764    if self is other:
765      return True
766    # Sort unknown fields because their order shouldn't
767    # affect equality test.
768    values = list(self._values)
769    if other is None:
770      return not values
771    values.sort()
772    # pylint: disable=protected-access
773    other_values = sorted(other._values)
774    return values == other_values
775
776  def _clear(self):
777    for value in self._values:
778      # pylint: disable=protected-access
779      if isinstance(value._data, UnknownFieldSet):
780        value._data._clear()  # pylint: disable=protected-access
781    self._values = None
782