_mut.py 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. # -*- coding: utf-8 -*-
  2. # Copyright 2018 Joshua Bronson. All Rights Reserved.
  3. #
  4. # This Source Code Form is subject to the terms of the Mozilla Public
  5. # License, v. 2.0. If a copy of the MPL was not distributed with this
  6. # file, You can obtain one at http://mozilla.org/MPL/2.0/.
  7. #==============================================================================
  8. # * Welcome to the bidict source code *
  9. #==============================================================================
  10. # Doing a code review? You'll find a "Code review nav" comment like the one
  11. # below at the top and bottom of the most important source files. This provides
  12. # a suggested initial path through the source when reviewing.
  13. #
  14. # Note: If you aren't reading this on https://github.com/jab/bidict, you may be
  15. # viewing an outdated version of the code. Please head to GitHub to review the
  16. # latest version, which contains important improvements over older versions.
  17. #
  18. # Thank you for reading and for any feedback you provide.
  19. # * Code review nav *
  20. #==============================================================================
  21. # ← Prev: _frozenbidict.py Current: _mut.py Next: _bidict.py →
  22. #==============================================================================
  23. """Provides :class:`_MutableBidict`."""
  24. from ._base import BidictBase
  25. from ._dup import OVERWRITE, RAISE, _OnDup
  26. from ._miss import _MISS
  27. from .compat import MutableMapping
  28. # Extend MutableMapping explicitly because it doesn't implement __subclasshook__, as well as to
  29. # inherit method implementations it provides that bidict can reuse (namely `setdefault`).
  30. class _MutableBidict(BidictBase, MutableMapping):
  31. """Base class for mutable bidirectional mappings."""
  32. __slots__ = ()
  33. __hash__ = None # since this class is mutable; explicit > implicit.
  34. _ON_DUP_OVERWRITE = _OnDup(key=OVERWRITE, val=OVERWRITE, kv=OVERWRITE)
  35. def __delitem__(self, key):
  36. u"""*x.__delitem__(y) ⟺ del x[y]*"""
  37. self._pop(key)
  38. def __setitem__(self, key, val):
  39. """
  40. Set the value for *key* to *val*.
  41. If *key* is already associated with *val*, this is a no-op.
  42. If *key* is already associated with a different value,
  43. the old value will be replaced with *val*,
  44. as with dict's :meth:`__setitem__`.
  45. If *val* is already associated with a different key,
  46. an exception is raised
  47. to protect against accidental removal of the key
  48. that's currently associated with *val*.
  49. Use :meth:`put` instead if you want to specify different policy in
  50. the case that the provided key or value duplicates an existing one.
  51. Or use :meth:`forceput` to unconditionally associate *key* with *val*,
  52. replacing any existing items as necessary to preserve uniqueness.
  53. :raises bidict.ValueDuplicationError: if *val* duplicates that of an
  54. existing item.
  55. :raises bidict.KeyAndValueDuplicationError: if *key* duplicates the key of an
  56. existing item and *val* duplicates the value of a different
  57. existing item.
  58. """
  59. on_dup = self._get_on_dup()
  60. self._put(key, val, on_dup)
  61. def put(self, key, val, on_dup_key=RAISE, on_dup_val=RAISE, on_dup_kv=None):
  62. """
  63. Associate *key* with *val* with the specified duplication policies.
  64. If *on_dup_kv* is ``None``, the *on_dup_val* policy will be used for it.
  65. For example, if all given duplication policies are :attr:`~bidict.RAISE`,
  66. then *key* will be associated with *val* if and only if
  67. *key* is not already associated with an existing value and
  68. *val* is not already associated with an existing key,
  69. otherwise an exception will be raised.
  70. If *key* is already associated with *val*, this is a no-op.
  71. :raises bidict.KeyDuplicationError: if attempting to insert an item
  72. whose key only duplicates an existing item's, and *on_dup_key* is
  73. :attr:`~bidict.RAISE`.
  74. :raises bidict.ValueDuplicationError: if attempting to insert an item
  75. whose value only duplicates an existing item's, and *on_dup_val* is
  76. :attr:`~bidict.RAISE`.
  77. :raises bidict.KeyAndValueDuplicationError: if attempting to insert an
  78. item whose key duplicates one existing item's, and whose value
  79. duplicates another existing item's, and *on_dup_kv* is
  80. :attr:`~bidict.RAISE`.
  81. """
  82. on_dup = self._get_on_dup((on_dup_key, on_dup_val, on_dup_kv))
  83. self._put(key, val, on_dup)
  84. def forceput(self, key, val):
  85. """
  86. Associate *key* with *val* unconditionally.
  87. Replace any existing mappings containing key *key* or value *val*
  88. as necessary to preserve uniqueness.
  89. """
  90. self._put(key, val, self._ON_DUP_OVERWRITE)
  91. def clear(self):
  92. """Remove all items."""
  93. self._fwdm.clear()
  94. self._invm.clear()
  95. def pop(self, key, default=_MISS):
  96. u"""*x.pop(k[, d]) → v*
  97. Remove specified key and return the corresponding value.
  98. :raises KeyError: if *key* is not found and no *default* is provided.
  99. """
  100. try:
  101. return self._pop(key)
  102. except KeyError:
  103. if default is _MISS:
  104. raise
  105. return default
  106. def popitem(self):
  107. u"""*x.popitem() → (k, v)*
  108. Remove and return some item as a (key, value) pair.
  109. :raises KeyError: if *x* is empty.
  110. """
  111. if not self:
  112. raise KeyError('mapping is empty')
  113. key, val = self._fwdm.popitem()
  114. del self._invm[val]
  115. return key, val
  116. def update(self, *args, **kw):
  117. """Like :meth:`putall` with default duplication policies."""
  118. if args or kw:
  119. self._update(False, None, *args, **kw)
  120. def forceupdate(self, *args, **kw):
  121. """Like a bulk :meth:`forceput`."""
  122. self._update(False, self._ON_DUP_OVERWRITE, *args, **kw)
  123. def putall(self, items, on_dup_key=RAISE, on_dup_val=RAISE, on_dup_kv=None):
  124. """
  125. Like a bulk :meth:`put`.
  126. If one of the given items causes an exception to be raised,
  127. none of the items is inserted.
  128. """
  129. if items:
  130. on_dup = self._get_on_dup((on_dup_key, on_dup_val, on_dup_kv))
  131. self._update(False, on_dup, items)
  132. # * Code review nav *
  133. #==============================================================================
  134. # ← Prev: _frozenbidict.py Current: _mut.py Next: _bidict.py →
  135. #==============================================================================