Skip to content

Commit

Permalink
upgrade to latest ruff
Browse files Browse the repository at this point in the history
  • Loading branch information
jab committed Jan 2, 2025
1 parent 374dfd4 commit e978b18
Show file tree
Hide file tree
Showing 12 changed files with 87 additions and 59 deletions.
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ repos:
- pytest

- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.8.1
rev: v0.8.5
hooks:
- id: ruff
args: [--fix, --unsafe-fixes]
Expand Down
10 changes: 6 additions & 4 deletions bidict/_abc.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,16 @@

from __future__ import annotations

import typing as t
from abc import abstractmethod
from collections.abc import Iterator
from collections.abc import Mapping
from collections.abc import MutableMapping

from ._typing import KT
from ._typing import VT


class BidirectionalMapping(t.Mapping[KT, VT]):
class BidirectionalMapping(Mapping[KT, VT]):
"""Abstract base class for bidirectional mapping types.
Extends :class:`collections.abc.Mapping` primarily by adding the
Expand All @@ -50,7 +52,7 @@ def inverse(self) -> BidirectionalMapping[VT, KT]:
# subclasses must actually provide their own implementation.
raise NotImplementedError

def __inverted__(self) -> t.Iterator[tuple[VT, KT]]:
def __inverted__(self) -> Iterator[tuple[VT, KT]]:
"""Get an iterator over the items in :attr:`inverse`.
This is functionally equivalent to iterating over the items in the
Expand All @@ -67,7 +69,7 @@ def __inverted__(self) -> t.Iterator[tuple[VT, KT]]:
return iter(self.inverse.items())


class MutableBidirectionalMapping(BidirectionalMapping[KT, VT], t.MutableMapping[KT, VT]):
class MutableBidirectionalMapping(BidirectionalMapping[KT, VT], MutableMapping[KT, VT]):
"""Abstract base class for mutable bidirectional mapping types."""

__slots__ = ()
Expand Down
48 changes: 28 additions & 20 deletions bidict/_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,14 @@

import typing as t
import weakref
from collections.abc import ItemsView
from collections.abc import Iterable
from collections.abc import Iterator
from collections.abc import KeysView
from collections.abc import Mapping
from collections.abc import MutableMapping
from collections.abc import Reversible
from collections.abc import ValuesView
from itertools import starmap
from operator import eq
from types import MappingProxyType
Expand Down Expand Up @@ -49,7 +57,7 @@
BT = t.TypeVar('BT', bound='BidictBase[t.Any, t.Any]')


class BidictKeysView(t.KeysView[KT], t.ValuesView[KT]):
class BidictKeysView(KeysView[KT], ValuesView[KT]):
"""Since the keys of a bidict are the values of its inverse (and vice versa),
the :class:`~collections.abc.ValuesView` result of calling *bi.values()*
is also a :class:`~collections.abc.KeysView` of *bi.inverse*.
Expand All @@ -68,12 +76,12 @@ class BidictBase(BidirectionalMapping[KT, VT]):
#: :doc:`extending` (https://bidict.rtfd.io/extending.html)
on_dup = ON_DUP_DEFAULT

_fwdm: t.MutableMapping[KT, VT] #: the backing forward mapping (*key* → *val*)
_invm: t.MutableMapping[VT, KT] #: the backing inverse mapping (*val* → *key*)
_fwdm: MutableMapping[KT, VT] #: the backing forward mapping (*key* → *val*)
_invm: MutableMapping[VT, KT] #: the backing inverse mapping (*val* → *key*)

# Use Any rather than KT/VT in the following to avoid "ClassVar cannot contain type variables" errors:
_fwdm_cls: t.ClassVar[type[t.MutableMapping[t.Any, t.Any]]] = dict #: class of the backing forward mapping
_invm_cls: t.ClassVar[type[t.MutableMapping[t.Any, t.Any]]] = dict #: class of the backing inverse mapping
_fwdm_cls: t.ClassVar[type[MutableMapping[t.Any, t.Any]]] = dict #: class of the backing forward mapping
_invm_cls: t.ClassVar[type[MutableMapping[t.Any, t.Any]]] = dict #: class of the backing inverse mapping

#: The class of the inverse bidict instance.
_inv_cls: t.ClassVar[type[BidictBase[t.Any, t.Any]]]
Expand All @@ -99,7 +107,7 @@ def _set_reversed(cls) -> None:
overridden = resolved is not BidictBase.__reversed__
if overridden: # E.g. OrderedBidictBase, OrderedBidict
return
backing_reversible = all(issubclass(i, t.Reversible) for i in (cls._fwdm_cls, cls._invm_cls))
backing_reversible = all(issubclass(i, Reversible) for i in (cls._fwdm_cls, cls._invm_cls))
cls.__reversed__ = _fwdm_reversed if backing_reversible else None

@classmethod
Expand Down Expand Up @@ -228,7 +236,7 @@ def values(self) -> BidictKeysView[VT]:
"""
return t.cast(BidictKeysView[VT], self.inverse.keys())

