diff --git a/stdlib/@tests/test_cases/builtins/check_set.py b/stdlib/@tests/test_cases/builtins/check_set.py index 89cb8683bfe1..545177169889 100644 --- a/stdlib/@tests/test_cases/builtins/check_set.py +++ b/stdlib/@tests/test_cases/builtins/check_set.py @@ -1,3 +1,4 @@ +from collections.abc import Set as AbstractSet from typing_extensions import Literal, assert_type @@ -55,3 +56,17 @@ def test_frozenset_interface(s: frozenset[Literal["foo", "bar"]], y: frozenset[s assert_type(s & y, frozenset[Literal["foo", "bar"]]) assert_type(s | y, frozenset[str]) assert_type(s ^ y, frozenset[str]) + + +def test_xor_with_abstract_set( + s: set[Literal["foo", "bar"]], frozen: frozenset[Literal["foo", "bar"]], other: AbstractSet[str] +) -> None: + s.__xor__(other) # type: ignore + frozen.__xor__(other) # type: ignore + assert_type(other.__rxor__(s), AbstractSet[str]) + assert_type(other.__rxor__(frozen), AbstractSet[str]) + assert_type(other.__rxor__([1]), AbstractSet[str | int]) + assert_type([1] ^ other, AbstractSet[str | int]) + assert_type(("foo", "baz") ^ other, AbstractSet[str]) + assert_type(s ^ other, AbstractSet[str]) + assert_type(frozen ^ other, AbstractSet[str]) diff --git a/stdlib/builtins.pyi b/stdlib/builtins.pyi index 9c8394ced492..a871a0e57f3c 100644 --- a/stdlib/builtins.pyi +++ b/stdlib/builtins.pyi @@ -1483,10 +1483,10 @@ class set(MutableSet[_T]): @overload def __rsub__(self, value: frozenset[_S], /) -> frozenset[_S]: ... - def __xor__(self, value: AbstractSet[_S], /) -> set[_T | _S]: ... + def __xor__(self, value: set[_S] | frozenset[_S], /) -> set[_T | _S]: ... # type: ignore[override] def __ixor__(self, value: AbstractSet[_T], /) -> Self: ... # type: ignore[override,misc] - @overload + @overload # type: ignore[override] def __rxor__(self, value: set[_S], /) -> set[_T | _S]: ... @overload def __rxor__(self, value: frozenset[_S], /) -> frozenset[_T | _S]: ... @@ -1538,9 +1538,9 @@ class frozenset(AbstractSet[_T_co]): @overload def __rsub__(self, value: frozenset[_S], /) -> frozenset[_S]: ... - def __xor__(self, value: AbstractSet[_S], /) -> frozenset[_T_co | _S]: ... + def __xor__(self, value: set[_S] | frozenset[_S], /) -> frozenset[_T_co | _S]: ... # type: ignore[override] - @overload + @overload # type: ignore[override] def __rxor__(self, value: set[_S], /) -> set[_T_co | _S]: ... @overload def __rxor__(self, value: frozenset[_S], /) -> frozenset[_T_co | _S]: ... diff --git a/stdlib/multiprocessing/managers.pyi b/stdlib/multiprocessing/managers.pyi index 0f1d4e87b0dc..0727f60f1080 100644 --- a/stdlib/multiprocessing/managers.pyi +++ b/stdlib/multiprocessing/managers.pyi @@ -195,7 +195,7 @@ if sys.version_info >= (3, 14): def __rand__(self, value: AbstractSet[object], /) -> set[_T]: ... def __ror__(self, value: AbstractSet[_S], /) -> set[_T | _S]: ... # type: ignore[misc] def __rsub__(self, value: AbstractSet[_T], /) -> set[_T]: ... - def __rxor__(self, value: AbstractSet[_S], /) -> set[_T | _S]: ... # type: ignore[misc] + def __rxor__(self, value: AbstractSet[_S], /) -> set[_T | _S]: ... # type: ignore[override,misc] def __class_getitem__(cls, item: Any, /) -> GenericAlias: ... class SetProxy(_BaseSetProxy[_T]): ... diff --git a/stdlib/typing.pyi b/stdlib/typing.pyi index 198dd45feedf..b8b90a0934e5 100644 --- a/stdlib/typing.pyi +++ b/stdlib/typing.pyi @@ -744,6 +744,7 @@ class AbstractSet(Collection[_T_co]): def __or__(self, other: AbstractSet[_T], /) -> AbstractSet[_T_co | _T]: ... def __sub__(self, other: AbstractSet[Any], /) -> AbstractSet[_T_co]: ... def __xor__(self, other: AbstractSet[_T], /) -> AbstractSet[_T_co | _T]: ... + def __rxor__(self, other: Iterable[_T], /) -> AbstractSet[_T_co | _T]: ... def __eq__(self, other: object, /) -> bool: ... def isdisjoint(self, other: Iterable[Any], /) -> bool: ... diff --git a/stubs/boltons/boltons/setutils.pyi b/stubs/boltons/boltons/setutils.pyi index d94de1967fc0..9dd1edee1a73 100644 --- a/stubs/boltons/boltons/setutils.pyi +++ b/stubs/boltons/boltons/setutils.pyi @@ -39,7 +39,7 @@ class IndexedSet(MutableSet[Any]): __rand__ = intersection # __sub__ = difference # __xor__ = symmetric_difference - __rxor__ = symmetric_difference + __rxor__ = symmetric_difference # type: ignore[assignment] # pyright: ignore[reportAssignmentType] def __rsub__(self, other: _RSub[_T_co]) -> _RSub[_T_co]: ... def update(self, *others: Iterable[Any]) -> None: ... def intersection_update(self, *others: Iterable[Any]) -> None: ...