31 """Contains container classes to represent different protocol buffer types.
33 This file defines container classes which represent categories of protocol
34 buffer field types which need extra maintenance. Currently these categories
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.
43 __author__ =
'petar@google.com (Petar Petrov)'
45 import collections.abc
48 class BaseContainer(object):
50 """Base container class."""
53 __slots__ = [
'_message_listener',
'_values']
58 message_listener: A MessageListener implementation.
59 The RepeatedScalarFieldContainer will call this object's
60 Modified() method when it is modified.
66 """Retrieves item by the specified key."""
70 """Returns the number of elements in the container."""
74 """Checks if another instance isn't equal to this one."""
76 return not self == other
79 raise TypeError(
'unhashable object')
84 def sort(self, *args, **kwargs):
88 if 'sort_function' in kwargs:
89 kwargs[
'cmp'] = kwargs.pop(
'sort_function')
96 collections.abc.MutableSequence.register(BaseContainer)
100 """Simple, type-checked, list-like container for holding repeated scalars."""
103 __slots__ = [
'_type_checker']
105 def __init__(self, message_listener, type_checker):
108 message_listener: A MessageListener implementation. The
109 RepeatedScalarFieldContainer will call this object's Modified() method
111 type_checker: A type_checkers.ValueChecker instance to run on elements
112 inserted into this container.
114 super(RepeatedScalarFieldContainer, self).
__init__(message_listener)
118 """Appends an item to the list. Similar to list.append()."""
124 """Inserts the item at the specified position. Similar to list.insert()."""
130 """Extends by appending the given iterable. Similar to list.extend()."""
135 elem_seq_iter =
iter(elem_seq)
143 new_values = [self.
_type_checker.CheckValue(elem)
for elem
in elem_seq_iter]
149 """Appends the contents of another repeated field of the same type to this
150 one. We do not check the types of the individual fields.
156 """Removes an item from the list. Similar to list.remove()."""
161 """Removes and returns an item at a given index. Similar to list.pop()."""
167 """Sets the item on the specified position."""
168 if isinstance(key, slice):
169 if key.step
is not None:
170 raise ValueError(
'Extended slices not supported')
177 """Retrieves the subset of items from between the specified indices."""
178 return self.
_values[start:stop]
181 """Sets the subset of items from between the specified indices."""
185 self.
_values[start:stop] = new_values
189 """Deletes the item at the specified position."""
194 """Deletes the subset of items from between the specified indices."""
199 """Compares the current instance with another one."""
203 if isinstance(other, self.__class__):
204 return other._values == self.
_values
211 """Simple, list-like container for holding repeated composite fields."""
214 __slots__ = [
'_message_descriptor']
216 def __init__(self, message_listener, message_descriptor):
218 Note that we pass in a descriptor instead of the generated directly,
219 since at the time we construct a _RepeatedCompositeFieldContainer we
220 haven't yet necessarily initialized the type that will be contained in the
224 message_listener: A MessageListener implementation.
225 The RepeatedCompositeFieldContainer will call this object's
226 Modified() method when it is modified.
227 message_descriptor: A Descriptor instance describing the protocol type
228 that should be present in this container. We'll use the
229 _concrete_class field of this descriptor when the client calls add().
231 super(RepeatedCompositeFieldContainer, self).
__init__(message_listener)
235 """Adds a new element at the end of the list and returns it. Keyword
236 arguments may be used to initialize the element.
246 """Appends one element by copying the message."""
249 new_element.CopyFrom(value)
255 """Inserts the item at the specified position by copying."""
258 new_element.CopyFrom(value)
264 """Extends by appending the given sequence of elements of the same type
266 as this one, copying each individual message.
271 for message
in elem_seq:
272 new_element = message_class()
273 new_element._SetListener(listener)
274 new_element.MergeFrom(message)
275 values.append(new_element)
279 """Appends the contents of another repeated field of the same type to this
280 one, copying each individual message.
282 self.
extend(other._values)
285 """Removes an item from the list. Similar to list.remove()."""
290 """Removes and returns an item at a given index. Similar to list.pop()."""
296 """Retrieves the subset of items from between the specified indices."""
297 return self.
_values[start:stop]
300 """Deletes the item at the specified position."""
305 """Deletes the subset of items from between the specified indices."""
310 """Compares the current instance with another one."""
313 if not isinstance(other, self.__class__):
314 raise TypeError(
'Can only compare repeated composite fields against '
315 'other repeated composite fields.')
316 return self.
_values == other._values
319 class ScalarMap(collections.abc.MutableMapping):
321 """Simple, type-checked, dict-like container for holding repeated scalars."""
324 __slots__ = [
'_key_checker',
'_value_checker',
'_values',
'_message_listener',
327 def __init__(self, message_listener, key_checker, value_checker,
331 message_listener: A MessageListener implementation.
332 The ScalarMap will call this object's Modified() method when it
334 key_checker: A type_checkers.ValueChecker instance to run on keys
335 inserted into this container.
336 value_checker: A type_checkers.ValueChecker instance to run on values
337 inserted into this container.
338 entry_descriptor: The MessageDescriptor of a map entry: key and value.
364 def get(self, key, default=None):
373 self.
_values[checked_key] = checked_value
398 original[
None] =
None
409 class MessageMap(collections.abc.MutableMapping):
411 """Simple, type-checked, dict-like container for with submessage values."""
414 __slots__ = [
'_key_checker',
'_values',
'_message_listener',
415 '_message_descriptor',
'_entry_descriptor']
417 def __init__(self, message_listener, message_descriptor, key_checker,
421 message_listener: A MessageListener implementation.
422 The ScalarMap will call this object's Modified() method when it
424 key_checker: A type_checkers.ValueChecker instance to run on keys
425 inserted into this container.
426 value_checker: A type_checkers.ValueChecker instance to run on values
427 inserted into this container.
428 entry_descriptor: The MessageDescriptor of a map entry: key and value.
443 self.
_values[key] = new_element
449 """get_or_create() is an alias for getitem (ie. map[key]).
452 key: The key to get or create in the map.
454 This is useful in cases where you want to be explicit that the call is
455 mutating the map. This can avoid lint errors for statements like this
456 that otherwise would appear to be pointless statements:
465 def get(self, key, default=None):
476 raise ValueError(
'May not set values directly, call my_map[key].foo = 5')
494 for key
in other._values:
508 original[
None] =
None
521 """A parsed unknown field."""
524 __slots__ = [
'_field_number',
'_wire_type',
'_data']
542 self.
_data == other._data)
554 raise ValueError(
'UnknownField does not exist. '
555 'The parent message might be cleared.')
557 raise ValueError(
'UnknownField does not exist. '
558 'The parent message might be cleared.')
581 """UnknownField container"""
584 __slots__ = [
'_values']
591 raise ValueError(
'UnknownFields does not exist. '
592 'The parent message might be cleared.')
596 if index < 0
or index >= size:
597 raise IndexError(
'index %d out of range'.index)
606 raise ValueError(
'UnknownFields does not exist. '
607 'The parent message might be cleared.')
610 def _add(self, field_number, wire_type, data):
612 self.
_values.append(unknown_field)
623 self.
_values.extend(other._values)
635 other_values = sorted(other._values)
636 return values == other_values
641 if isinstance(value._data, UnknownFieldSet):