def keys(self) -> t.KeysView[KT]:
def keys(self) -> KeysView[KT]:
"""A set-like object providing a view on the contained keys.
When *b._fwdm* is a :class:`dict`, *b.keys()* returns a
Expand All @@ -245,7 +253,7 @@ def keys(self) -> t.KeysView[KT]:
fwdm, fwdm_cls = self._fwdm, self._fwdm_cls
return fwdm.keys() if fwdm_cls is dict else BidictKeysView(self)

def items(self) -> t.ItemsView[KT, VT]:
def items(self) -> ItemsView[KT, VT]:
"""A set-like object providing a view on the contained items.
When *b._fwdm* is a :class:`dict`, *b.items()* returns a
Expand Down Expand Up @@ -286,7 +294,7 @@ def __eq__(self, other: object) -> bool:
*See also* :meth:`equals_order_sensitive`
"""
if isinstance(other, t.Mapping):
if isinstance(other, Mapping):
return self._fwdm.items() == other.items()
# Ref: https://docs.python.org/3/library/constants.html#NotImplemented
return NotImplemented
Expand All @@ -297,7 +305,7 @@ def equals_order_sensitive(self, other: object) -> bool:
*See also* :ref:`eq-order-insensitive`
(https://bidict.rtfd.io/other-bidict-types.html#eq-is-order-insensitive)
"""
if not isinstance(other, t.Mapping) or len(self) != len(other):
if not isinstance(other, Mapping) or len(self) != len(other):
return False
return all(starmap(eq, zip(self.items(), other.items())))

