You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
bazarr/libs/bidict/_bidict.py

198 lines
7.1 KiB

# Copyright 2009-2022 Joshua Bronson. All rights reserved.
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
# * Code review nav *
# (see comments in __init__.py)
#==============================================================================
# ← Prev: _frozenbidict.py Current: _bidict.py Next: _orderedbase.py →
#==============================================================================
"""Provide :class:`MutableBidict`."""
import typing as t
from ._abc import MutableBidirectionalMapping
from ._base import BidictBase, get_arg
from ._dup import OnDup, ON_DUP_RAISE, ON_DUP_DROP_OLD
from ._typing import KT, VT, DT, ODT, MISSING, IterItems, MapOrIterItems
class MutableBidict(BidictBase[KT, VT], MutableBidirectionalMapping[KT, VT]):
"""Base class for mutable bidirectional mappings."""
if t.TYPE_CHECKING:
@property
def inverse(self) -> 'MutableBidict[VT, KT]': ...
def _pop(self, key: KT) -> VT:
val = self._fwdm.pop(key)
del self._invm[val]
return val
def __delitem__(self, key: KT) -> None:
"""*x.__delitem__(y)  del x[y]*"""
self._pop(key)
def __setitem__(self, key: KT, val: VT) -> None:
"""Set the value for *key* to *val*.
If *key* is already associated with *val*, this is a no-op.
If *key* is already associated with a different value,
the old value will be replaced with *val*,
as with dict's :meth:`__setitem__`.
If *val* is already associated with a different key,
an exception is raised
to protect against accidental removal of the key
that's currently associated with *val*.
Use :meth:`put` instead if you want to specify different behavior in
the case that the provided key or value duplicates an existing one.
Or use :meth:`forceput` to unconditionally associate *key* with *val*,
replacing any existing items as necessary to preserve uniqueness.
:raises bidict.ValueDuplicationError: if *val* duplicates that of an
existing item.
:raises bidict.KeyAndValueDuplicationError: if *key* duplicates the key of an
existing item and *val* duplicates the value of a different
existing item.
"""
self.put(key, val, on_dup=self.on_dup)
def put(self, key: KT, val: VT, on_dup: OnDup = ON_DUP_RAISE) -> None:
"""Associate *key* with *val*, honoring the :class:`OnDup` given in *on_dup*.
For example, if *on_dup* is :attr:`~bidict.ON_DUP_RAISE`,
then *key* will be associated with *val* if and only if
*key* is not already associated with an existing value and
*val* is not already associated with an existing key,
otherwise an exception will be raised.
If *key* is already associated with *val*, this is a no-op.
:raises bidict.KeyDuplicationError: if attempting to insert an item
whose key only duplicates an existing item's, and *on_dup.key* is
:attr:`~bidict.RAISE`.
:raises bidict.ValueDuplicationError: if attempting to insert an item
whose value only duplicates an existing item's, and *on_dup.val* is
:attr:`~bidict.RAISE`.
:raises bidict.KeyAndValueDuplicationError: if attempting to insert an
item whose key duplicates one existing item's, and whose value
duplicates another existing item's, and *on_dup.kv* is
:attr:`~bidict.RAISE`.
"""
self._update([(key, val)], on_dup=on_dup)
def forceput(self, key: KT, val: VT) -> None:
"""Associate *key* with *val* unconditionally.
Replace any existing mappings containing key *key* or value *val*
as necessary to preserve uniqueness.
"""
self.put(key, val, on_dup=ON_DUP_DROP_OLD)
def clear(self) -> None:
"""Remove all items."""
self._fwdm.clear()
self._invm.clear()
@t.overload
def pop(self, __key: KT) -> VT: ...
@t.overload
def pop(self, __key: KT, __default: DT = ...) -> t.Union[VT, DT]: ...
def pop(self, key: KT, default: ODT[DT] = MISSING) -> t.Union[VT, DT]:
"""*x.pop(k[, d]) → v*
Remove specified key and return the corresponding value.
:raises KeyError: if *key* is not found and no *default* is provided.
"""
try:
return self._pop(key)
except KeyError:
if default is MISSING:
raise
return default
def popitem(self) -> t.Tuple[KT, VT]:
"""*x.popitem() → (k, v)*
Remove and return some item as a (key, value) pair.
:raises KeyError: if *x* is empty.
"""
key, val = self._fwdm.popitem()
del self._invm[val]
return key, val
@t.overload # type: ignore [override] # https://github.com/jab/bidict/pull/242#discussion_r825464731
def update(self, __m: t.Mapping[KT, VT], **kw: VT) -> None: ...
@t.overload
def update(self, __i: IterItems[KT, VT], **kw: VT) -> None: ...
@t.overload
def update(self, **kw: VT) -> None: ...
def update(self, *args: MapOrIterItems[KT, VT], **kw: VT) -> None:
"""Like calling :meth:`putall` with *self.on_dup* passed for *on_dup*."""
if args or kw:
self._update(get_arg(*args), kw)
@t.overload
def forceupdate(self, __m: t.Mapping[KT, VT], **kw: VT) -> None: ...
@t.overload
def forceupdate(self, __i: IterItems[KT, VT], **kw: VT) -> None: ...
@t.overload
def forceupdate(self, **kw: VT) -> None: ...
def forceupdate(self, *args: MapOrIterItems[KT, VT], **kw: VT) -> None:
"""Like a bulk :meth:`forceput`."""
if args or kw:
self._update(get_arg(*args), kw, on_dup=ON_DUP_DROP_OLD)
def __ior__(self, other: t.Mapping[KT, VT]) -> 'MutableBidict[KT, VT]':
"""Return self|=other."""
self.update(other)
return self
@t.overload
def putall(self, items: t.Mapping[KT, VT], on_dup: OnDup) -> None: ...
@t.overload
def putall(self, items: IterItems[KT, VT], on_dup: OnDup = ...) -> None: ...
def putall(self, items: MapOrIterItems[KT, VT], on_dup: OnDup = ON_DUP_RAISE) -> None:
"""Like a bulk :meth:`put`.
If one of the given items causes an exception to be raised,
none of the items is inserted.
"""
if items:
self._update(items, on_dup=on_dup)
class bidict(MutableBidict[KT, VT]):
"""The main bidirectional mapping type.
See :ref:`intro:Introduction` and :ref:`basic-usage:Basic Usage`
to get started (also available at https://bidict.rtfd.io).
"""
if t.TYPE_CHECKING:
@property
def inverse(self) -> 'bidict[VT, KT]': ...
# * Code review nav *
#==============================================================================
# ← Prev: _frozenbidict.py Current: _bidict.py Next: _orderedbase.py →
#==============================================================================