first commit
This commit is contained in:
94
hypenv/lib/python3.11/site-packages/bidict/__init__.py
Normal file
94
hypenv/lib/python3.11/site-packages/bidict/__init__.py
Normal file
@@ -0,0 +1,94 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2009-2020 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/.
|
||||
|
||||
|
||||
#==============================================================================
|
||||
# * Welcome to the bidict source code *
|
||||
#==============================================================================
|
||||
|
||||
# Doing a code review? You'll find a "Code review nav" comment like the one
|
||||
# below at the top and bottom of the most important source files. This provides
|
||||
# a suggested initial path through the source when reviewing.
|
||||
#
|
||||
# Note: If you aren't reading this on https://github.com/jab/bidict, you may be
|
||||
# viewing an outdated version of the code. Please head to GitHub to review the
|
||||
# latest version, which contains important improvements over older versions.
|
||||
#
|
||||
# Thank you for reading and for any feedback you provide.
|
||||
|
||||
# * Code review nav *
|
||||
#==============================================================================
|
||||
# Current: __init__.py Next: _abc.py →
|
||||
#==============================================================================
|
||||
|
||||
|
||||
"""The bidirectional mapping library for Python.
|
||||
|
||||
bidict by example:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> from bidict import bidict
|
||||
>>> element_by_symbol = bidict({'H': 'hydrogen'})
|
||||
>>> element_by_symbol['H']
|
||||
'hydrogen'
|
||||
>>> element_by_symbol.inverse['hydrogen']
|
||||
'H'
|
||||
|
||||
|
||||
Please see https://github.com/jab/bidict for the most up-to-date code and
|
||||
https://bidict.readthedocs.io for the most up-to-date documentation
|
||||
if you are reading this elsewhere.
|
||||
|
||||
|
||||
.. :copyright: (c) 2009-2020 Joshua Bronson.
|
||||
.. :license: MPLv2. See LICENSE for details.
|
||||
"""
|
||||
|
||||
# Use private aliases to not re-export these publicly (for Sphinx automodule with imported-members).
|
||||
from sys import version_info as _version_info
|
||||
|
||||
|
||||
if _version_info < (3, 6): # pragma: no cover
|
||||
raise ImportError('Python 3.6+ is required.')
|
||||
|
||||
# The rest of this file only collects functionality implemented in the rest of the
|
||||
# source for the purposes of exporting it under the `bidict` module namespace.
|
||||
# flake8: noqa: F401 (imported but unused)
|
||||
from ._abc import BidirectionalMapping, MutableBidirectionalMapping
|
||||
from ._base import BidictBase
|
||||
from ._mut import MutableBidict
|
||||
from ._bidict import bidict
|
||||
from ._frozenbidict import frozenbidict
|
||||
from ._frozenordered import FrozenOrderedBidict
|
||||
from ._named import namedbidict
|
||||
from ._orderedbase import OrderedBidictBase
|
||||
from ._orderedbidict import OrderedBidict
|
||||
from ._dup import ON_DUP_DEFAULT, ON_DUP_RAISE, ON_DUP_DROP_OLD, RAISE, DROP_OLD, DROP_NEW, OnDup, OnDupAction
|
||||
from ._exc import BidictException, DuplicationError, KeyDuplicationError, ValueDuplicationError, KeyAndValueDuplicationError
|
||||
from ._iter import inverted
|
||||
from .metadata import (
|
||||
__author__, __maintainer__, __copyright__, __email__, __credits__, __url__,
|
||||
__license__, __status__, __description__, __keywords__, __version__, __version_info__,
|
||||
)
|
||||
|
||||
# Set __module__ of re-exported classes to the 'bidict' top-level module name
|
||||
# so that private/internal submodules are not exposed to users e.g. in repr strings.
|
||||
_locals = tuple(locals().items())
|
||||
for _name, _obj in _locals: # pragma: no cover
|
||||
if not getattr(_obj, '__module__', '').startswith('bidict.'):
|
||||
continue
|
||||
try:
|
||||
_obj.__module__ = 'bidict'
|
||||
except AttributeError as exc: # raised when __module__ is read-only (as in OnDup)
|
||||
pass
|
||||
|
||||
|
||||
# * Code review nav *
|
||||
#==============================================================================
|
||||
# Current: __init__.py Next: _abc.py →
|
||||
#==============================================================================
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
105
hypenv/lib/python3.11/site-packages/bidict/_abc.py
Normal file
105
hypenv/lib/python3.11/site-packages/bidict/_abc.py
Normal file
@@ -0,0 +1,105 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2009-2020 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/.
|
||||
|
||||
|
||||
#==============================================================================
|
||||
# * Welcome to the bidict source code *
|
||||
#==============================================================================
|
||||
|
||||
# Doing a code review? You'll find a "Code review nav" comment like the one
|
||||
# below at the top and bottom of the most important source files. This provides
|
||||
# a suggested initial path through the source when reviewing.
|
||||
#
|
||||
# Note: If you aren't reading this on https://github.com/jab/bidict, you may be
|
||||
# viewing an outdated version of the code. Please head to GitHub to review the
|
||||
# latest version, which contains important improvements over older versions.
|
||||
#
|
||||
# Thank you for reading and for any feedback you provide.
|
||||
|
||||
# * Code review nav *
|
||||
#==============================================================================
|
||||
# ← Prev: __init__.py Current: _abc.py Next: _base.py →
|
||||
#==============================================================================
|
||||
|
||||
|
||||
"""Provide the :class:`BidirectionalMapping` abstract base class."""
|
||||
|
||||
import typing as _t
|
||||
from abc import abstractmethod
|
||||
|
||||
from ._typing import KT, VT
|
||||
|
||||
|
||||
class BidirectionalMapping(_t.Mapping[KT, VT]):
|
||||
"""Abstract base class (ABC) for bidirectional mapping types.
|
||||
|
||||
Extends :class:`collections.abc.Mapping` primarily by adding the
|
||||
(abstract) :attr:`inverse` property,
|
||||
which implementors of :class:`BidirectionalMapping`
|
||||
should override to return a reference to the inverse
|
||||
:class:`BidirectionalMapping` instance.
|
||||
"""
|
||||
|
||||
__slots__ = ()
|
||||
|
||||
@property
|
||||
@abstractmethod
|
||||
def inverse(self) -> 'BidirectionalMapping[VT, KT]':
|
||||
"""The inverse of this bidirectional mapping instance.
|
||||
|
||||
*See also* :attr:`bidict.BidictBase.inverse`, :attr:`bidict.BidictBase.inv`
|
||||
|
||||
:raises NotImplementedError: Meant to be overridden in subclasses.
|
||||
"""
|
||||
# The @abstractproperty decorator prevents BidirectionalMapping subclasses from being
|
||||
# instantiated unless they override this method. So users shouldn't be able to get to the
|
||||
# point where they can unintentionally call this implementation of .inverse on something
|
||||
# anyway. Could leave the method body empty, but raise NotImplementedError so it's extra
|
||||
# clear there's no reason to call this implementation (e.g. via super() after overriding).
|
||||
raise NotImplementedError
|
||||
|
||||
def __inverted__(self) -> _t.Iterator[_t.Tuple[VT, KT]]:
|
||||
"""Get an iterator over the items in :attr:`inverse`.
|
||||
|
||||
This is functionally equivalent to iterating over the items in the
|
||||
forward mapping and inverting each one on the fly, but this provides a
|
||||
more efficient implementation: Assuming the already-inverted items
|
||||
are stored in :attr:`inverse`, just return an iterator over them directly.
|
||||
|
||||
Providing this default implementation enables external functions,
|
||||
particularly :func:`~bidict.inverted`, to use this optimized
|
||||
implementation when available, instead of having to invert on the fly.
|
||||
|
||||
*See also* :func:`bidict.inverted`
|
||||
"""
|
||||
return iter(self.inverse.items())
|
||||
|
||||
def values(self) -> _t.AbstractSet[VT]: # type: ignore # https://github.com/python/typeshed/issues/4435
|
||||
"""A set-like object providing a view on the contained values.
|
||||
|
||||
Override the implementation inherited from
|
||||
:class:`~collections.abc.Mapping`.
|
||||
Because the values of a :class:`~bidict.BidirectionalMapping`
|
||||
are the keys of its inverse,
|
||||
this returns a :class:`~collections.abc.KeysView`
|
||||
rather than a :class:`~collections.abc.ValuesView`,
|
||||
which has the advantages of constant-time containment checks
|
||||
and supporting set operations.
|
||||
"""
|
||||
return self.inverse.keys()
|
||||
|
||||
|
||||
class MutableBidirectionalMapping(BidirectionalMapping[KT, VT], _t.MutableMapping[KT, VT]):
|
||||
"""Abstract base class (ABC) for mutable bidirectional mapping types."""
|
||||
|
||||
__slots__ = ()
|
||||
|
||||
|
||||
# * Code review nav *
|
||||
#==============================================================================
|
||||
# ← Prev: __init__.py Current: _abc.py Next: _base.py →
|
||||
#==============================================================================
|
||||
383
hypenv/lib/python3.11/site-packages/bidict/_base.py
Normal file
383
hypenv/lib/python3.11/site-packages/bidict/_base.py
Normal file
@@ -0,0 +1,383 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2009-2020 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/.
|
||||
|
||||
|
||||
#==============================================================================
|
||||
# * Welcome to the bidict source code *
|
||||
#==============================================================================
|
||||
|
||||
# Doing a code review? You'll find a "Code review nav" comment like the one
|
||||
# below at the top and bottom of the most important source files. This provides
|
||||
# a suggested initial path through the source when reviewing.
|
||||
#
|
||||
# Note: If you aren't reading this on https://github.com/jab/bidict, you may be
|
||||
# viewing an outdated version of the code. Please head to GitHub to review the
|
||||
# latest version, which contains important improvements over older versions.
|
||||
#
|
||||
# Thank you for reading and for any feedback you provide.
|
||||
|
||||
# * Code review nav *
|
||||
#==============================================================================
|
||||
# ← Prev: _abc.py Current: _base.py Next: _frozenbidict.py →
|
||||
#==============================================================================
|
||||
|
||||
|
||||
"""Provide :class:`BidictBase`."""
|
||||
|
||||
import typing as _t
|
||||
from collections import namedtuple
|
||||
from copy import copy
|
||||
from weakref import ref
|
||||
|
||||
from ._abc import BidirectionalMapping
|
||||
from ._dup import ON_DUP_DEFAULT, RAISE, DROP_OLD, DROP_NEW, OnDup
|
||||
from ._exc import DuplicationError, KeyDuplicationError, ValueDuplicationError, KeyAndValueDuplicationError
|
||||
from ._iter import _iteritems_args_kw
|
||||
from ._typing import _NONE, KT, VT, OKT, OVT, IterItems, MapOrIterItems
|
||||
|
||||
|
||||
_WriteResult = namedtuple('_WriteResult', 'key val oldkey oldval')
|
||||
_DedupResult = namedtuple('_DedupResult', 'isdupkey isdupval invbyval fwdbykey')
|
||||
_NODUP = _DedupResult(False, False, _NONE, _NONE)
|
||||
|
||||
BT = _t.TypeVar('BT', bound='BidictBase') # typevar for BidictBase.copy
|
||||
|
||||
|
||||
class BidictBase(BidirectionalMapping[KT, VT]):
|
||||
"""Base class implementing :class:`BidirectionalMapping`."""
|
||||
|
||||
__slots__ = ['_fwdm', '_invm', '_inv', '_invweak', '_hash', '__weakref__']
|
||||
|
||||
#: The default :class:`~bidict.OnDup`
|
||||
#: that governs behavior when a provided item
|
||||
#: duplicates the key or value of other item(s).
|
||||
#:
|
||||
#: *See also* :ref:`basic-usage:Values Must Be Unique`, :doc:`extending`
|
||||
on_dup = ON_DUP_DEFAULT
|
||||
|
||||
_fwdm_cls = dict #: class of the backing forward mapping
|
||||
_invm_cls = dict #: class of the backing inverse mapping
|
||||
|
||||
#: The object used by :meth:`__repr__` for printing the contained items.
|
||||
_repr_delegate = dict
|
||||
|
||||
def __init_subclass__(cls, **kw):
|
||||
super().__init_subclass__(**kw)
|
||||
# Compute and set _inv_cls, the inverse of this bidict class.
|
||||
if '_inv_cls' in cls.__dict__:
|
||||
return
|
||||
if cls._fwdm_cls is cls._invm_cls:
|
||||
cls._inv_cls = cls
|
||||
return
|
||||
inv_cls = type(cls.__name__ + 'Inv', cls.__bases__, {
|
||||
**cls.__dict__,
|
||||
'_inv_cls': cls,
|
||||
'_fwdm_cls': cls._invm_cls,
|
||||
'_invm_cls': cls._fwdm_cls,
|
||||
})
|
||||
cls._inv_cls = inv_cls
|
||||
|
||||
@_t.overload
|
||||
def __init__(self, __arg: _t.Mapping[KT, VT], **kw: VT) -> None: ...
|
||||
@_t.overload
|
||||
def __init__(self, __arg: IterItems[KT, VT], **kw: VT) -> None: ...
|
||||
@_t.overload
|
||||
def __init__(self, **kw: VT) -> None: ...
|
||||
def __init__(self, *args: MapOrIterItems[KT, VT], **kw: VT) -> None:
|
||||
"""Make a new bidirectional dictionary.
|
||||
The signature behaves like that of :class:`dict`.
|
||||
Items passed in are added in the order they are passed,
|
||||
respecting the :attr:`on_dup` class attribute in the process.
|
||||
"""
|
||||
#: The backing :class:`~collections.abc.Mapping`
|
||||
#: storing the forward mapping data (*key* → *value*).
|
||||
self._fwdm: _t.Dict[KT, VT] = self._fwdm_cls()
|
||||
#: The backing :class:`~collections.abc.Mapping`
|
||||
#: storing the inverse mapping data (*value* → *key*).
|
||||
self._invm: _t.Dict[VT, KT] = self._invm_cls()
|
||||
self._init_inv()
|
||||
if args or kw:
|
||||
self._update(True, self.on_dup, *args, **kw)
|
||||
|
||||
def _init_inv(self) -> None:
|
||||
# Create the inverse bidict instance via __new__, bypassing its __init__ so that its
|
||||
# _fwdm and _invm can be assigned to this bidict's _invm and _fwdm. Store it in self._inv,
|
||||
# which holds a strong reference to a bidict's inverse, if one is available.
|
||||
self._inv = inv = self._inv_cls.__new__(self._inv_cls) # type: ignore
|
||||
inv._fwdm = self._invm
|
||||
inv._invm = self._fwdm
|
||||
# Only give the inverse a weak reference to this bidict to avoid creating a reference cycle,
|
||||
# stored in the _invweak attribute. See also the docs in
|
||||
# :ref:`addendum:Bidict Avoids Reference Cycles`
|
||||
inv._inv = None
|
||||
inv._invweak = ref(self)
|
||||
# Since this bidict has a strong reference to its inverse already, set its _invweak to None.
|
||||
self._invweak = None
|
||||
|
||||
@property
|
||||
def _isinv(self) -> bool:
|
||||
return self._inv is None
|
||||
|
||||
@property
|
||||
def inverse(self) -> 'BidictBase[VT, KT]':
|
||||
"""The inverse of this bidict."""
|
||||
# Resolve and return a strong reference to the inverse bidict.
|
||||
# One may be stored in self._inv already.
|
||||
if self._inv is not None:
|
||||
return self._inv # type: ignore
|
||||
# Otherwise a weakref is stored in self._invweak. Try to get a strong ref from it.
|
||||
assert self._invweak is not None
|
||||
inv = self._invweak()
|
||||
if inv is not None:
|
||||
return inv
|
||||
# Refcount of referent must have dropped to zero, as in `bidict().inv.inv`. Init a new one.
|
||||
self._init_inv() # Now this bidict will retain a strong ref to its inverse.
|
||||
return self._inv
|
||||
|
||||
#: Alias for :attr:`inverse`.
|
||||
inv = inverse
|
||||
|
||||
def __getstate__(self) -> dict:
|
||||
"""Needed to enable pickling due to use of :attr:`__slots__` and weakrefs.
|
||||
|
||||
*See also* :meth:`object.__getstate__`
|
||||
"""
|
||||
state = {}
|
||||
for cls in self.__class__.__mro__:
|
||||
slots = getattr(cls, '__slots__', ())
|
||||
for slot in slots:
|
||||
if hasattr(self, slot):
|
||||
state[slot] = getattr(self, slot)
|
||||
# weakrefs can't be pickled.
|
||||
state.pop('_invweak', None) # Added back in __setstate__ via _init_inv call.
|
||||
state.pop('__weakref__', None) # Not added back in __setstate__. Python manages this one.
|
||||
return state
|
||||
|
||||
def __setstate__(self, state: dict) -> None:
|
||||
"""Implemented because use of :attr:`__slots__` would prevent unpickling otherwise.
|
||||
|
||||
*See also* :meth:`object.__setstate__`
|
||||
"""
|
||||
for slot, value in state.items():
|
||||
setattr(self, slot, value)
|
||||
self._init_inv()
|
||||
|
||||
def __repr__(self) -> str:
|
||||
"""See :func:`repr`."""
|
||||
clsname = self.__class__.__name__
|
||||
if not self:
|
||||
return f'{clsname}()'
|
||||
return f'{clsname}({self._repr_delegate(self.items())})'
|
||||
|
||||
# The inherited Mapping.__eq__ implementation would work, but it's implemented in terms of an
|
||||
# inefficient ``dict(self.items()) == dict(other.items())`` comparison, so override it with a
|
||||
# more efficient implementation.
|
||||
def __eq__(self, other: object) -> bool:
|
||||
"""*x.__eq__(other) ⟺ x == other*
|
||||
|
||||
Equivalent to *dict(x.items()) == dict(other.items())*
|
||||
but more efficient.
|
||||
|
||||
Note that :meth:`bidict's __eq__() <bidict.bidict.__eq__>` implementation
|
||||
is inherited by subclasses,
|
||||
in particular by the ordered bidict subclasses,
|
||||
so even with ordered bidicts,
|
||||
:ref:`== comparison is order-insensitive <eq-order-insensitive>`.
|
||||
|
||||
*See also* :meth:`bidict.FrozenOrderedBidict.equals_order_sensitive`
|
||||
"""
|
||||
if not isinstance(other, _t.Mapping) or len(self) != len(other):
|
||||
return False
|
||||
selfget = self.get
|
||||
return all(selfget(k, _NONE) == v for (k, v) in other.items()) # type: ignore
|
||||
|
||||
# The following methods are mutating and so are not public. But they are implemented in this
|
||||
# non-mutable base class (rather than the mutable `bidict` subclass) because they are used here
|
||||
# during initialization (starting with the `_update` method). (Why is this? Because `__init__`
|
||||
# and `update` share a lot of the same behavior (inserting the provided items while respecting
|
||||
# `on_dup`), so it makes sense for them to share implementation too.)
|
||||
def _pop(self, key: KT) -> VT:
|
||||
val = self._fwdm.pop(key)
|
||||
del self._invm[val]
|
||||
return val
|
||||
|
||||
def _put(self, key: KT, val: VT, on_dup: OnDup) -> None:
|
||||
dedup_result = self._dedup_item(key, val, on_dup)
|
||||
if dedup_result is not None:
|
||||
self._write_item(key, val, dedup_result)
|
||||
|
||||
def _dedup_item(self, key: KT, val: VT, on_dup: OnDup) -> _t.Optional[_DedupResult]:
|
||||
"""Check *key* and *val* for any duplication in self.
|
||||
|
||||
Handle any duplication as per the passed in *on_dup*.
|
||||
|
||||
(key, val) already present is construed as a no-op, not a duplication.
|
||||
|
||||
If duplication is found and the corresponding :class:`~bidict.OnDupAction` is
|
||||
:attr:`~bidict.DROP_NEW`, return None.
|
||||
|
||||
If duplication is found and the corresponding :class:`~bidict.OnDupAction` is
|
||||
:attr:`~bidict.RAISE`, raise the appropriate error.
|
||||
|
||||
If duplication is found and the corresponding :class:`~bidict.OnDupAction` is
|
||||
:attr:`~bidict.DROP_OLD`,
|
||||
or if no duplication is found,
|
||||
return the :class:`_DedupResult` *(isdupkey, isdupval, oldkey, oldval)*.
|
||||
"""
|
||||
fwdm = self._fwdm
|
||||
invm = self._invm
|
||||
oldval: OVT = fwdm.get(key, _NONE)
|
||||
oldkey: OKT = invm.get(val, _NONE)
|
||||
isdupkey = oldval is not _NONE
|
||||
isdupval = oldkey is not _NONE
|
||||
dedup_result = _DedupResult(isdupkey, isdupval, oldkey, oldval)
|
||||
if isdupkey and isdupval:
|
||||
if self._already_have(key, val, oldkey, oldval):
|
||||
# (key, val) duplicates an existing item -> no-op.
|
||||
return None
|
||||
# key and val each duplicate a different existing item.
|
||||
if on_dup.kv is RAISE:
|
||||
raise KeyAndValueDuplicationError(key, val)
|
||||
if on_dup.kv is DROP_NEW:
|
||||
return None
|
||||
assert on_dup.kv is DROP_OLD
|
||||
# Fall through to the return statement on the last line.
|
||||
elif isdupkey:
|
||||
if on_dup.key is RAISE:
|
||||
raise KeyDuplicationError(key)
|
||||
if on_dup.key is DROP_NEW:
|
||||
return None
|
||||
assert on_dup.key is DROP_OLD
|
||||
# Fall through to the return statement on the last line.
|
||||
elif isdupval:
|
||||
if on_dup.val is RAISE:
|
||||
raise ValueDuplicationError(val)
|
||||
if on_dup.val is DROP_NEW:
|
||||
return None
|
||||
assert on_dup.val is DROP_OLD
|
||||
# Fall through to the return statement on the last line.
|
||||
# else neither isdupkey nor isdupval.
|
||||
return dedup_result
|
||||
|
||||
@staticmethod
|
||||
def _already_have(key: KT, val: VT, oldkey: OKT, oldval: OVT) -> bool:
|
||||
# Overridden by _orderedbase.OrderedBidictBase.
|
||||
isdup = oldkey == key
|
||||
assert isdup == (oldval == val), f'{key} {val} {oldkey} {oldval}'
|
||||
return isdup
|
||||
|
||||
def _write_item(self, key: KT, val: VT, dedup_result: _DedupResult) -> _WriteResult:
|
||||
# Overridden by _orderedbase.OrderedBidictBase.
|
||||
isdupkey, isdupval, oldkey, oldval = dedup_result
|
||||
fwdm = self._fwdm
|
||||
invm = self._invm
|
||||
fwdm[key] = val
|
||||
invm[val] = key
|
||||
if isdupkey:
|
||||
del invm[oldval]
|
||||
if isdupval:
|
||||
del fwdm[oldkey]
|
||||
return _WriteResult(key, val, oldkey, oldval)
|
||||
|
||||
def _update(self, init: bool, on_dup: OnDup, *args: MapOrIterItems[KT, VT], **kw: VT) -> None:
|
||||
# args[0] may be a generator that yields many items, so process input in a single pass.
|
||||
if not args and not kw:
|
||||
return
|
||||
can_skip_dup_check = not self and not kw and isinstance(args[0], BidirectionalMapping)
|
||||
if can_skip_dup_check:
|
||||
self._update_no_dup_check(args[0]) # type: ignore
|
||||
return
|
||||
can_skip_rollback = init or RAISE not in on_dup
|
||||
if can_skip_rollback:
|
||||
self._update_no_rollback(on_dup, *args, **kw)
|
||||
else:
|
||||
self._update_with_rollback(on_dup, *args, **kw)
|
||||
|
||||
def _update_no_dup_check(self, other: BidirectionalMapping[KT, VT]) -> None:
|
||||
write_item = self._write_item
|
||||
for (key, val) in other.items():
|
||||
write_item(key, val, _NODUP)
|
||||
|
||||
def _update_no_rollback(self, on_dup: OnDup, *args: MapOrIterItems[KT, VT], **kw: VT) -> None:
|
||||
put = self._put
|
||||
for (key, val) in _iteritems_args_kw(*args, **kw):
|
||||
put(key, val, on_dup)
|
||||
|
||||
def _update_with_rollback(self, on_dup: OnDup, *args: MapOrIterItems[KT, VT], **kw: VT) -> None:
|
||||
"""Update, rolling back on failure."""
|
||||
writes: _t.List[_t.Tuple[_DedupResult, _WriteResult]] = []
|
||||
append_write = writes.append
|
||||
dedup_item = self._dedup_item
|
||||
write_item = self._write_item
|
||||
for (key, val) in _iteritems_args_kw(*args, **kw):
|
||||
try:
|
||||
dedup_result = dedup_item(key, val, on_dup)
|
||||
except DuplicationError:
|
||||
undo_write = self._undo_write
|
||||
for dedup_result, write_result in reversed(writes):
|
||||
undo_write(dedup_result, write_result)
|
||||
raise
|
||||
if dedup_result is not None:
|
||||
write_result = write_item(key, val, dedup_result)
|
||||
append_write((dedup_result, write_result))
|
||||
|
||||
def _undo_write(self, dedup_result: _DedupResult, write_result: _WriteResult) -> None:
|
||||
isdupkey, isdupval, _, _ = dedup_result
|
||||
key, val, oldkey, oldval = write_result
|
||||
if not isdupkey and not isdupval:
|
||||
self._pop(key)
|
||||
return
|
||||
fwdm = self._fwdm
|
||||
invm = self._invm
|
||||
if isdupkey:
|
||||
fwdm[key] = oldval
|
||||
invm[oldval] = key
|
||||
if not isdupval:
|
||||
del invm[val]
|
||||
if isdupval:
|
||||
invm[val] = oldkey
|
||||
fwdm[oldkey] = val
|
||||
if not isdupkey:
|
||||
del fwdm[key]
|
||||
|
||||
def copy(self: BT) -> BT:
|
||||
"""A shallow copy."""
|
||||
# Could just ``return self.__class__(self)`` here instead, but the below is faster. It uses
|
||||
# __new__ to create a copy instance while bypassing its __init__, which would result
|
||||
# in copying this bidict's items into the copy instance one at a time. Instead, make whole
|
||||
# copies of each of the backing mappings, and make them the backing mappings of the copy,
|
||||
# avoiding copying items one at a time.
|
||||
cp = self.__class__.__new__(self.__class__)
|
||||
cp._fwdm = copy(self._fwdm)
|
||||
cp._invm = copy(self._invm)
|
||||
cp._init_inv()
|
||||
return cp # type: ignore
|
||||
|
||||
#: Used for the copy protocol.
|
||||
#: *See also* the :mod:`copy` module
|
||||
__copy__ = copy
|
||||
|
||||
def __len__(self) -> int:
|
||||
"""The number of contained items."""
|
||||
return len(self._fwdm)
|
||||
|
||||
def __iter__(self) -> _t.Iterator[KT]:
|
||||
"""Iterator over the contained keys."""
|
||||
return iter(self._fwdm)
|
||||
|
||||
def __getitem__(self, key: KT) -> VT:
|
||||
"""*x.__getitem__(key) ⟺ x[key]*"""
|
||||
return self._fwdm[key]
|
||||
|
||||
|
||||
# Work around weakref slot with Generics bug on Python 3.6 (https://bugs.python.org/issue41451):
|
||||
BidictBase.__slots__.remove('__weakref__')
|
||||
|
||||
# * Code review nav *
|
||||
#==============================================================================
|
||||
# ← Prev: _abc.py Current: _base.py Next: _frozenbidict.py →
|
||||
#==============================================================================
|
||||
51
hypenv/lib/python3.11/site-packages/bidict/_bidict.py
Normal file
51
hypenv/lib/python3.11/site-packages/bidict/_bidict.py
Normal file
@@ -0,0 +1,51 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2009-2020 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/.
|
||||
|
||||
|
||||
#==============================================================================
|
||||
# * Welcome to the bidict source code *
|
||||
#==============================================================================
|
||||
|
||||
# Doing a code review? You'll find a "Code review nav" comment like the one
|
||||
# below at the top and bottom of the most important source files. This provides
|
||||
# a suggested initial path through the source when reviewing.
|
||||
#
|
||||
# Note: If you aren't reading this on https://github.com/jab/bidict, you may be
|
||||
# viewing an outdated version of the code. Please head to GitHub to review the
|
||||
# latest version, which contains important improvements over older versions.
|
||||
#
|
||||
# Thank you for reading and for any feedback you provide.
|
||||
|
||||
# * Code review nav *
|
||||
#==============================================================================
|
||||
# ← Prev: _mut.py Current: _bidict.py Next: _orderedbase.py →
|
||||
#==============================================================================
|
||||
|
||||
|
||||
"""Provide :class:`bidict`."""
|
||||
|
||||
import typing as _t
|
||||
|
||||
from ._delegating import _DelegatingBidict
|
||||
from ._mut import MutableBidict
|
||||
from ._typing import KT, VT
|
||||
|
||||
|
||||
class bidict(_DelegatingBidict[KT, VT], MutableBidict[KT, VT]):
|
||||
"""Base class for mutable bidirectional mappings."""
|
||||
|
||||
__slots__ = ()
|
||||
|
||||
if _t.TYPE_CHECKING:
|
||||
@property
|
||||
def inverse(self) -> 'bidict[VT, KT]': ...
|
||||
|
||||
|
||||
# * Code review nav *
|
||||
#==============================================================================
|
||||
# ← Prev: _mut.py Current: _bidict.py Next: _orderedbase.py →
|
||||
#==============================================================================
|
||||
39
hypenv/lib/python3.11/site-packages/bidict/_delegating.py
Normal file
39
hypenv/lib/python3.11/site-packages/bidict/_delegating.py
Normal file
@@ -0,0 +1,39 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2009-2020 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/.
|
||||
|
||||
|
||||
"""Provide :class:`_DelegatingBidict`."""
|
||||
|
||||
import typing as _t
|
||||
|
||||
from ._base import BidictBase
|
||||
from ._typing import KT, VT
|
||||
|
||||
|
||||
class _DelegatingBidict(BidictBase[KT, VT]):
|
||||
"""Provide optimized implementations of several methods by delegating to backing dicts.
|
||||
|
||||
Used to override less efficient implementations inherited by :class:`~collections.abc.Mapping`.
|
||||
"""
|
||||
|
||||
__slots__ = ()
|
||||
|
||||
def __iter__(self) -> _t.Iterator[KT]:
|
||||
"""Iterator over the contained keys."""
|
||||
return iter(self._fwdm)
|
||||
|
||||
def keys(self) -> _t.KeysView[KT]:
|
||||
"""A set-like object providing a view on the contained keys."""
|
||||
return self._fwdm.keys()
|
||||
|
||||
def values(self) -> _t.KeysView[VT]: # type: ignore # https://github.com/python/typeshed/issues/4435
|
||||
"""A set-like object providing a view on the contained values."""
|
||||
return self._invm.keys()
|
||||
|
||||
def items(self) -> _t.ItemsView[KT, VT]:
|
||||
"""A set-like object providing a view on the contained items."""
|
||||
return self._fwdm.items()
|
||||
58
hypenv/lib/python3.11/site-packages/bidict/_dup.py
Normal file
58
hypenv/lib/python3.11/site-packages/bidict/_dup.py
Normal file
@@ -0,0 +1,58 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2009-2020 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/.
|
||||
|
||||
|
||||
"""Provide :class:`OnDup` and related functionality."""
|
||||
|
||||
|
||||
from collections import namedtuple
|
||||
from enum import Enum
|
||||
|
||||
|
||||
class OnDupAction(Enum):
|
||||
"""An action to take to prevent duplication from occurring."""
|
||||
|
||||
#: Raise a :class:`~bidict.DuplicationError`.
|
||||
RAISE = 'RAISE'
|
||||
#: Overwrite existing items with new items.
|
||||
DROP_OLD = 'DROP_OLD'
|
||||
#: Keep existing items and drop new items.
|
||||
DROP_NEW = 'DROP_NEW'
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f'<{self.name}>'
|
||||
|
||||
|
||||
RAISE = OnDupAction.RAISE
|
||||
DROP_OLD = OnDupAction.DROP_OLD
|
||||
DROP_NEW = OnDupAction.DROP_NEW
|
||||
|
||||
|
||||
class OnDup(namedtuple('_OnDup', 'key val kv')):
|
||||
r"""A 3-tuple of :class:`OnDupAction`\s specifying how to handle the 3 kinds of duplication.
|
||||
|
||||
*See also* :ref:`basic-usage:Values Must Be Unique`
|
||||
|
||||
If *kv* is not specified, *val* will be used for *kv*.
|
||||
"""
|
||||
|
||||
__slots__ = ()
|
||||
|
||||
def __new__(cls, key: OnDupAction = DROP_OLD, val: OnDupAction = RAISE, kv: OnDupAction = RAISE) -> 'OnDup':
|
||||
"""Override to provide user-friendly default values."""
|
||||
return super().__new__(cls, key, val, kv or val)
|
||||
|
||||
|
||||
#: Default :class:`OnDup` used for the
|
||||
#: :meth:`~bidict.bidict.__init__`,
|
||||
#: :meth:`~bidict.bidict.__setitem__`, and
|
||||
#: :meth:`~bidict.bidict.update` methods.
|
||||
ON_DUP_DEFAULT = OnDup()
|
||||
#: An :class:`OnDup` whose members are all :obj:`RAISE`.
|
||||
ON_DUP_RAISE = OnDup(key=RAISE, val=RAISE, kv=RAISE)
|
||||
#: An :class:`OnDup` whose members are all :obj:`DROP_OLD`.
|
||||
ON_DUP_DROP_OLD = OnDup(key=DROP_OLD, val=DROP_OLD, kv=DROP_OLD)
|
||||
35
hypenv/lib/python3.11/site-packages/bidict/_exc.py
Normal file
35
hypenv/lib/python3.11/site-packages/bidict/_exc.py
Normal file
@@ -0,0 +1,35 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2009-2020 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/.
|
||||
|
||||
|
||||
"""Provide all bidict exceptions."""
|
||||
|
||||
|
||||
class BidictException(Exception):
|
||||
"""Base class for bidict exceptions."""
|
||||
|
||||
|
||||
class DuplicationError(BidictException):
|
||||
"""Base class for exceptions raised when uniqueness is violated
|
||||
as per the :attr:~bidict.RAISE` :class:`~bidict.OnDupAction`.
|
||||
"""
|
||||
|
||||
|
||||
class KeyDuplicationError(DuplicationError):
|
||||
"""Raised when a given key is not unique."""
|
||||
|
||||
|
||||
class ValueDuplicationError(DuplicationError):
|
||||
"""Raised when a given value is not unique."""
|
||||
|
||||
|
||||
class KeyAndValueDuplicationError(KeyDuplicationError, ValueDuplicationError):
|
||||
"""Raised when a given item's key and value are not unique.
|
||||
|
||||
That is, its key duplicates that of another item,
|
||||
and its value duplicates that of a different other item.
|
||||
"""
|
||||
58
hypenv/lib/python3.11/site-packages/bidict/_frozenbidict.py
Normal file
58
hypenv/lib/python3.11/site-packages/bidict/_frozenbidict.py
Normal file
@@ -0,0 +1,58 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2009-2020 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/.
|
||||
|
||||
|
||||
#==============================================================================
|
||||
# * Welcome to the bidict source code *
|
||||
#==============================================================================
|
||||
|
||||
# Doing a code review? You'll find a "Code review nav" comment like the one
|
||||
# below at the top and bottom of the most important source files. This provides
|
||||
# a suggested initial path through the source when reviewing.
|
||||
#
|
||||
# Note: If you aren't reading this on https://github.com/jab/bidict, you may be
|
||||
# viewing an outdated version of the code. Please head to GitHub to review the
|
||||
# latest version, which contains important improvements over older versions.
|
||||
#
|
||||
# Thank you for reading and for any feedback you provide.
|
||||
|
||||
# * Code review nav *
|
||||
#==============================================================================
|
||||
# ← Prev: _base.py Current: _frozenbidict.py Next: _mut.py →
|
||||
#==============================================================================
|
||||
|
||||
"""Provide :class:`frozenbidict`, an immutable, hashable bidirectional mapping type."""
|
||||
|
||||
import typing as _t
|
||||
|
||||
from ._delegating import _DelegatingBidict
|
||||
from ._typing import KT, VT
|
||||
|
||||
|
||||
class frozenbidict(_DelegatingBidict[KT, VT]):
|
||||
"""Immutable, hashable bidict type."""
|
||||
|
||||
__slots__ = ()
|
||||
|
||||
# Work around lack of support for higher-kinded types in mypy.
|
||||
# Ref: https://github.com/python/typing/issues/548#issuecomment-621571821
|
||||
# Remove this and similar type stubs from other classes if support is ever added.
|
||||
if _t.TYPE_CHECKING:
|
||||
@property
|
||||
def inverse(self) -> 'frozenbidict[VT, KT]': ...
|
||||
|
||||
def __hash__(self) -> int:
|
||||
"""The hash of this bidict as determined by its items."""
|
||||
if getattr(self, '_hash', None) is None:
|
||||
self._hash = _t.ItemsView(self)._hash() # type: ignore
|
||||
return self._hash # type: ignore
|
||||
|
||||
|
||||
# * Code review nav *
|
||||
#==============================================================================
|
||||
# ← Prev: _base.py Current: _frozenbidict.py Next: _mut.py →
|
||||
#==============================================================================
|
||||
75
hypenv/lib/python3.11/site-packages/bidict/_frozenordered.py
Normal file
75
hypenv/lib/python3.11/site-packages/bidict/_frozenordered.py
Normal file
@@ -0,0 +1,75 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2009-2020 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/.
|
||||
|
||||
|
||||
#==============================================================================
|
||||
# * Welcome to the bidict source code *
|
||||
#==============================================================================
|
||||
|
||||
# Doing a code review? You'll find a "Code review nav" comment like the one
|
||||
# below at the top and bottom of the most important source files. This provides
|
||||
# a suggested initial path through the source when reviewing.
|
||||
#
|
||||
# Note: If you aren't reading this on https://github.com/jab/bidict, you may be
|
||||
# viewing an outdated version of the code. Please head to GitHub to review the
|
||||
# latest version, which contains important improvements over older versions.
|
||||
#
|
||||
# Thank you for reading and for any feedback you provide.
|
||||
|
||||
# * Code review nav *
|
||||
#==============================================================================
|
||||
#← Prev: _orderedbase.py Current: _frozenordered.py Next: _orderedbidict.py →
|
||||
#==============================================================================
|
||||
|
||||
"""Provide :class:`FrozenOrderedBidict`, an immutable, hashable, ordered bidict."""
|
||||
|
||||
import typing as _t
|
||||
|
||||
from ._frozenbidict import frozenbidict
|
||||
from ._orderedbase import OrderedBidictBase
|
||||
from ._typing import KT, VT
|
||||
|
||||
|
||||
class FrozenOrderedBidict(OrderedBidictBase[KT, VT]):
|
||||
"""Hashable, immutable, ordered bidict type."""
|
||||
|
||||
__slots__ = ()
|
||||
__hash__ = frozenbidict.__hash__
|
||||
|
||||
if _t.TYPE_CHECKING:
|
||||
@property
|
||||
def inverse(self) -> 'FrozenOrderedBidict[VT, KT]': ...
|
||||
|
||||
# Assume the Python implementation's dict type is ordered (e.g. PyPy or CPython >= 3.6), so we
|
||||
# can delegate to `_fwdm` and `_invm` for faster implementations of several methods. Both
|
||||
# `_fwdm` and `_invm` will always be initialized with the provided items in the correct order,
|
||||
# and since `FrozenOrderedBidict` is immutable, their respective orders can't get out of sync
|
||||
# after a mutation.
|
||||
def __iter__(self) -> _t.Iterator[KT]:
|
||||
"""Iterator over the contained keys in insertion order."""
|
||||
return self._iter()
|
||||
|
||||
def _iter(self, *, reverse: bool = False) -> _t.Iterator[KT]:
|
||||
if reverse:
|
||||
return super()._iter(reverse=True)
|
||||
return iter(self._fwdm._fwdm)
|
||||
|
||||
def keys(self) -> _t.KeysView[KT]:
|
||||
"""A set-like object providing a view on the contained keys."""
|
||||
return self._fwdm._fwdm.keys()
|
||||
|
||||
def values(self) -> _t.KeysView[VT]: # type: ignore
|
||||
"""A set-like object providing a view on the contained values."""
|
||||
return self._invm._fwdm.keys()
|
||||
|
||||
# We can't delegate for items because values in `_fwdm` are nodes.
|
||||
|
||||
|
||||
# * Code review nav *
|
||||
#==============================================================================
|
||||
#← Prev: _orderedbase.py Current: _frozenordered.py Next: _orderedbidict.py →
|
||||
#==============================================================================
|
||||
67
hypenv/lib/python3.11/site-packages/bidict/_iter.py
Normal file
67
hypenv/lib/python3.11/site-packages/bidict/_iter.py
Normal file
@@ -0,0 +1,67 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2009-2020 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/.
|
||||
|
||||
|
||||
"""Functions for iterating over items in a mapping."""
|
||||
|
||||
import typing as _t
|
||||
from collections.abc import Mapping
|
||||
from itertools import chain, repeat
|
||||
|
||||
from ._typing import KT, VT, IterItems, MapOrIterItems
|
||||
|
||||
|
||||
_NULL_IT = repeat(None, 0) # repeat 0 times -> raise StopIteration from the start
|
||||
|
||||
|
||||
def _iteritems_mapping_or_iterable(arg: MapOrIterItems[KT, VT]) -> IterItems[KT, VT]:
|
||||
"""Yield the items in *arg*.
|
||||
|
||||
If *arg* is a :class:`~collections.abc.Mapping`, return an iterator over its items.
|
||||
Otherwise return an iterator over *arg* itself.
|
||||
"""
|
||||
return iter(arg.items() if isinstance(arg, Mapping) else arg)
|
||||
|
||||
|
||||
def _iteritems_args_kw(*args: MapOrIterItems[KT, VT], **kw: VT) -> IterItems[KT, VT]:
|
||||
"""Yield the items from the positional argument (if given) and then any from *kw*.
|
||||
|
||||
:raises TypeError: if more than one positional argument is given.
|
||||
"""
|
||||
args_len = len(args)
|
||||
if args_len > 1:
|
||||
raise TypeError(f'Expected at most 1 positional argument, got {args_len}')
|
||||
itemchain = None
|
||||
if args:
|
||||
arg = args[0]
|
||||
if arg:
|
||||
itemchain = _iteritems_mapping_or_iterable(arg)
|
||||
if kw:
|
||||
iterkw = iter(kw.items())
|
||||
itemchain = chain(itemchain, iterkw) if itemchain else iterkw # type: ignore
|
||||
return itemchain or _NULL_IT # type: ignore
|
||||
|
||||
|
||||
@_t.overload
|
||||
def inverted(arg: _t.Mapping[KT, VT]) -> IterItems[VT, KT]: ...
|
||||
@_t.overload
|
||||
def inverted(arg: IterItems[KT, VT]) -> IterItems[VT, KT]: ...
|
||||
def inverted(arg: MapOrIterItems[KT, VT]) -> IterItems[VT, KT]:
|
||||
"""Yield the inverse items of the provided object.
|
||||
|
||||
If *arg* has a :func:`callable` ``__inverted__`` attribute,
|
||||
return the result of calling it.
|
||||
|
||||
Otherwise, return an iterator over the items in `arg`,
|
||||
inverting each item on the fly.
|
||||
|
||||
*See also* :attr:`bidict.BidirectionalMapping.__inverted__`
|
||||
"""
|
||||
inv = getattr(arg, '__inverted__', None)
|
||||
if callable(inv):
|
||||
return inv() # type: ignore
|
||||
return ((val, key) for (key, val) in _iteritems_mapping_or_iterable(arg))
|
||||
188
hypenv/lib/python3.11/site-packages/bidict/_mut.py
Normal file
188
hypenv/lib/python3.11/site-packages/bidict/_mut.py
Normal file
@@ -0,0 +1,188 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2009-2020 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/.
|
||||
|
||||
|
||||
#==============================================================================
|
||||
# * Welcome to the bidict source code *
|
||||
#==============================================================================
|
||||
|
||||
# Doing a code review? You'll find a "Code review nav" comment like the one
|
||||
# below at the top and bottom of the most important source files. This provides
|
||||
# a suggested initial path through the source when reviewing.
|
||||
#
|
||||
# Note: If you aren't reading this on https://github.com/jab/bidict, you may be
|
||||
# viewing an outdated version of the code. Please head to GitHub to review the
|
||||
# latest version, which contains important improvements over older versions.
|
||||
#
|
||||
# Thank you for reading and for any feedback you provide.
|
||||
|
||||
# * Code review nav *
|
||||
#==============================================================================
|
||||
# ← Prev: _frozenbidict.py Current: _mut.py Next: _bidict.py →
|
||||
#==============================================================================
|
||||
|
||||
|
||||
"""Provide :class:`MutableBidict`."""
|
||||
|
||||
import typing as _t
|
||||
|
||||
from ._abc import MutableBidirectionalMapping
|
||||
from ._base import BidictBase
|
||||
from ._dup import OnDup, ON_DUP_RAISE, ON_DUP_DROP_OLD
|
||||
from ._typing import _NONE, KT, VT, VDT, IterItems, MapOrIterItems
|
||||
|
||||
|
||||
class MutableBidict(BidictBase[KT, VT], MutableBidirectionalMapping[KT, VT]):
|
||||
"""Base class for mutable bidirectional mappings."""
|
||||
|
||||
__slots__ = ()
|
||||
|
||||
if _t.TYPE_CHECKING:
|
||||
@property
|
||||
def inverse(self) -> 'MutableBidict[VT, KT]': ...
|
||||
|
||||
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, 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._put(key, val, 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_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: VDT = ...) -> VDT: ...
|
||||
def pop(self, key: KT, default: VDT = _NONE) -> VDT:
|
||||
"""*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 _NONE:
|
||||
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.
|
||||
"""
|
||||
if not self:
|
||||
raise KeyError('mapping is empty')
|
||||
key, val = self._fwdm.popitem()
|
||||
del self._invm[val]
|
||||
return key, val
|
||||
|
||||
@_t.overload
|
||||
def update(self, __arg: _t.Mapping[KT, VT], **kw: VT) -> None: ...
|
||||
@_t.overload
|
||||
def update(self, __arg: 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(False, self.on_dup, *args, **kw)
|
||||
|
||||
@_t.overload
|
||||
def forceupdate(self, __arg: _t.Mapping[KT, VT], **kw: VT) -> None: ...
|
||||
@_t.overload
|
||||
def forceupdate(self, __arg: 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`."""
|
||||
self._update(False, ON_DUP_DROP_OLD, *args, **kw)
|
||||
|
||||
@_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 = ON_DUP_RAISE) -> 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(False, on_dup, items)
|
||||
|
||||
|
||||
# * Code review nav *
|
||||
#==============================================================================
|
||||
# ← Prev: _frozenbidict.py Current: _mut.py Next: _bidict.py →
|
||||
#==============================================================================
|
||||
99
hypenv/lib/python3.11/site-packages/bidict/_named.py
Normal file
99
hypenv/lib/python3.11/site-packages/bidict/_named.py
Normal file
@@ -0,0 +1,99 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2009-2020 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/.
|
||||
|
||||
"""Provide :func:`bidict.namedbidict`."""
|
||||
|
||||
import typing as _t
|
||||
from sys import _getframe
|
||||
|
||||
from ._abc import BidirectionalMapping, KT, VT
|
||||
from ._bidict import bidict
|
||||
|
||||
|
||||
def namedbidict(
|
||||
typename: str,
|
||||
keyname: str,
|
||||
valname: str,
|
||||
*,
|
||||
base_type: _t.Type[BidirectionalMapping[KT, VT]] = bidict,
|
||||
) -> _t.Type[BidirectionalMapping[KT, VT]]:
|
||||
r"""Create a new subclass of *base_type* with custom accessors.
|
||||
|
||||
Like :func:`collections.namedtuple` for bidicts.
|
||||
|
||||
The new class's ``__name__`` and ``__qualname__`` will be set to *typename*,
|
||||
and its ``__module__`` will be set to the caller's module.
|
||||
|
||||
Instances of the new class will provide access to their
|
||||
:attr:`inverse <BidirectionalMapping.inverse>` instances
|
||||
via the custom *keyname*\_for property,
|
||||
and access to themselves
|
||||
via the custom *valname*\_for property.
|
||||
|
||||
*See also* the :ref:`namedbidict usage documentation
|
||||
<other-bidict-types:\:func\:\`~bidict.namedbidict\`>`
|
||||
|
||||
:raises ValueError: if any of the *typename*, *keyname*, or *valname*
|
||||
strings is not a valid Python identifier, or if *keyname == valname*.
|
||||
|
||||
:raises TypeError: if *base_type* is not a :class:`BidirectionalMapping` subclass
|
||||
that provides ``_isinv`` and :meth:`~object.__getstate__` attributes.
|
||||
(Any :class:`~bidict.BidictBase` subclass can be passed in, including all the
|
||||
concrete bidict types pictured in the :ref:`other-bidict-types:Bidict Types Diagram`.
|
||||
"""
|
||||
if not issubclass(base_type, BidirectionalMapping) or not all(hasattr(base_type, i) for i in ('_isinv', '__getstate__')):
|
||||
raise TypeError(base_type)
|
||||
names = (typename, keyname, valname)
|
||||
if not all(map(str.isidentifier, names)) or keyname == valname:
|
||||
raise ValueError(names)
|
||||
|
||||
class _Named(base_type): # type: ignore
|
||||
|
||||
__slots__ = ()
|
||||
|
||||
def _getfwd(self) -> '_Named':
|
||||
return self.inverse if self._isinv else self # type: ignore
|
||||
|
||||
def _getinv(self) -> '_Named':
|
||||
return self if self._isinv else self.inverse # type: ignore
|
||||
|
||||
@property
|
||||
def _keyname(self) -> str:
|
||||
return valname if self._isinv else keyname
|
||||
|
||||
@property
|
||||
def _valname(self) -> str:
|
||||
return keyname if self._isinv else valname
|
||||
|
||||
def __reduce__(self) -> '_t.Tuple[_t.Callable[[str, str, str, _t.Type[BidirectionalMapping]], BidirectionalMapping], _t.Tuple[str, str, str, _t.Type[BidirectionalMapping]], dict]':
|
||||
return (_make_empty, (typename, keyname, valname, base_type), self.__getstate__())
|
||||
|
||||
bname = base_type.__name__
|
||||
fname = valname + '_for'
|
||||
iname = keyname + '_for'
|
||||
fdoc = f'{typename} forward {bname}: {keyname} → {valname}'
|
||||
idoc = f'{typename} inverse {bname}: {valname} → {keyname}'
|
||||
setattr(_Named, fname, property(_Named._getfwd, doc=fdoc))
|
||||
setattr(_Named, iname, property(_Named._getinv, doc=idoc))
|
||||
|
||||
_Named.__name__ = typename
|
||||
_Named.__qualname__ = typename
|
||||
_Named.__module__ = _getframe(1).f_globals.get('__name__') # type: ignore
|
||||
return _Named
|
||||
|
||||
|
||||
def _make_empty(
|
||||
typename: str,
|
||||
keyname: str,
|
||||
valname: str,
|
||||
base_type: _t.Type[BidirectionalMapping] = bidict,
|
||||
) -> BidirectionalMapping:
|
||||
"""Create a named bidict with the indicated arguments and return an empty instance.
|
||||
Used to make :func:`bidict.namedbidict` instances picklable.
|
||||
"""
|
||||
cls = namedbidict(typename, keyname, valname, base_type=base_type)
|
||||
return cls()
|
||||
314
hypenv/lib/python3.11/site-packages/bidict/_orderedbase.py
Normal file
314
hypenv/lib/python3.11/site-packages/bidict/_orderedbase.py
Normal file
@@ -0,0 +1,314 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2009-2020 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/.
|
||||
|
||||
|
||||
#==============================================================================
|
||||
# * Welcome to the bidict source code *
|
||||
#==============================================================================
|
||||
|
||||
# Doing a code review? You'll find a "Code review nav" comment like the one
|
||||
# below at the top and bottom of the most important source files. This provides
|
||||
# a suggested initial path through the source when reviewing.
|
||||
#
|
||||
# Note: If you aren't reading this on https://github.com/jab/bidict, you may be
|
||||
# viewing an outdated version of the code. Please head to GitHub to review the
|
||||
# latest version, which contains important improvements over older versions.
|
||||
#
|
||||
# Thank you for reading and for any feedback you provide.
|
||||
|
||||
# * Code review nav *
|
||||
#==============================================================================
|
||||
# ← Prev: _bidict.py Current: _orderedbase.py Next: _frozenordered.py →
|
||||
#==============================================================================
|
||||
|
||||
|
||||
"""Provide :class:`OrderedBidictBase`."""
|
||||
|
||||
import typing as _t
|
||||
from copy import copy
|
||||
from weakref import ref
|
||||
|
||||
from ._base import _NONE, _DedupResult, _WriteResult, BidictBase, BT
|
||||
from ._bidict import bidict
|
||||
from ._typing import KT, VT, IterItems, MapOrIterItems
|
||||
|
||||
|
||||
class _Node:
|
||||
"""A node in a circular doubly-linked list
|
||||
used to encode the order of items in an ordered bidict.
|
||||
|
||||
Only weak references to the next and previous nodes
|
||||
are held to avoid creating strong reference cycles.
|
||||
|
||||
Because an ordered bidict retains two strong references
|
||||
to each node instance (one from its backing `_fwdm` mapping
|
||||
and one from its `_invm` mapping), a node's refcount will not
|
||||
drop to zero (and so will not be garbage collected) as long as
|
||||
the ordered bidict that contains it is still alive.
|
||||
Because nodes don't have strong reference cycles,
|
||||
once their containing bidict is freed,
|
||||
they too are immediately freed.
|
||||
"""
|
||||
|
||||
__slots__ = ('_prv', '_nxt', '__weakref__')
|
||||
|
||||
def __init__(self, prv: '_Node' = None, nxt: '_Node' = None) -> None:
|
||||
self._setprv(prv)
|
||||
self._setnxt(nxt)
|
||||
|
||||
def __repr__(self) -> str:
|
||||
clsname = self.__class__.__name__
|
||||
prv = id(self.prv)
|
||||
nxt = id(self.nxt)
|
||||
return f'{clsname}(prv={prv}, self={id(self)}, nxt={nxt})'
|
||||
|
||||
def _getprv(self) -> '_t.Optional[_Node]':
|
||||
return self._prv() if isinstance(self._prv, ref) else self._prv
|
||||
|
||||
def _setprv(self, prv: '_t.Optional[_Node]') -> None:
|
||||
self._prv = prv and ref(prv)
|
||||
|
||||
prv = property(_getprv, _setprv)
|
||||
|
||||
def _getnxt(self) -> '_t.Optional[_Node]':
|
||||
return self._nxt() if isinstance(self._nxt, ref) else self._nxt
|
||||
|
||||
def _setnxt(self, nxt: '_t.Optional[_Node]') -> None:
|
||||
self._nxt = nxt and ref(nxt)
|
||||
|
||||
nxt = property(_getnxt, _setnxt)
|
||||
|
||||
def __getstate__(self) -> dict:
|
||||
"""Return the instance state dictionary
|
||||
but with weakrefs converted to strong refs
|
||||
so that it can be pickled.
|
||||
|
||||
*See also* :meth:`object.__getstate__`
|
||||
"""
|
||||
return dict(_prv=self.prv, _nxt=self.nxt)
|
||||
|
||||
def __setstate__(self, state: dict) -> None:
|
||||
"""Set the instance state from *state*."""
|
||||
self._setprv(state['_prv'])
|
||||
self._setnxt(state['_nxt'])
|
||||
|
||||
|
||||
class _SentinelNode(_Node):
|
||||
"""Special node in a circular doubly-linked list
|
||||
that links the first node with the last node.
|
||||
When its next and previous references point back to itself
|
||||
it represents an empty list.
|
||||
"""
|
||||
|
||||
__slots__ = ()
|
||||
|
||||
def __init__(self, prv: _Node = None, nxt: _Node = None) -> None:
|
||||
super().__init__(prv or self, nxt or self)
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return '<SNTL>'
|
||||
|
||||
def __bool__(self) -> bool:
|
||||
return False
|
||||
|
||||
def _iter(self, *, reverse: bool = False) -> _t.Iterator[_Node]:
|
||||
"""Iterator yielding nodes in the requested order,
|
||||
i.e. traverse the linked list via :attr:`nxt`
|
||||
(or :attr:`prv` if *reverse* is truthy)
|
||||
until reaching a falsy (i.e. sentinel) node.
|
||||
"""
|
||||
attr = 'prv' if reverse else 'nxt'
|
||||
node = getattr(self, attr)
|
||||
while node:
|
||||
yield node
|
||||
node = getattr(node, attr)
|
||||
|
||||
|
||||
class OrderedBidictBase(BidictBase[KT, VT]):
|
||||
"""Base class implementing an ordered :class:`BidirectionalMapping`."""
|
||||
|
||||
__slots__ = ('_sntl',)
|
||||
|
||||
_fwdm_cls = bidict # type: ignore
|
||||
_invm_cls = bidict # type: ignore
|
||||
|
||||
#: The object used by :meth:`__repr__` for printing the contained items.
|
||||
_repr_delegate = list # type: ignore
|
||||
|
||||
@_t.overload
|
||||
def __init__(self, __arg: _t.Mapping[KT, VT], **kw: VT) -> None: ...
|
||||
@_t.overload
|
||||
def __init__(self, __arg: IterItems[KT, VT], **kw: VT) -> None: ...
|
||||
@_t.overload
|
||||
def __init__(self, **kw: VT) -> None: ...
|
||||
def __init__(self, *args: MapOrIterItems[KT, VT], **kw: VT) -> None:
|
||||
"""Make a new ordered bidirectional mapping.
|
||||
The signature behaves like that of :class:`dict`.
|
||||
Items passed in are added in the order they are passed,
|
||||
respecting the :attr:`on_dup` class attribute in the process.
|
||||
|
||||
The order in which items are inserted is remembered,
|
||||
similar to :class:`collections.OrderedDict`.
|
||||
"""
|
||||
self._sntl = _SentinelNode()
|
||||
|
||||
# Like unordered bidicts, ordered bidicts also store two backing one-directional mappings
|
||||
# `_fwdm` and `_invm`. But rather than mapping `key` to `val` and `val` to `key`
|
||||
# (respectively), they map `key` to `nodefwd` and `val` to `nodeinv` (respectively), where
|
||||
# `nodefwd` is `nodeinv` when `key` and `val` are associated with one another.
|
||||
|
||||
# To effect this difference, `_write_item` and `_undo_write` are overridden. But much of the
|
||||
# rest of BidictBase's implementation, including BidictBase.__init__ and BidictBase._update,
|
||||
# are inherited and are able to be reused without modification.
|
||||
super().__init__(*args, **kw)
|
||||
|
||||
if _t.TYPE_CHECKING:
|
||||
@property
|
||||
def inverse(self) -> 'OrderedBidictBase[VT, KT]': ...
|
||||
_fwdm: bidict[KT, _Node] # type: ignore
|
||||
_invm: bidict[VT, _Node] # type: ignore
|
||||
|
||||
def _init_inv(self) -> None:
|
||||
super()._init_inv()
|
||||
self.inverse._sntl = self._sntl
|
||||
|
||||
# Can't reuse BidictBase.copy since ordered bidicts have different internal structure.
|
||||
def copy(self: BT) -> BT:
|
||||
"""A shallow copy of this ordered bidict."""
|
||||
# Fast copy implementation bypassing __init__. See comments in :meth:`BidictBase.copy`.
|
||||
cp = self.__class__.__new__(self.__class__)
|
||||
sntl = _SentinelNode()
|
||||
fwdm = copy(self._fwdm)
|
||||
invm = copy(self._invm)
|
||||
cur = sntl
|
||||
nxt = sntl.nxt
|
||||
for (key, val) in self.items():
|
||||
nxt = _Node(cur, sntl)
|
||||
cur.nxt = fwdm[key] = invm[val] = nxt
|
||||
cur = nxt
|
||||
sntl.prv = nxt
|
||||
cp._sntl = sntl
|
||||
cp._fwdm = fwdm
|
||||
cp._invm = invm
|
||||
cp._init_inv()
|
||||
return cp # type: ignore
|
||||
|
||||
__copy__ = copy
|
||||
|
||||
def __getitem__(self, key: KT) -> VT:
|
||||
nodefwd = self._fwdm[key]
|
||||
val = self._invm.inverse[nodefwd]
|
||||
return val
|
||||
|
||||
def _pop(self, key: KT) -> VT:
|
||||
nodefwd = self._fwdm.pop(key)
|
||||
val = self._invm.inverse.pop(nodefwd)
|
||||
nodefwd.prv.nxt = nodefwd.nxt
|
||||
nodefwd.nxt.prv = nodefwd.prv
|
||||
return val
|
||||
|
||||
@staticmethod
|
||||
def _already_have(key: KT, val: VT, nodeinv: _Node, nodefwd: _Node) -> bool: # type: ignore
|
||||
# Overrides _base.BidictBase.
|
||||
return nodeinv is nodefwd
|
||||
|
||||
def _write_item(self, key: KT, val: VT, dedup_result: _DedupResult) -> _WriteResult:
|
||||
# Overrides _base.BidictBase.
|
||||
fwdm = self._fwdm # bidict mapping keys to nodes
|
||||
invm = self._invm # bidict mapping vals to nodes
|
||||
isdupkey, isdupval, nodeinv, nodefwd = dedup_result
|
||||
if not isdupkey and not isdupval:
|
||||
# No key or value duplication -> create and append a new node.
|
||||
sntl = self._sntl
|
||||
last = sntl.prv
|
||||
node = _Node(last, sntl)
|
||||
last.nxt = sntl.prv = fwdm[key] = invm[val] = node
|
||||
oldkey = oldval = _NONE
|
||||
elif isdupkey and isdupval:
|
||||
# Key and value duplication across two different nodes.
|
||||
assert nodefwd is not nodeinv
|
||||
oldval = invm.inverse[nodefwd] # type: ignore
|
||||
oldkey = fwdm.inverse[nodeinv] # type: ignore
|
||||
assert oldkey != key
|
||||
assert oldval != val
|
||||
# We have to collapse nodefwd and nodeinv into a single node, i.e. drop one of them.
|
||||
# Drop nodeinv, so that the item with the same key is the one overwritten in place.
|
||||
nodeinv.prv.nxt = nodeinv.nxt
|
||||
nodeinv.nxt.prv = nodeinv.prv
|
||||
# Don't remove nodeinv's references to its neighbors since
|
||||
# if the update fails, we'll need them to undo this write.
|
||||
# Update fwdm and invm.
|
||||
tmp = fwdm.pop(oldkey) # type: ignore
|
||||
assert tmp is nodeinv
|
||||
tmp = invm.pop(oldval) # type: ignore
|
||||
assert tmp is nodefwd
|
||||
fwdm[key] = invm[val] = nodefwd
|
||||
elif isdupkey:
|
||||
oldval = invm.inverse[nodefwd] # type: ignore
|
||||
oldkey = _NONE
|
||||
oldnodeinv = invm.pop(oldval) # type: ignore
|
||||
assert oldnodeinv is nodefwd
|
||||
invm[val] = nodefwd
|
||||
else: # isdupval
|
||||
oldkey = fwdm.inverse[nodeinv] # type: ignore
|
||||
oldval = _NONE
|
||||
oldnodefwd = fwdm.pop(oldkey) # type: ignore
|
||||
assert oldnodefwd is nodeinv
|
||||
fwdm[key] = nodeinv
|
||||
return _WriteResult(key, val, oldkey, oldval)
|
||||
|
||||
def _undo_write(self, dedup_result: _DedupResult, write_result: _WriteResult) -> None:
|
||||
fwdm = self._fwdm
|
||||
invm = self._invm
|
||||
isdupkey, isdupval, nodeinv, nodefwd = dedup_result
|
||||
key, val, oldkey, oldval = write_result
|
||||
if not isdupkey and not isdupval:
|
||||
self._pop(key)
|
||||
elif isdupkey and isdupval:
|
||||
# Restore original items.
|
||||
nodeinv.prv.nxt = nodeinv.nxt.prv = nodeinv
|
||||
fwdm[oldkey] = invm[val] = nodeinv
|
||||
invm[oldval] = fwdm[key] = nodefwd
|
||||
elif isdupkey:
|
||||
tmp = invm.pop(val)
|
||||
assert tmp is nodefwd
|
||||
invm[oldval] = nodefwd
|
||||
assert fwdm[key] is nodefwd
|
||||
else: # isdupval
|
||||
tmp = fwdm.pop(key)
|
||||
assert tmp is nodeinv
|
||||
fwdm[oldkey] = nodeinv
|
||||
assert invm[val] is nodeinv
|
||||
|
||||
def __iter__(self) -> _t.Iterator[KT]:
|
||||
"""Iterator over the contained keys in insertion order."""
|
||||
return self._iter()
|
||||
|
||||
def _iter(self, *, reverse: bool = False) -> _t.Iterator[KT]:
|
||||
fwdm_inv = self._fwdm.inverse
|
||||
for node in self._sntl._iter(reverse=reverse):
|
||||
yield fwdm_inv[node]
|
||||
|
||||
def __reversed__(self) -> _t.Iterator[KT]:
|
||||
"""Iterator over the contained keys in reverse insertion order."""
|
||||
yield from self._iter(reverse=True)
|
||||
|
||||
def equals_order_sensitive(self, other: object) -> bool:
|
||||
"""Order-sensitive equality check.
|
||||
|
||||
*See also* :ref:`eq-order-insensitive`
|
||||
"""
|
||||
# Same short-circuit as BidictBase.__eq__. Factoring out not worth function call overhead.
|
||||
if not isinstance(other, _t.Mapping) or len(self) != len(other):
|
||||
return False
|
||||
return all(i == j for (i, j) in zip(self.items(), other.items()))
|
||||
|
||||
|
||||
# * Code review nav *
|
||||
#==============================================================================
|
||||
# ← Prev: _bidict.py Current: _orderedbase.py Next: _frozenordered.py →
|
||||
#==============================================================================
|
||||
93
hypenv/lib/python3.11/site-packages/bidict/_orderedbidict.py
Normal file
93
hypenv/lib/python3.11/site-packages/bidict/_orderedbidict.py
Normal file
@@ -0,0 +1,93 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2009-2020 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/.
|
||||
|
||||
|
||||
#==============================================================================
|
||||
# * Welcome to the bidict source code *
|
||||
#==============================================================================
|
||||
|
||||
# Doing a code review? You'll find a "Code review nav" comment like the one
|
||||
# below at the top and bottom of the most important source files. This provides
|
||||
# a suggested initial path through the source when reviewing.
|
||||
#
|
||||
# Note: If you aren't reading this on https://github.com/jab/bidict, you may be
|
||||
# viewing an outdated version of the code. Please head to GitHub to review the
|
||||
# latest version, which contains important improvements over older versions.
|
||||
#
|
||||
# Thank you for reading and for any feedback you provide.
|
||||
|
||||
# * Code review nav *
|
||||
#==============================================================================
|
||||
# ← Prev: _frozenordered.py Current: _orderedbidict.py <FIN>
|
||||
#==============================================================================
|
||||
|
||||
|
||||
"""Provide :class:`OrderedBidict`."""
|
||||
|
||||
import typing as _t
|
||||
|
||||
from ._mut import MutableBidict
|
||||
from ._orderedbase import OrderedBidictBase
|
||||
from ._typing import KT, VT
|
||||
|
||||
|
||||
class OrderedBidict(OrderedBidictBase[KT, VT], MutableBidict[KT, VT]):
|
||||
"""Mutable bidict type that maintains items in insertion order."""
|
||||
|
||||
__slots__ = ()
|
||||
|
||||
if _t.TYPE_CHECKING:
|
||||
@property
|
||||
def inverse(self) -> 'OrderedBidict[VT, KT]': ...
|
||||
|
||||
def clear(self) -> None:
|
||||
"""Remove all items."""
|
||||
self._fwdm.clear()
|
||||
self._invm.clear()
|
||||
self._sntl.nxt = self._sntl.prv = self._sntl
|
||||
|
||||
def popitem(self, last: bool = True) -> _t.Tuple[KT, VT]:
|
||||
"""*x.popitem() → (k, v)*
|
||||
|
||||
Remove and return the most recently added item as a (key, value) pair
|
||||
if *last* is True, else the least recently added item.
|
||||
|
||||
:raises KeyError: if *x* is empty.
|
||||
"""
|
||||
if not self:
|
||||
raise KeyError('mapping is empty')
|
||||
key = next((reversed if last else iter)(self)) # type: ignore
|
||||
val = self._pop(key)
|
||||
return key, val
|
||||
|
||||
def move_to_end(self, key: KT, last: bool = True) -> None:
|
||||
"""Move an existing key to the beginning or end of this ordered bidict.
|
||||
|
||||
The item is moved to the end if *last* is True, else to the beginning.
|
||||
|
||||
:raises KeyError: if the key does not exist
|
||||
"""
|
||||
node = self._fwdm[key]
|
||||
node.prv.nxt = node.nxt
|
||||
node.nxt.prv = node.prv
|
||||
sntl = self._sntl
|
||||
if last:
|
||||
lastnode = sntl.prv
|
||||
node.prv = lastnode
|
||||
node.nxt = sntl
|
||||
sntl.prv = lastnode.nxt = node
|
||||
else:
|
||||
firstnode = sntl.nxt
|
||||
node.prv = sntl
|
||||
node.nxt = firstnode
|
||||
sntl.nxt = firstnode.prv = node
|
||||
|
||||
|
||||
# * Code review nav *
|
||||
#==============================================================================
|
||||
# ← Prev: _frozenordered.py Current: _orderedbidict.py <FIN>
|
||||
#==============================================================================
|
||||
33
hypenv/lib/python3.11/site-packages/bidict/_typing.py
Normal file
33
hypenv/lib/python3.11/site-packages/bidict/_typing.py
Normal file
@@ -0,0 +1,33 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2009-2020 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/.
|
||||
|
||||
|
||||
"""Provide typing-related objects."""
|
||||
|
||||
import typing as _t
|
||||
|
||||
|
||||
KT = _t.TypeVar('KT')
|
||||
VT = _t.TypeVar('VT')
|
||||
IterItems = _t.Iterable[_t.Tuple[KT, VT]]
|
||||
MapOrIterItems = _t.Union[_t.Mapping[KT, VT], IterItems[KT, VT]]
|
||||
|
||||
DT = _t.TypeVar('DT') #: for default arguments
|
||||
VDT = _t.Union[VT, DT]
|
||||
|
||||
|
||||
class _BareReprMeta(type):
|
||||
def __repr__(cls) -> str:
|
||||
return f'<{cls.__name__}>'
|
||||
|
||||
|
||||
class _NONE(metaclass=_BareReprMeta):
|
||||
"""Sentinel type used to represent 'missing'."""
|
||||
|
||||
|
||||
OKT = _t.Union[KT, _NONE] #: optional key type
|
||||
OVT = _t.Union[VT, _NONE] #: optional value type
|
||||
4
hypenv/lib/python3.11/site-packages/bidict/_version.py
Normal file
4
hypenv/lib/python3.11/site-packages/bidict/_version.py
Normal file
@@ -0,0 +1,4 @@
|
||||
# coding: utf-8
|
||||
# file generated by setuptools_scm
|
||||
# don't change, don't track in version control
|
||||
version = '0.21.2'
|
||||
49
hypenv/lib/python3.11/site-packages/bidict/metadata.py
Normal file
49
hypenv/lib/python3.11/site-packages/bidict/metadata.py
Normal file
@@ -0,0 +1,49 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2009-2020 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/.
|
||||
|
||||
"""Define bidict package metadata."""
|
||||
|
||||
|
||||
# _version.py is generated by setuptools_scm (via its `write_to` param, see setup.py)
|
||||
try:
|
||||
from ._version import version
|
||||
except (ImportError, ValueError, SystemError): # pragma: no cover
|
||||
try:
|
||||
import pkg_resources
|
||||
except ImportError:
|
||||
__version__ = '0.0.0.VERSION_NOT_FOUND'
|
||||
else:
|
||||
try:
|
||||
__version__ = pkg_resources.get_distribution('bidict').version
|
||||
except pkg_resources.DistributionNotFound:
|
||||
__version__ = '0.0.0.VERSION_NOT_FOUND'
|
||||
else: # pragma: no cover
|
||||
__version__ = version
|
||||
|
||||
try:
|
||||
__version_info__ = tuple(int(p) if i < 3 else p for (i, p) in enumerate(__version__.split('.')))
|
||||
except Exception: # pragma: no cover
|
||||
__vesion_info__ = (0, 0, 0, f'PARSE FAILURE: __version__={__version__!r}')
|
||||
|
||||
__author__ = 'Joshua Bronson'
|
||||
__maintainer__ = 'Joshua Bronson'
|
||||
__copyright__ = 'Copyright 2009-2020 Joshua Bronson'
|
||||
__email__ = 'jabronson@gmail.com'
|
||||
|
||||
# See: ../docs/thanks.rst
|
||||
__credits__ = [i.strip() for i in """
|
||||
Joshua Bronson, Michael Arntzenius, Francis Carr, Gregory Ewing, Raymond Hettinger, Jozef Knaperek,
|
||||
Daniel Pope, Terry Reedy, David Turner, Tom Viner, Richard Sanger, Zeyi Wang
|
||||
""".split(',')]
|
||||
|
||||
__description__ = 'The bidirectional mapping library for Python.'
|
||||
__keywords__ = 'dict dictionary mapping datastructure bimap bijection bijective ' \
|
||||
'injective inverse reverse bidirectional two-way 2-way'
|
||||
|
||||
__license__ = 'MPL 2.0'
|
||||
__status__ = 'Beta'
|
||||
__url__ = 'https://bidict.readthedocs.io'
|
||||
0
hypenv/lib/python3.11/site-packages/bidict/py.typed
Normal file
0
hypenv/lib/python3.11/site-packages/bidict/py.typed
Normal file
Reference in New Issue
Block a user