Expand Down Expand Up @@ -413,14 +421,14 @@ def _write(self, newkey: KT, newval: VT, oldkey: OKT[KT], oldval: OVT[VT], unwri
def _update(
self,
arg: MapOrItems[KT, VT],
kw: t.Mapping[str, VT] = MappingProxyType({}),
kw: Mapping[str, VT] = MappingProxyType({}),
*,
rollback: bool | None = None,
on_dup: OnDup | None = None,
) -> None:
"""Update with the items from *arg* and *kw*, maybe failing and rolling back as per *on_dup* and *rollback*."""
# Note: We must process input in a single pass, since arg may be a generator.
if not isinstance(arg, (t.Iterable, Maplike)):
if not isinstance(arg, (Iterable, Maplike)):
raise TypeError(f"'{arg.__class__.__name__}' object is not iterable")
if not arg and not kw:
return
Expand Down Expand Up @@ -495,17 +503,17 @@ def _init_from(self, other: MapOrItems[KT, VT]) -> None:

# other's type is Mapping rather than Maplike since bidict() | SupportsKeysAndGetItem({})
# raises a TypeError, just like dict() | SupportsKeysAndGetItem({}) does.
def __or__(self: BT, other: t.Mapping[KT, VT]) -> BT:
def __or__(self: BT, other: Mapping[KT, VT]) -> BT:
"""Return self|other."""
if not isinstance(other, t.Mapping):
if not isinstance(other, Mapping):
return NotImplemented
new = self.copy()
new._update(other, rollback=False)
return new

def __ror__(self: BT, other: t.Mapping[KT, VT]) -> BT:
def __ror__(self: BT, other: Mapping[KT, VT]) -> BT:
"""Return other|self."""
if not isinstance(other, t.Mapping):
if not isinstance(other, Mapping):
return NotImplemented
new = self.__class__(other)
new._update(self, rollback=False)
Expand All @@ -515,7 +523,7 @@ def __len__(self) -> int:
"""The number of contained items."""
return len(self._fwdm)

def __iter__(self) -> t.Iterator[KT]:
def __iter__(self) -> Iterator[KT]:
"""Iterator over the contained keys."""
return iter(self._fwdm)

Expand All @@ -526,7 +534,7 @@ def __getitem__(self, key: KT) -> VT:
def __reduce__(self) -> tuple[t.Any, ...]:
"""Return state information for pickling."""
cls = self.__class__
inst: t.Mapping[t.Any, t.Any] = self
inst: Mapping[t.Any, t.Any] = self
# If this bidict's class is dynamically generated, pickle the inverse instead, whose (presumably not
# dynamically generated) class the caller is more likely to have a reference to somewhere in sys.modules
# that pickle can discover.
Expand All @@ -537,9 +545,9 @@ def __reduce__(self) -> tuple[t.Any, ...]:


# See BidictBase._set_reversed() above.
def _fwdm_reversed(self: BidictBase[KT, t.Any]) -> t.Iterator[KT]:
def _fwdm_reversed(self: BidictBase[KT, t.Any]) -> Iterator[KT]:
"""Iterator over the contained keys in reverse order."""
assert isinstance(self._fwdm, t.Reversible)
assert isinstance(self._fwdm, Reversible)
return reversed(self._fwdm)


Expand Down
3 changes: 2 additions & 1 deletion bidict/_bidict.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
from __future__ import annotations

import typing as t
from collections.abc import Mapping

from ._abc import MutableBidirectionalMapping
from ._base import BidictBase
Expand Down Expand Up @@ -165,7 +166,7 @@ def putall(self, items: MapOrItems[KT, VT], on_dup: OnDup = ON_DUP_RAISE) -> Non

# other's type is Mapping rather than Maplike since bidict() |= SupportsKeysAndGetItem({})
# raises a TypeError, just like dict() |= SupportsKeysAndGetItem({}) does.
def __ior__(self, other: t.Mapping[KT, VT]) -> MutableBidict[KT, VT]:
def __ior__(self, other: Mapping[KT, VT]) -> MutableBidict[KT, VT]:
"""Return self|=other."""
self.update(other)
return self
Expand Down
3 changes: 2 additions & 1 deletion bidict/_frozen.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
from __future__ import annotations

import typing as t
from collections.abc import ItemsView

from ._base import BidictBase
from ._typing import KT
Expand All @@ -40,7 +41,7 @@ def __hash__(self) -> int:
if getattr(self, '_hash', None) is None:
# The following is like hash(frozenset(self.items()))
# but more memory efficient. See also: https://bugs.python.org/issue46684
self._hash = t.ItemsView(self)._hash()
self._hash = ItemsView(self)._hash()
return self._hash


Expand Down
3 changes: 2 additions & 1 deletion bidict/_iter.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from __future__ import annotations

import typing as t
from collections.abc import Mapping
from operator import itemgetter

from ._typing import KT
Expand All @@ -21,7 +22,7 @@

def iteritems(arg: MapOrItems[KT, VT] = (), /, **kw: VT) -> ItemsIter[KT, VT]:
"""Yield the items from *arg* and *kw* in the order given."""
if isinstance(arg, t.Mapping):
if isinstance(arg, Mapping):
yield from arg.items()
elif isinstance(arg, Maplike):
yield from ((k, arg[k]) for k in arg.keys())
Expand Down
9 changes: 5 additions & 4 deletions bidict/_orderedbase.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
from __future__ import annotations

import typing as t
from collections.abc import Iterator
from weakref import ref as weakref

from ._base import BidictBase
Expand Down Expand Up @@ -94,7 +95,7 @@ class SentinelNode(Node):
def __init__(self) -> None:
super().__init__(self, self)

def iternodes(self, *, reverse: bool = False) -> t.Iterator[Node]:
def iternodes(self, *, reverse: bool = False) -> Iterator[Node]:
"""Iterator yielding nodes in the requested order."""
attr = 'prv' if reverse else 'nxt'
node = getattr(self, attr)
Expand Down Expand Up @@ -210,15 +211,15 @@ def _write(self, newkey: KT, newval: VT, oldkey: OKT[KT], oldval: OVT[VT], unwri
if unwrites is not None:
unwrites.append((assoc, node, oldkey, newval))

def __iter__(self) -> t.Iterator[KT]:
def __iter__(self) -> Iterator[KT]:
"""Iterator over the contained keys in insertion order."""
return self._iter(reverse=False)

def __reversed__(self) -> t.Iterator[KT]:
def __reversed__(self) -> Iterator[KT]:
"""Iterator over the contained keys in reverse insertion order."""
return self._iter(reverse=True)

def _iter(self, *, reverse: bool = False) -> t.Iterator[KT]:
def _iter(self, *, reverse: bool = False) -> Iterator[KT]:
nodes = self._sntl.iternodes(reverse=reverse)
korv_by_node = self._node_by_korv.inverse
if self._bykey:
Expand Down
16 changes: 10 additions & 6 deletions bidict/_orderedbidict.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@
from __future__ import annotations

import typing as t
from collections.abc import ItemsView
from collections.abc import Iterable
from collections.abc import Iterator
from collections.abc import KeysView
from collections.abc import Set

from ._base import BidictKeysView
Expand Down Expand Up @@ -91,11 +95,11 @@ def move_to_end(self, key: KT, last: bool = True) -> None:
# which may delegate to the backing _fwdm dict, since this is a mutable ordered bidict,
# and therefore the ordering of items can get out of sync with the backing mappings
# after mutation. (Need not override values() because it delegates to .inverse.keys().)
def keys(self) -> t.KeysView[KT]:
def keys(self) -> KeysView[KT]:
"""A set-like object providing a view on the contained keys."""
return _OrderedBidictKeysView(self)

def items(self) -> t.ItemsView[KT, VT]:
def items(self) -> ItemsView[KT, VT]:
"""A set-like object providing a view on the contained items."""
return _OrderedBidictItemsView(self)

Expand All @@ -108,14 +112,14 @@ def items(self) -> t.ItemsView[KT, VT]:
class _OrderedBidictKeysView(BidictKeysView[KT]):
_mapping: OrderedBidict[KT, t.Any]

def __reversed__(self) -> t.Iterator[KT]:
def __reversed__(self) -> Iterator[KT]:
return reversed(self._mapping)


class _OrderedBidictItemsView(t.ItemsView[KT, VT]):
class _OrderedBidictItemsView(ItemsView[KT, VT]):
_mapping: OrderedBidict[KT, VT]

def __reversed__(self) -> t.Iterator[tuple[KT, VT]]:
def __reversed__(self) -> Iterator[tuple[KT, VT]]:
ob = self._mapping
for key in reversed(ob):
yield key, ob[key]
Expand All @@ -125,7 +129,7 @@ def __reversed__(self) -> t.Iterator[tuple[KT, VT]]:
# to backing dicts for the methods they inherit from collections.abc.Set. (Cannot delegate
# for __iter__ and __reversed__ since they are order-sensitive.) See also: https://bugs.python.org/issue46713
_OView = t.Union[type[_OrderedBidictKeysView[KT]], type[_OrderedBidictItemsView[KT, t.Any]]]
_setmethodnames: t.Iterable[str] = (
_setmethodnames: Iterable[str] = (
'__lt__ __le__ __gt__ __ge__ __eq__ __ne__ __sub__ __rsub__ '
'__or__ __ror__ __xor__ __rxor__ __and__ __rand__ isdisjoint'
).split()
Expand Down
8 changes: 5 additions & 3 deletions bidict/_typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
from __future__ import annotations

import typing as t
from collections.abc import Iterable
from collections.abc import Iterator
from enum import Enum


Expand All @@ -18,19 +20,19 @@
VT_co = t.TypeVar('VT_co', covariant=True)


Items = t.Iterable[tuple[KT, VT]]
Items = Iterable[tuple[KT, VT]]


@t.runtime_checkable
class Maplike(t.Protocol[KT, VT_co]):
"""Like typeshed's SupportsKeysAndGetItem, but usable at runtime."""

def keys(self) -> t.Iterable[KT]: ...
def keys(self) -> Iterable[KT]: ...
def __getitem__(self, __key: KT) -> VT_co: ...


MapOrItems = t.Union[Maplike[KT, VT], Items[KT, VT]]
ItemsIter = t.Iterator[tuple[KT, VT]]
ItemsIter = Iterator[tuple[KT, VT]]


class MissingT(Enum):
Expand Down
2 changes: 1 addition & 1 deletion docs/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@

# https://github.com/thisch/pytest-sphinx/issues/5#issuecomment-618072237
@pytest.fixture(autouse=True)
def _add_doctest_globals(doctest_namespace: t.MutableMapping[str, t.Any]) -> None:
def _add_doctest_globals(doctest_namespace: MutableMapping[str, t.Any]) -> None:
doctest_namespace['Mapping'] = Mapping
doctest_namespace['MutableMapping'] = MutableMapping
doctest_namespace['pypy'] = sys.implementation.name == 'pypy'
Expand Down
Loading

0 comments on commit e978b18

Please # to comment.