From 71a34c63a15d902da05374a8fc0cbc0f9e35c462 Mon Sep 17 00:00:00 2001 From: Matthias Diener Date: Tue, 21 Jan 2025 16:08:31 -0600 Subject: [PATCH 1/6] Simplify and update --- doc/api.rst | 40 ++++----- orderedsets/__init__.py | 178 +++++++++------------------------------ test/test_orderedsets.py | 15 ++++ 3 files changed, 77 insertions(+), 156 deletions(-) diff --git a/doc/api.rst b/doc/api.rst index 123cf6c..7fbd883 100644 --- a/doc/api.rst +++ b/doc/api.rst @@ -2,25 +2,25 @@ General Set API =============== -From the `Python documentation `__. +From the `Python documentation `__. -+------------------------------------------------+----------------+-------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| Class | Inherits from | Abstract methods | Mixin methods | -+================================================+================+===================================================================+===========================================================================================================================================================================================================================================================================================================+ -| ``collections.abc.Set`` | ``Collection`` | ``__contains__``, ``__iter__``, ``__len__`` | ``__le__``, ``__lt__``, ``__eq__``, ``__ne__``, ``__gt__``, ``__ge__``, ``__and__``, ``__or__``, ``__sub__``, ``__xor__``, and ``isdisjoint`` | -+------------------------------------------------+----------------+-------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``collections.abc.MutableSet`` | ``Set`` | ``__contains__``, ``__iter__``, ``__len__``, ``add``, ``discard`` | Inherited ``Set`` methods and ``clear``, ``pop``, ``remove``, ``__ior__``, ``__iand__``, ``__ixor__``, and ``__isub__`` | -+------------------------------------------------+----------------+-------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``set`` (builtin) | --- | | ``MutableSet`` methods and ``__rand__``, ``__ror__``, ``__rsub__``, ``__rxor__``, ``copy``, ``difference``, ``difference_update``, ``discard``, ``intersection``, ``intersection_update``, ``issubset``, ``issuperset``, ``symmetric_difference``, ``symmetric_difference_update``, ``union``, ``update`` | -+------------------------------------------------+----------------+-------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``frozenset`` (builtin) | --- | | ``Set`` methods and ``__rand__``, ``__ror__``, ``__rsub__``, ``__rxor__``, ``copy``, ``difference``, ``intersection``, ``symmetric_difference``, ``union`` | -+------------------------------------------------+----------------+-------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``typing.AbstractSet`` (deprecated since 3.9) | | | | -+------------------------------------------------+----------------+-------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``typing.Set`` (deprecated since 3.9) | | | | -+------------------------------------------------+----------------+-------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``typing.MutableSet`` (deprecated since 3.9) | | | | -+------------------------------------------------+----------------+-------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ``typing.FrozenSet`` (deprecated since 3.9) | | | | -+------------------------------------------------+----------------+-------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ ++----------------------------------------------------------+----------------------------------------------+-------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Class | Inherits from | Abstract methods | Mixin methods | ++==========================================================+==============================================+===================================================================+================================================================================================================================================================================================================================================================================================================================+ +| :class:`collections.abc.Set` | :class:`collections.abc.Collection` | ``__contains__``, ``__iter__``, ``__len__`` | ``__le__``, ``__lt__``, ``__eq__``, ``__ne__``, ``__gt__``, ``__ge__``, ``__and__``, ``__or__``, ``__sub__``, ``__xor__``, and ``isdisjoint`` | ++----------------------------------------------------------+----------------------------------------------+-------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| :class:`collections.abc.MutableSet` | :class:`collections.abc.Set` | ``__contains__``, ``__iter__``, ``__len__``, ``add``, ``discard`` | Inherited ``Set`` methods and ``clear``, ``pop``, ``remove``, ``__ior__``, ``__iand__``, ``__ixor__``, and ``__isub__`` | ++----------------------------------------------------------+----------------------------------------------+-------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| :class:`set` | --- | | :class:`collections.abc.MutableSet` methods and ``__rand__``, ``__ror__``, ``__rsub__``, ``__rxor__``, ``copy``, ``difference``, ``difference_update``, ``discard``, ``intersection``, ``intersection_update``, ``issubset``, ``issuperset``, ``symmetric_difference``, ``symmetric_difference_update``, ``union``, ``update`` | ++----------------------------------------------------------+----------------------------------------------+-------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| :class:`frozenset` | --- | | :class:`collections.abc.Set` methods and ``__rand__``, ``__ror__``, ``__rsub__``, ``__rxor__``, ``copy``, ``difference``, ``intersection``, ``symmetric_difference``, ``union`` | ++----------------------------------------------------------+----------------------------------------------+-------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| :class:`typing.AbstractSet` (deprecated since 3.9) | equal to :class:`collections.abc.Set` | | | ++----------------------------------------------------------+----------------------------------------------+-------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| :class:`typing.Set` (deprecated since 3.9) | equal to :class:`set` | | | ++----------------------------------------------------------+----------------------------------------------+-------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| :class:`typing.MutableSet` (deprecated since 3.9) | equal to :class:`collections.abc.MutableSet` | | | ++----------------------------------------------------------+----------------------------------------------+-------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| :class:`typing.FrozenSet` (deprecated since 3.9) | equal to :class:`frozenset` | | | ++----------------------------------------------------------+----------------------------------------------+-------------------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ diff --git a/orderedsets/__init__.py b/orderedsets/__init__.py index d4257a1..cfd8e5a 100644 --- a/orderedsets/__init__.py +++ b/orderedsets/__init__.py @@ -35,8 +35,8 @@ __version__ = importlib_metadata.version(__package__ or __name__) -from collections.abc import Iterable, Iterator, Set -from typing import AbstractSet, Any, Hashable, TypeVar +from collections.abc import Iterable, Iterator, MutableSet, Set +from typing import Any, Hashable, TypeVar T = TypeVar("T", bound=Hashable) T_cov = TypeVar("T_cov", covariant=True, bound=Hashable) @@ -46,13 +46,12 @@ class _NotProvided: pass -class OrderedSet(AbstractSet[T]): +class OrderedSet(MutableSet[T]): """A set class that preserves insertion order. - It can be used as a drop-in replacement for :class:`set` where ordering is - desired. + It implements the same API as :class:`set` and can be used as a drop-in + replacement for that class when ordering is desired. """ - def __init__(self, items: Iterable[T] | type[_NotProvided] = _NotProvided)\ -> None: """Create a new :class:`OrderedSet`, optionally initialized with *items*.""" @@ -63,17 +62,12 @@ def __init__(self, items: Iterable[T] | type[_NotProvided] = _NotProvided)\ # mypy thinks 'items' can still be Type[_NotProvided] here. self._dict = dict.fromkeys(items) # type: ignore[arg-type] - def __eq__(self, other: object) -> bool: - """Return whether this set is equal to *other*.""" - return (isinstance(other, Set) - and len(self) == len(other) - and all(i in other for i in self)) - def __repr__(self) -> str: """Return a string representation of this set.""" + cls_name = self.__class__.__name__ if len(self) == 0: - return "OrderedSet()" - return "OrderedSet({" + ", ".join([repr(k) for k in self._dict]) + "})" + return f"{cls_name}()" + return f"{cls_name}({{" + ", ".join([repr(k) for k in self._dict]) + "})" def add(self, element: T) -> None: """Add *element* to this set.""" @@ -85,15 +79,15 @@ def clear(self) -> None: def copy(self) -> OrderedSet[T]: """Return a shallow copy of this set.""" - return OrderedSet(self._dict.copy()) + return self.__class__(self._dict.copy()) def difference(self, *others: Iterable[T]) -> OrderedSet[T]: """Return all elements that are in this set but not in *others*.""" if not others: - return OrderedSet(self._dict) + return self.__class__(self._dict) other_elems = set.union(*map(set, others)) items = [item for item in self._dict if item not in other_elems] - return OrderedSet(items) + return self.__class__(items) def difference_update(self, *others: Iterable[T]) -> None: """Update this set to remove all items that are in *others*.""" @@ -111,12 +105,12 @@ def discard(self, element: T) -> None: def intersection(self, *others: Iterable[T]) -> OrderedSet[T]: """Return a new set with elements common to this set and all *others*.""" if not others: - return OrderedSet(self._dict) + return self.__class__(self._dict) oth = set(self).intersection(*others) result_elements = [element for element in self._dict if element in oth] - return OrderedSet(result_elements) + return self.__class__(result_elements) def intersection_update(self, *others: Iterable[T]) -> None: """Update this set to be the intersection of itself and *others*.""" @@ -129,10 +123,6 @@ def intersection_update(self, *others: Iterable[T]) -> None: self._dict = dict.fromkeys(common_keys) - def isdisjoint(self, s: Iterable[T]) -> bool: - """Return whether this set is disjoint with *s*.""" - return self._dict.keys().isdisjoint(s) - def issubset(self, s: Iterable[T]) -> bool: """Return whether this set is a subset of *s*.""" return all(i in s for i in self) @@ -151,7 +141,7 @@ def remove(self, element: T) -> None: def symmetric_difference(self, s: Iterable[T]) -> OrderedSet[T]: """Return the symmetric difference of this set and *s*.""" - return OrderedSet( + return self.__class__( dict.fromkeys([e for e in self._dict if e not in s] + [e for e in s if e not in self._dict])) @@ -161,7 +151,7 @@ def symmetric_difference_update(self, s: Iterable[T]) -> None: def union(self, *others: Iterable[T]) -> OrderedSet[T]: """Return a new set with elements from this set and *others*.""" - return OrderedSet(list(self._dict) + return self.__class__(list(self._dict) + [e for other in others for e in other]) def update(self, *others: Iterable[T]) -> None: @@ -220,42 +210,17 @@ def __ixor__(self, s: Set[Any]) -> OrderedSet[T]: self._dict = result._dict return result - def __le__(self, s: Set[T]) -> bool: - """Return whether this set is a subset of *s*.""" - return self.issubset(s) - - def __lt__(self, s: Set[T]) -> bool: - """Return whether this set is a proper subset of *s*.""" - return len(self) < len(s) and self.issubset(s) - - def __ge__(self, s: Set[T]) -> bool: - """Return whether this set is a superset of *s*.""" - return set(self) >= set(s) - - def __gt__(self, s: Set[T]) -> bool: - """Return whether this set is a proper superset of *s*.""" - return len(self) > len(s) and set(self) > set(s) - -class FrozenOrderedSet(AbstractSet[T_cov]): +class FrozenOrderedSet(Set[T_cov]): """A frozen set class that preserves insertion order. - It can be used as a drop-in replacement for :class:`frozenset` where - ordering is desired. + It implements the same API as :class:`frozenset` and can be used as a + drop-in replacement for that class when ordering is desired. """ + _dict: dict[T_cov, None] + _my_hash: int | None = None - def __init__(self, items: Iterable[T_cov] | type[_NotProvided] = _NotProvided)\ - -> None: - """Create a new :class:`FrozenOrderedSet`, optionally initialized \ - with *items*.""" - if items is _NotProvided: - self._dict = {} - else: - # type-ignore-reason: - # mypy thinks 'items' can still be Type[_NotProvided] here. - self._dict = dict.fromkeys(items) # type: ignore[arg-type] - - self._my_hash: int | None = None + __init__ = OrderedSet.__init__ def __reduce__(self) -> tuple[Any, ...]: """Return pickling information for this set.""" @@ -266,94 +231,35 @@ def __reduce__(self) -> tuple[Any, ...]: return (self.__class__, (self._dict,)) def __hash__(self) -> int: - """Return a hash of this set.""" + """Return a hash of this set. The hash has the same value as a + :class:`frozenset` with the same elements, and it is cached after the + first call.""" if self._my_hash is not None: return self._my_hash + # This needs to use the same hashing algorithm as frozenset. + # Converting to a frozenset is the safest and fastest way to do that. self._my_hash = hash(frozenset(self)) return self._my_hash - def __eq__(self, other: object) -> bool: - """Return whether this set is equal to *other*.""" - return (isinstance(other, Set) - and len(self) == len(other) - and all(i in other for i in self)) - - def __repr__(self) -> str: - """Return a string representation of this set.""" - if len(self) == 0: - return "FrozenOrderedSet()" - return "FrozenOrderedSet({" + ", ".join([repr(k) for k in self._dict]) + "})" + __repr__ = OrderedSet.__repr__ + __len__ = OrderedSet.__len__ + __contains__ = OrderedSet.__contains__ + __iter__ = OrderedSet.__iter__ - def __len__(self) -> int: - """Return the number of elements in this set.""" - return len(self._dict) + __eq__ = Set.__eq__ # needed for mypy - def __contains__(self, o: object) -> bool: - """Return whether *o* is in this set.""" - return o in self._dict + copy = OrderedSet.copy - def __iter__(self) -> Iterator[T_cov]: - """Return an iterator over the elements of this set.""" - return iter(self._dict) + difference = OrderedSet.difference + intersection = OrderedSet.intersection + symmetric_difference = OrderedSet.symmetric_difference - def copy(self) -> FrozenOrderedSet[T_cov]: - """Return a shallow copy of this set.""" - return FrozenOrderedSet(self._dict) + issubset = OrderedSet.issubset + issuperset = OrderedSet.issuperset + union = OrderedSet.union - def difference(self, *others: Iterable[T_cov]) -> FrozenOrderedSet[T_cov]: - """Return the difference of this set and *others*.""" - if not others: - return FrozenOrderedSet(self._dict) - other_elems = set.union(*map(set, others)) - items = [item for item in self._dict if item not in other_elems] - return FrozenOrderedSet(items) - - def intersection(self, *others: Iterable[T_cov]) -> FrozenOrderedSet[T_cov]: - """Return the intersection of this set and *others*.""" - if not others: - return FrozenOrderedSet(self._dict) - - oth = set(self).intersection(*others) - result_elements = [element for element in self._dict if element in oth] - - return FrozenOrderedSet(result_elements) - - def symmetric_difference(self, s: Iterable[T_cov]) -> FrozenOrderedSet[T_cov]: - """Return the symmetric difference of this set and *s*.""" - return FrozenOrderedSet( - dict.fromkeys([e for e in self._dict if e not in s] - + [e for e in s if e not in self._dict])) - - def isdisjoint(self, s: Iterable[T_cov]) -> bool: - """Return whether this set is disjoint with *s*.""" - return self._dict.keys().isdisjoint(s) # pylint: disable=no-member - - def issubset(self, s: Iterable[T_cov]) -> bool: - """Return whether this set is a subset of *s*.""" - return all(i in s for i in self) - - def issuperset(self, s: Iterable[T_cov]) -> bool: - """Return whether this set is a superset of *s*.""" - return set(self).issuperset(set(s)) - - def union(self, *others: Iterable[T_cov]) -> FrozenOrderedSet[T_cov]: - """Return the union of this set and *others*.""" - return FrozenOrderedSet(list(self._dict) - + [e for other in others for e in other]) - - def __and__(self, s: Set[T_cov]) -> FrozenOrderedSet[T_cov]: - """Return the intersection of this set and *s*.""" - return self.intersection(s) - - def __or__(self, s: Set[Any]) -> FrozenOrderedSet[T_cov]: - """Return the union of this set and *s*.""" - return self.union(s) - - def __sub__(self, s: Set[T_cov]) -> FrozenOrderedSet[T_cov]: - """Return the difference of this set and *s*.""" - return self.difference(s) - - def __xor__(self, s: Set[Any]) -> FrozenOrderedSet[T_cov]: - """Return the symmetric difference of this set and *s*.""" - return self.symmetric_difference(s) + __and__ = OrderedSet.__and__ + __or__ = OrderedSet.__or__ + __sub__ = OrderedSet.__sub__ + __xor__ = OrderedSet.__xor__ diff --git a/test/test_orderedsets.py b/test/test_orderedsets.py index 9915068..993cf3b 100644 --- a/test/test_orderedsets.py +++ b/test/test_orderedsets.py @@ -217,6 +217,7 @@ def test_remove_discard_mutable(cls: T_mutable_set[str]) -> None: s.remove("d") assert s == {"a"} + assert isinstance(s, cls) @all_immutable_set_types @@ -235,11 +236,13 @@ def test_clear_mutable(cls: T_mutable_set[str]) -> None: assert len(s) == 0 assert s == cls() + assert isinstance(s, cls) @all_set_types def test_convert_to_set(cls: T_set[int]) -> None: assert {1, 2, 3} == set(cls([3, 1, 2])) + assert {1, 2, 3} == frozenset(cls([3, 1, 2])) @all_ordered_set_types @@ -305,6 +308,7 @@ def test_update_mutable(cls: T_mutable_set[Any]) -> None: assert len(s) == 3 assert s == {"a", "f", "h"} + assert isinstance(s, cls) @all_set_types @@ -314,6 +318,7 @@ def test_intersection(cls: T_set[str]) -> None: assert cls(["a"]) == s1.intersection(s2) assert s1 == s1.intersection(s1) assert cls(["a", "b"]) == s1.intersection(["a", "b"]) + assert isinstance(s1.intersection(["b", "c"]), cls) if cls in ordered_set_types: assert list(s1.intersection(["a", "b", "c"])) == ["c", "a", "b"] @@ -363,6 +368,7 @@ def test_intersection_update_mutable(cls: T_mutable_set[str]) -> None: s3.intersection_update(["b", "a"]) s3.intersection_update({"b", "a"}) assert list(s3) == ["a", "b"] + assert isinstance(s3, cls) @all_immutable_set_types @@ -382,12 +388,15 @@ def test_add_mutable(cls: T_mutable_set[str]) -> None: if cls in ordered_set_types: assert list(s) == ["c", "a", "b", "z"] + assert isinstance(s, cls) + @all_set_types def test_copy(cls: T_set[str]) -> None: s1 = cls(["c", "a", "b"]) s2 = s1.copy() assert s1 == s2 + assert type(s1) is type(s2) if not isinstance(s1, frozenset): assert s1 is not s2 @@ -776,14 +785,20 @@ def test_ordering(cls: T_set[int]) -> None: @all_ordered_set_types def test_isinstance(cls: T_ordered_set[int]) -> None: + from collections.abc import MutableSet as abc_MutableSet + from collections.abc import Set as abc_Set assert isinstance(cls(), AbstractSet) assert not isinstance(cls(), Set) assert not isinstance(cls(), set) assert not isinstance(cls(), frozenset) + assert isinstance(cls(), abc_Set) + if cls in mutable_set_types: assert isinstance(cls(), OrderedSet) assert not isinstance(cls(), FrozenOrderedSet) + assert isinstance(cls(), abc_MutableSet) else: assert not isinstance(cls(), OrderedSet) assert isinstance(cls(), FrozenOrderedSet) + assert not isinstance(cls(), abc_MutableSet) From 71baa886a651ca36083104330282f85ebe2df81e Mon Sep 17 00:00:00 2001 From: Matthias Diener Date: Wed, 22 Jan 2025 12:07:56 -0600 Subject: [PATCH 2/6] add another reference --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index a0c1494..8164a13 100644 --- a/README.md +++ b/README.md @@ -59,6 +59,7 @@ Please also see the [documentation](https://matthiasdiener.github.io/orderedsets - https://pypi.org/project/stableset/ (no frozen/immutable class) - https://pypi.org/project/orderedset/ (Cython, no frozen/immutable class) - https://pypi.org/project/Ordered-set-37/ (no frozen/immutable class) +- https://github.com/grantjenks/python-sortedcollections (no frozen/immutable class) ### Discussions From 2407379d9bf52824f68386810c65048bcf9d980c Mon Sep 17 00:00:00 2001 From: Matthias Diener Date: Wed, 22 Jan 2025 12:09:05 -0600 Subject: [PATCH 3/6] pydocstyle --- orderedsets/__init__.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/orderedsets/__init__.py b/orderedsets/__init__.py index b7ceafc..5e392ec 100644 --- a/orderedsets/__init__.py +++ b/orderedsets/__init__.py @@ -52,6 +52,7 @@ class OrderedSet(MutableSet[T]): It implements the same API as :class:`set` and can be used as a drop-in replacement for that class when ordering is desired. """ + def __init__(self, items: Iterable[T] | type[_NotProvided] = _NotProvided)\ -> None: """Create a new :class:`OrderedSet`, optionally initialized with *items*.""" @@ -217,6 +218,7 @@ class FrozenOrderedSet(Set[T_cov]): It implements the same API as :class:`frozenset` and can be used as a drop-in replacement for that class when ordering is desired. """ + _dict: dict[T_cov, None] _my_hash: int | None = None From e351206664efcc3590bc5540bdc71574fc7388fb Mon Sep 17 00:00:00 2001 From: Matthias Diener Date: Wed, 22 Jan 2025 12:15:30 -0600 Subject: [PATCH 4/6] use typing for <3.9 --- orderedsets/__init__.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/orderedsets/__init__.py b/orderedsets/__init__.py index 5e392ec..90ee89f 100644 --- a/orderedsets/__init__.py +++ b/orderedsets/__init__.py @@ -35,9 +35,17 @@ __version__ = importlib_metadata.version(__package__ or __name__) -from collections.abc import Iterable, Iterator, MutableSet, Set +import sys +from collections.abc import Iterable, Iterator from typing import Any, Hashable, TypeVar +if sys.version_info < (3, 9): + from typing import AbstractSet as Set + from typing import Set as MutableSet +else: + from collections.abc import MutableSet, Set + + T = TypeVar("T", bound=Hashable) T_cov = TypeVar("T_cov", covariant=True, bound=Hashable) From b60fe2ef970ed34c77b7e6ecf8e2a97c461d6809 Mon Sep 17 00:00:00 2001 From: Matthias Diener Date: Wed, 22 Jan 2025 12:20:23 -0600 Subject: [PATCH 5/6] coverage --- orderedsets/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/orderedsets/__init__.py b/orderedsets/__init__.py index 90ee89f..707707f 100644 --- a/orderedsets/__init__.py +++ b/orderedsets/__init__.py @@ -39,7 +39,7 @@ from collections.abc import Iterable, Iterator from typing import Any, Hashable, TypeVar -if sys.version_info < (3, 9): +if sys.version_info < (3, 9): # pragma: no cover from typing import AbstractSet as Set from typing import Set as MutableSet else: From 4173572c4ea3598b56ee4c5ea3fd94372d829ee1 Mon Sep 17 00:00:00 2001 From: Matthias Diener Date: Wed, 22 Jan 2025 12:40:27 -0600 Subject: [PATCH 6/6] <3.9 fixes --- orderedsets/__init__.py | 7 ++++--- test/test_orderedsets.py | 4 +++- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/orderedsets/__init__.py b/orderedsets/__init__.py index 707707f..5b7be72 100644 --- a/orderedsets/__init__.py +++ b/orderedsets/__init__.py @@ -39,9 +39,9 @@ from collections.abc import Iterable, Iterator from typing import Any, Hashable, TypeVar -if sys.version_info < (3, 9): # pragma: no cover +if sys.version_info < (3, 9): # pragma: no cover + from typing import AbstractSet as MutableSet from typing import AbstractSet as Set - from typing import Set as MutableSet else: from collections.abc import MutableSet, Set @@ -259,7 +259,8 @@ def __hash__(self) -> int: __contains__ = OrderedSet.__contains__ __iter__ = OrderedSet.__iter__ - __eq__ = Set.__eq__ # needed for mypy + if sys.version_info >= (3, 9): + __eq__ = Set.__eq__ # needed for mypy copy = OrderedSet.copy diff --git a/test/test_orderedsets.py b/test/test_orderedsets.py index 993cf3b..80fb22d 100644 --- a/test/test_orderedsets.py +++ b/test/test_orderedsets.py @@ -797,7 +797,9 @@ def test_isinstance(cls: T_ordered_set[int]) -> None: if cls in mutable_set_types: assert isinstance(cls(), OrderedSet) assert not isinstance(cls(), FrozenOrderedSet) - assert isinstance(cls(), abc_MutableSet) + import sys + if sys.version_info >= (3, 9): + assert isinstance(cls(), abc_MutableSet) else: assert not isinstance(cls(), OrderedSet) assert isinstance(cls(), FrozenOrderedSet)