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(ptucker): 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