From 76c53c34218e72ae94495da45009603356004f9b Mon Sep 17 00:00:00 2001 From: Sebastian Rittau Date: Thu, 18 Dec 2025 17:25:13 +0100 Subject: [PATCH 1/7] [assertpy] Replace or explain `Any`s Closes: #15142 --- stubs/assertpy/assertpy/assertpy.pyi | 24 ++++++++++++++---------- stubs/assertpy/assertpy/base.pyi | 9 ++++----- stubs/assertpy/assertpy/collection.pyi | 16 ++++++++++++---- stubs/assertpy/assertpy/contains.pyi | 18 ++++++++++-------- stubs/assertpy/assertpy/dict.pyi | 14 ++++++++------ stubs/assertpy/assertpy/dynamic.pyi | 2 +- stubs/assertpy/assertpy/extracting.pyi | 6 ++++-- stubs/assertpy/assertpy/file.pyi | 5 ++--- 8 files changed, 55 insertions(+), 39 deletions(-) diff --git a/stubs/assertpy/assertpy/assertpy.pyi b/stubs/assertpy/assertpy/assertpy.pyi index 3000dfd1e1e9..8fde6281d9fa 100644 --- a/stubs/assertpy/assertpy/assertpy.pyi +++ b/stubs/assertpy/assertpy/assertpy.pyi @@ -1,6 +1,6 @@ import logging from collections.abc import Callable, Generator -from typing import Any +from typing import Any, Generic, TypeVar from typing_extensions import Self from .base import BaseMixin @@ -17,11 +17,14 @@ from .numeric import NumericMixin from .snapshot import SnapshotMixin from .string import StringMixin +_T = TypeVar("_T") +_V = TypeVar("_V", default=Any) + __version__: str __tracebackhide__: bool class WarningLoggingAdapter(logging.LoggerAdapter[logging.Logger]): - def process(self, msg: str, kwargs: Any) -> tuple[str, Any]: ... + def process(self, msg: str, kwargs: _T) -> tuple[str, _T]: ... class AssertionBuilder( StringMixin, @@ -34,18 +37,19 @@ class AssertionBuilder( DynamicMixin, DictMixin, DateMixin, - ContainsMixin, - CollectionMixin, + ContainsMixin[_V], + CollectionMixin[_V], BaseMixin, + Generic[_V] ): - val: Any + val: _V description: str kind: str | None expected: BaseException | None logger: logging.Logger def __init__( self, - val: Any, + val: _V, description: str = "", kind: str | None = None, expected: BaseException | None = None, @@ -53,7 +57,7 @@ class AssertionBuilder( ) -> None: ... def builder( self, - val: Any, + val: _V, description: str = "", kind: str | None = None, expected: BaseException | None = None, @@ -61,9 +65,9 @@ class AssertionBuilder( ) -> Self: ... def error(self, msg: str) -> Self: ... -def soft_assertions() -> Generator[None, None, None]: ... -def assert_that(val: Any, description: str = "") -> AssertionBuilder: ... -def assert_warn(val: Any, description: str = "", logger: logging.Logger | None = None) -> AssertionBuilder: ... +def soft_assertions() -> Generator[None]: ... +def assert_that(val: _V, description: str = "") -> AssertionBuilder[_V]: ... +def assert_warn(val: _V, description: str = "", logger: logging.Logger | None = None) -> AssertionBuilder: ... def fail(msg: str = "") -> None: ... def soft_fail(msg: str = "") -> None: ... def add_extension(func: Callable[[AssertionBuilder], AssertionBuilder]) -> None: ... diff --git a/stubs/assertpy/assertpy/base.pyi b/stubs/assertpy/assertpy/base.pyi index 8181d33de6b8..be5db39ff985 100644 --- a/stubs/assertpy/assertpy/base.pyi +++ b/stubs/assertpy/assertpy/base.pyi @@ -1,4 +1,3 @@ -from typing import Any from typing_extensions import Self, TypeAlias __tracebackhide__: bool @@ -8,10 +7,10 @@ _IncludeIgnore: TypeAlias = str | list[str] | list[tuple[str, ...]] | None class BaseMixin: description: str def described_as(self, description: str) -> Self: ... - def is_equal_to(self, other: Any, *, include: _IncludeIgnore = None, ignore: _IncludeIgnore = None) -> Self: ... - def is_not_equal_to(self, other: Any) -> Self: ... - def is_same_as(self, other: Any) -> Self: ... - def is_not_same_as(self, other: Any) -> Self: ... + def is_equal_to(self, other: object, *, include: _IncludeIgnore = None, ignore: _IncludeIgnore = None) -> Self: ... + def is_not_equal_to(self, other: object) -> Self: ... + def is_same_as(self, other: object) -> Self: ... + def is_not_same_as(self, other: object) -> Self: ... def is_true(self) -> Self: ... def is_false(self) -> Self: ... def is_none(self) -> Self: ... diff --git a/stubs/assertpy/assertpy/collection.pyi b/stubs/assertpy/assertpy/collection.pyi index 68485dbefd32..50c84c50423f 100644 --- a/stubs/assertpy/assertpy/collection.pyi +++ b/stubs/assertpy/assertpy/collection.pyi @@ -1,11 +1,19 @@ +from _typeshed import SupportsRichComparison from collections.abc import Callable -from typing import Any +from typing import Any, Generic, Literal, TypeVar, overload from typing_extensions import Self __tracebackhide__: bool -class CollectionMixin: +_V = TypeVar("_V", default=Any) + +class CollectionMixin(Generic[_V]): def is_iterable(self) -> Self: ... def is_not_iterable(self) -> Self: ... - def is_subset_of(self, *supersets: Any) -> Self: ... - def is_sorted(self, key: Callable[[Any], Any] = ..., reverse: bool = False) -> Self: ... + def is_subset_of(self, *supersets) -> Self: ... + @overload + def is_sorted(self, key: Callable[[_V], SupportsRichComparison] = ..., reverse: Literal[False] = False) -> Self: ... + @overload + def is_sorted(self, *, reverse: Literal[True]) -> Self: ... + @overload + def is_sorted(self, key: Callable[[_V], SupportsRichComparison], reverse: Literal[True]) -> Self: ... diff --git a/stubs/assertpy/assertpy/contains.pyi b/stubs/assertpy/assertpy/contains.pyi index 2953e40c96b5..6c59d2a5f81a 100644 --- a/stubs/assertpy/assertpy/contains.pyi +++ b/stubs/assertpy/assertpy/contains.pyi @@ -1,16 +1,18 @@ -from typing import Any +from typing import Any, Generic, TypeVar from typing_extensions import Self __tracebackhide__: bool -class ContainsMixin: - def contains(self, *items: Any) -> Self: ... - def does_not_contain(self, *items: Any) -> Self: ... - def contains_only(self, *items: Any) -> Self: ... - def contains_sequence(self, *items: Any) -> Self: ... +_V = TypeVar("_V", default=Any) + +class ContainsMixin(Generic[_V]): + def contains(self, *items: object) -> Self: ... + def does_not_contain(self, *items: object) -> Self: ... + def contains_only(self, *items: object) -> Self: ... + def contains_sequence(self, *items: object) -> Self: ... def contains_duplicates(self) -> Self: ... def does_not_contain_duplicates(self) -> Self: ... def is_empty(self) -> Self: ... def is_not_empty(self) -> Self: ... - def is_in(self, *items: Any) -> Self: ... - def is_not_in(self, *items: Any) -> Self: ... + def is_in(self, *items: _V) -> Self: ... + def is_not_in(self, *items: _V) -> Self: ... diff --git a/stubs/assertpy/assertpy/dict.pyi b/stubs/assertpy/assertpy/dict.pyi index f88e86db7274..2e2a41e56d72 100644 --- a/stubs/assertpy/assertpy/dict.pyi +++ b/stubs/assertpy/assertpy/dict.pyi @@ -1,12 +1,14 @@ +from collections.abc import Iterable from typing import Any from typing_extensions import Self __tracebackhide__: bool class DictMixin: - def contains_key(self, *keys: Any) -> Self: ... - def does_not_contain_key(self, *keys: Any) -> Self: ... - def contains_value(self, *values: Any) -> Self: ... - def does_not_contain_value(self, *values: Any) -> Self: ... - def contains_entry(self, *args: Any, **kwargs: dict[str, Any]) -> Self: ... - def does_not_contain_entry(self, *args: Any, **kwargs: dict[str, Any]) -> Self: ... + def contains_key(self, *keys: object) -> Self: ... + def does_not_contain_key(self, *keys: object) -> Self: ... + def contains_value(self, *values: object) -> Self: ... + def does_not_contain_value(self, *values: object) -> Self: ... + # The dicts can contain arbitrary keys and values + def contains_entry(self, *args: Iterable[dict[Any, Any]], **kwargs: Any) -> Self: ... + def does_not_contain_entry(self, *args: Iterable[dict[Any, Any]], **kwargs: Any) -> Self: ... diff --git a/stubs/assertpy/assertpy/dynamic.pyi b/stubs/assertpy/assertpy/dynamic.pyi index 52c8c24d07cc..681512a565bb 100644 --- a/stubs/assertpy/assertpy/dynamic.pyi +++ b/stubs/assertpy/assertpy/dynamic.pyi @@ -4,4 +4,4 @@ from typing_extensions import Self __tracebackhide__: bool class DynamicMixin: - def __getattr__(self, attr: str) -> Callable[..., Self]: ... + def __getattr__(self, attr: str) -> Callable[[object], Self]: ... diff --git a/stubs/assertpy/assertpy/extracting.pyi b/stubs/assertpy/assertpy/extracting.pyi index f2ae1f16e905..00e82fb26beb 100644 --- a/stubs/assertpy/assertpy/extracting.pyi +++ b/stubs/assertpy/assertpy/extracting.pyi @@ -1,4 +1,5 @@ -from collections.abc import Callable, Iterable as _Iterable, Mapping +from _typeshed import SupportsRichComparison +from collections.abc import Callable, Iterable, Mapping from typing import Any from typing_extensions import Self @@ -8,6 +9,7 @@ class ExtractingMixin: def extracting( self, *names: str, + # The callable must accept the type of the items in the self.val collection. filter: str | Mapping[str, Any] | Callable[[Any], bool] = ..., - sort: str | _Iterable[str] | Callable[[Any], Any] = ..., + sort: str | Iterable[str] | Callable[[Any], SupportsRichComparison] = ..., ) -> Self: ... diff --git a/stubs/assertpy/assertpy/file.pyi b/stubs/assertpy/assertpy/file.pyi index 1bff54a1ae9a..0bcf39525677 100644 --- a/stubs/assertpy/assertpy/file.pyi +++ b/stubs/assertpy/assertpy/file.pyi @@ -1,10 +1,9 @@ -from _typeshed import StrPath -from typing import IO, AnyStr +from _typeshed import StrPath, SupportsRead from typing_extensions import Self __tracebackhide__: bool -def contents_of(file: IO[AnyStr] | StrPath, encoding: str = "utf-8") -> str: ... +def contents_of(file: SupportsRead[str] | StrPath, encoding: str = "utf-8") -> str: ... class FileMixin: def exists(self) -> Self: ... From 812a76f3547b029f151265316cadfd2cc033c6b0 Mon Sep 17 00:00:00 2001 From: Sebastian Rittau Date: Thu, 18 Dec 2025 17:27:40 +0100 Subject: [PATCH 2/7] Add an allowlist item --- stubs/assertpy/@tests/stubtest_allowlist.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/stubs/assertpy/@tests/stubtest_allowlist.txt b/stubs/assertpy/@tests/stubtest_allowlist.txt index 57fe5e2ee114..79c0089b0015 100644 --- a/stubs/assertpy/@tests/stubtest_allowlist.txt +++ b/stubs/assertpy/@tests/stubtest_allowlist.txt @@ -1,5 +1,6 @@ # Python 2 compatibility cruft: assertpy.collection.Iterable +assertpy.collection.Iterable.__class_getitem__ assertpy.contains.str_types assertpy.contains.xrange assertpy.dynamic.Iterable From 058895120a329f0b1a19653e24db5e19b78e786c Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 18 Dec 2025 16:28:22 +0000 Subject: [PATCH 3/7] [pre-commit.ci] auto fixes from pre-commit.com hooks --- stubs/assertpy/assertpy/assertpy.pyi | 2 +- stubs/assertpy/assertpy/dict.pyi | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/stubs/assertpy/assertpy/assertpy.pyi b/stubs/assertpy/assertpy/assertpy.pyi index 8fde6281d9fa..e911ae88316b 100644 --- a/stubs/assertpy/assertpy/assertpy.pyi +++ b/stubs/assertpy/assertpy/assertpy.pyi @@ -40,7 +40,7 @@ class AssertionBuilder( ContainsMixin[_V], CollectionMixin[_V], BaseMixin, - Generic[_V] + Generic[_V], ): val: _V description: str diff --git a/stubs/assertpy/assertpy/dict.pyi b/stubs/assertpy/assertpy/dict.pyi index 2e2a41e56d72..0f04642291e1 100644 --- a/stubs/assertpy/assertpy/dict.pyi +++ b/stubs/assertpy/assertpy/dict.pyi @@ -10,5 +10,5 @@ class DictMixin: def contains_value(self, *values: object) -> Self: ... def does_not_contain_value(self, *values: object) -> Self: ... # The dicts can contain arbitrary keys and values - def contains_entry(self, *args: Iterable[dict[Any, Any]], **kwargs: Any) -> Self: ... - def does_not_contain_entry(self, *args: Iterable[dict[Any, Any]], **kwargs: Any) -> Self: ... + def contains_entry(self, *args: Iterable[dict[Any, Any]], **kwargs: Any) -> Self: ... + def does_not_contain_entry(self, *args: Iterable[dict[Any, Any]], **kwargs: Any) -> Self: ... From 11a8aec149ccf33e00ff1409500328346759b602 Mon Sep 17 00:00:00 2001 From: Sebastian Rittau Date: Thu, 18 Dec 2025 17:28:48 +0100 Subject: [PATCH 4/7] Annotate supersets --- stubs/assertpy/assertpy/collection.pyi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stubs/assertpy/assertpy/collection.pyi b/stubs/assertpy/assertpy/collection.pyi index 50c84c50423f..9f6d22bc98bd 100644 --- a/stubs/assertpy/assertpy/collection.pyi +++ b/stubs/assertpy/assertpy/collection.pyi @@ -10,7 +10,7 @@ _V = TypeVar("_V", default=Any) class CollectionMixin(Generic[_V]): def is_iterable(self) -> Self: ... def is_not_iterable(self) -> Self: ... - def is_subset_of(self, *supersets) -> Self: ... + def is_subset_of(self, *supersets: _V) -> Self: ... @overload def is_sorted(self, key: Callable[[_V], SupportsRichComparison] = ..., reverse: Literal[False] = False) -> Self: ... @overload From 38737e9d211b389cfc7c8bd82b8349e5ee90568e Mon Sep 17 00:00:00 2001 From: Sebastian Rittau Date: Thu, 18 Dec 2025 17:37:42 +0100 Subject: [PATCH 5/7] Remove redundant Generic --- stubs/assertpy/assertpy/assertpy.pyi | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/stubs/assertpy/assertpy/assertpy.pyi b/stubs/assertpy/assertpy/assertpy.pyi index e911ae88316b..5366825bcbd2 100644 --- a/stubs/assertpy/assertpy/assertpy.pyi +++ b/stubs/assertpy/assertpy/assertpy.pyi @@ -1,6 +1,6 @@ import logging from collections.abc import Callable, Generator -from typing import Any, Generic, TypeVar +from typing import Any, TypeVar from typing_extensions import Self from .base import BaseMixin @@ -40,7 +40,6 @@ class AssertionBuilder( ContainsMixin[_V], CollectionMixin[_V], BaseMixin, - Generic[_V], ): val: _V description: str From 7a56fd16202a9028cbe98473900ecd348371f1e3 Mon Sep 17 00:00:00 2001 From: Sebastian Rittau Date: Thu, 18 Dec 2025 17:40:19 +0100 Subject: [PATCH 6/7] Update allowlist --- stubs/assertpy/@tests/stubtest_allowlist.txt | 3 --- 1 file changed, 3 deletions(-) diff --git a/stubs/assertpy/@tests/stubtest_allowlist.txt b/stubs/assertpy/@tests/stubtest_allowlist.txt index 79c0089b0015..072bd1d6e209 100644 --- a/stubs/assertpy/@tests/stubtest_allowlist.txt +++ b/stubs/assertpy/@tests/stubtest_allowlist.txt @@ -1,11 +1,8 @@ # Python 2 compatibility cruft: -assertpy.collection.Iterable -assertpy.collection.Iterable.__class_getitem__ assertpy.contains.str_types assertpy.contains.xrange assertpy.dynamic.Iterable assertpy.exception.Iterable -assertpy.extracting.Iterable assertpy.extracting.str_types assertpy.file.str_types assertpy.helpers.Iterable From 7c18139db3149c00d2a06f03f4d898b2164ab41f Mon Sep 17 00:00:00 2001 From: Sebastian Rittau Date: Thu, 18 Dec 2025 17:44:46 +0100 Subject: [PATCH 7/7] Use a regexp in allowlist --- stubs/assertpy/@tests/stubtest_allowlist.txt | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/stubs/assertpy/@tests/stubtest_allowlist.txt b/stubs/assertpy/@tests/stubtest_allowlist.txt index 072bd1d6e209..47dccabd33c1 100644 --- a/stubs/assertpy/@tests/stubtest_allowlist.txt +++ b/stubs/assertpy/@tests/stubtest_allowlist.txt @@ -1,10 +1,7 @@ # Python 2 compatibility cruft: +assertpy\..+\.Iterable(\.__class_getitem__)? assertpy.contains.str_types assertpy.contains.xrange -assertpy.dynamic.Iterable -assertpy.exception.Iterable assertpy.extracting.str_types assertpy.file.str_types -assertpy.helpers.Iterable -assertpy.string.Iterable assertpy.string.str_types