Skip to content

Commit 84f4099

Browse files
committed
fixing mypy's Matcher[Never]
closes: #266 #264
1 parent 65880f2 commit 84f4099

File tree

10 files changed

+2189
-589
lines changed

10 files changed

+2189
-589
lines changed

pyproject.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,3 +171,6 @@ known_third_party = ["hypothesis", "pytest", "setuptools", "six"]
171171
filename = "CHANGELOG.rst"
172172
directory = "changelog.d"
173173
issue_format = "`#{issue} <https://github.com/hamcrest/PyHamcrest/issues/{issue}>`_"
174+
175+
[dependency-groups]
176+
dev = [ "PyHamcrest[dev]" ]

src/hamcrest/core/core/allof.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from typing import Optional, TypeVar, Union
1+
from typing import Optional, TypeVar, Union, overload
22

33
from hamcrest.core.base_matcher import BaseMatcher
44
from hamcrest.core.description import Description
@@ -42,6 +42,12 @@ def describe_to(self, description: Description) -> None:
4242
description.append_list("(", " and ", ")", self.matchers)
4343

4444

45+
@overload
46+
def all_of(*items: Matcher[T]) -> Matcher[T]: ...
47+
@overload
48+
def all_of(*items: T) -> Matcher[T]: ...
49+
50+
4551
def all_of(*items: Union[Matcher[T], T]) -> Matcher[T]:
4652
"""Matches if all of the given matchers evaluate to ``True``.
4753

src/hamcrest/core/core/anyof.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from typing import TypeVar, Union
1+
from typing import TypeVar, Union, overload
22

33
from hamcrest.core.base_matcher import BaseMatcher
44
from hamcrest.core.description import Description
@@ -26,6 +26,12 @@ def describe_to(self, description: Description) -> None:
2626
description.append_list("(", " or ", ")", self.matchers)
2727

2828

29+
@overload
30+
def any_of(*items: Matcher[T]) -> Matcher[T]: ...
31+
@overload
32+
def any_of(*items: T) -> Matcher[T]: ...
33+
34+
2935
def any_of(*items: Union[Matcher[T], T]) -> Matcher[T]:
3036
"""Matches if any of the given matchers evaluate to ``True``.
3137

src/hamcrest/library/collection/isdict_containingentries.py

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from typing import Any, Hashable, Mapping, Optional, TypeVar, Union, overload
1+
from typing import Any, Hashable, Mapping, Optional, TypeVar, Union, cast, overload
22

33
from hamcrest.core.base_matcher import BaseMatcher
44
from hamcrest.core.description import Description
@@ -73,20 +73,26 @@ def describe_to(self, description: Description) -> None:
7373

7474
# Keyword argument form
7575
@overload
76-
def has_entries(**keys_valuematchers: Union[Matcher[V], V]) -> Matcher[Mapping[str, V]]: ...
76+
def has_entries(**keys_valuematchers: Matcher[V]) -> Matcher[Mapping[str, V]]: ...
77+
@overload
78+
def has_entries(**keys_valuematchers: V) -> Matcher[Mapping[str, V]]: ...
7779

7880

7981
# Key to matcher dict form
8082
@overload
81-
def has_entries(keys_valuematchers: Mapping[K, Union[Matcher[V], V]]) -> Matcher[Mapping[K, V]]: ...
83+
def has_entries(keys_valuematchers: Mapping[K, Matcher[V]], /) -> Matcher[Mapping[K, V]]: ...
84+
@overload
85+
def has_entries(keys_valuematchers: Mapping[K, V], /) -> Matcher[Mapping[K, V]]: ...
8286

8387

8488
# Alternating key/matcher form
8589
@overload
8690
def has_entries(*keys_valuematchers: Any) -> Matcher[Mapping[Any, Any]]: ...
8791

8892

89-
def has_entries(*keys_valuematchers, **kv_args):
93+
def has_entries(
94+
*keys_valuematchers: Mapping[K, Union[Matcher[V], V]], **kv_args: Union[Matcher[V], V]
95+
) -> Matcher[Mapping[K, V]]:
9096
"""Matches if dictionary contains entries satisfying a dictionary of keys
9197
and corresponding value matchers.
9298
@@ -132,11 +138,13 @@ def has_entries(*keys_valuematchers, **kv_args):
132138
has_entries('foo', 1, 'bar', 2)
133139
134140
"""
141+
base_dict: dict[K, Matcher[V]] = {}
142+
key: K
143+
value: Union[Matcher[V], V]
135144
if len(keys_valuematchers) == 1:
136145
try:
137-
base_dict = keys_valuematchers[0].copy()
138-
for key in base_dict:
139-
base_dict[key] = wrap_matcher(base_dict[key])
146+
for key, value in keys_valuematchers[0].items():
147+
base_dict[key] = wrap_matcher(value)
140148
except AttributeError:
141149
raise ValueError(
142150
"single-argument calls to has_entries must pass a dict as the argument"
@@ -146,11 +154,12 @@ def has_entries(*keys_valuematchers, **kv_args):
146154
raise ValueError("has_entries requires key-value pairs")
147155
base_dict = {}
148156
for index in range(int(len(keys_valuematchers) / 2)):
149-
base_dict[keys_valuematchers[2 * index]] = wrap_matcher(
150-
keys_valuematchers[2 * index + 1]
151-
)
157+
key = cast(K, keys_valuematchers[2 * index])
158+
value = cast(V, keys_valuematchers[2 * index + 1])
159+
base_dict[key] = wrap_matcher(value)
152160

153-
for key, value in kv_args.items():
161+
for key_name, value in kv_args.items():
162+
key = cast(K, key_name)
154163
base_dict[key] = wrap_matcher(value)
155164

156165
return IsDictContainingEntries(base_dict)

src/hamcrest/library/collection/issequence_containing.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from typing import Sequence, TypeVar, Union, cast
1+
from typing import Sequence, TypeVar, Union, cast, overload
22

33
from hamcrest.core.base_matcher import BaseMatcher
44
from hamcrest.core.core.allof import all_of
@@ -54,6 +54,12 @@ def describe_to(self, description: Description) -> None:
5454
self.matcher.describe_to(description)
5555

5656

57+
@overload
58+
def has_item(match: Matcher[T]) -> Matcher[Sequence[T]]: ...
59+
@overload
60+
def has_item(match: T) -> Matcher[Sequence[T]]: ...
61+
62+
5763
def has_item(match: Union[Matcher[T], T]) -> Matcher[Sequence[T]]:
5864
"""Matches if any element of sequence satisfies a given matcher.
5965
@@ -72,6 +78,12 @@ def has_item(match: Union[Matcher[T], T]) -> Matcher[Sequence[T]]:
7278
return IsSequenceContaining(wrap_matcher(match))
7379

7480

81+
@overload
82+
def has_items(*items: Matcher[T]) -> Matcher[Sequence[T]]: ...
83+
@overload
84+
def has_items(*items: T) -> Matcher[Sequence[T]]: ...
85+
86+
7587
def has_items(*items: Union[Matcher[T], T]) -> Matcher[Sequence[T]]:
7688
"""Matches if all of the given matchers are satisfied by any elements of
7789
the sequence.

src/hamcrest/library/collection/issequence_containinginanyorder.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from typing import MutableSequence, Optional, Sequence, TypeVar, Union, cast
1+
from typing import Generic, MutableSequence, Optional, Sequence, TypeVar, Union, cast, overload
22

33
from hamcrest.core.base_matcher import BaseMatcher
44
from hamcrest.core.description import Description
@@ -12,7 +12,7 @@
1212
T = TypeVar("T")
1313

1414

15-
class MatchInAnyOrder(object):
15+
class MatchInAnyOrder(Generic[T]):
1616
def __init__(
1717
self, matchers: Sequence[Matcher[T]], mismatch_description: Optional[Description]
1818
) -> None:
@@ -79,6 +79,12 @@ def describe_to(self, description: Description) -> None:
7979
).append_text(" in any order")
8080

8181

82+
@overload
83+
def contains_inanyorder(*items: Matcher[T]) -> Matcher[Sequence[T]]: ...
84+
@overload
85+
def contains_inanyorder(*items: T) -> Matcher[Sequence[T]]: ...
86+
87+
8288
def contains_inanyorder(*items: Union[Matcher[T], T]) -> Matcher[Sequence[T]]:
8389
"""Matches if sequences's elements, in any order, satisfy a given list of
8490
matchers.

src/hamcrest/library/collection/issequence_containinginorder.py

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import warnings
2-
from typing import Optional, Sequence, TypeVar, Union
2+
from typing import Generic, Optional, Sequence, TypeVar, Union, cast, overload
33

44
from hamcrest.core.base_matcher import BaseMatcher
55
from hamcrest.core.description import Description
@@ -13,7 +13,7 @@
1313
T = TypeVar("T")
1414

1515

16-
class MatchingInOrder(object):
16+
class MatchingInOrder(Generic[T]):
1717
def __init__(
1818
self, matchers: Sequence[Matcher[T]], mismatch_description: Optional[Description]
1919
) -> None:
@@ -78,6 +78,12 @@ def describe_to(self, description: Description) -> None:
7878
description.append_text("a sequence containing ").append_list("[", ", ", "]", self.matchers)
7979

8080

81+
@overload
82+
def contains_exactly(*items: Matcher[T]) -> Matcher[Sequence[T]]: ...
83+
@overload
84+
def contains_exactly(*items: T) -> Matcher[Sequence[T]]: ...
85+
86+
8187
def contains_exactly(*items: Union[Matcher[T], T]) -> Matcher[Sequence[T]]:
8288
"""Matches if sequence's elements satisfy a given list of matchers, in order.
8389
@@ -97,7 +103,13 @@ def contains_exactly(*items: Union[Matcher[T], T]) -> Matcher[Sequence[T]]:
97103
return IsSequenceContainingInOrder(matchers)
98104

99105

106+
@overload
107+
def contains(*items: Matcher[T]) -> Matcher[Sequence[T]]: ...
108+
@overload
109+
def contains(*items: T) -> Matcher[Sequence[T]]: ...
110+
111+
100112
def contains(*items: Union[Matcher[T], T]) -> Matcher[Sequence[T]]:
101113
"""Deprecated - use contains_exactly(*items)"""
102114
warnings.warn("deprecated - use contains_exactly(*items)", DeprecationWarning)
103-
return contains_exactly(*items)
115+
return contains_exactly(*cast(tuple[T, ...], items))

src/hamcrest/library/collection/issequence_onlycontaining.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from typing import Sequence, TypeVar, Union
1+
from typing import Sequence, TypeVar, Union, overload
22

33
from hamcrest.core.base_matcher import BaseMatcher
44
from hamcrest.core.core.anyof import any_of
@@ -35,6 +35,12 @@ def describe_to(self, description: Description) -> None:
3535
)
3636

3737

38+
@overload
39+
def only_contains(*items: Matcher[T]) -> Matcher[Sequence[T]]: ...
40+
@overload
41+
def only_contains(*items: T) -> Matcher[Sequence[T]]: ...
42+
43+
3844
def only_contains(*items: Union[Matcher[T], T]) -> Matcher[Sequence[T]]:
3945
"""Matches if each element of sequence satisfies any of the given matchers.
4046

src/hamcrest/library/object/hasproperty.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,15 @@ def __str__(self):
5959
return str(d)
6060

6161

62-
def has_property(name: str, match: Union[None, Matcher[V], V] = None) -> Matcher[object]:
62+
@overload
63+
def has_property(name: str, match: None = None) -> Matcher[object]: ...
64+
@overload
65+
def has_property(name: str, match: Matcher[object]) -> Matcher[object]: ...
66+
@overload
67+
def has_property(name: str, match: object) -> Matcher[object]: ...
68+
69+
70+
def has_property(name: str, match: Union[None, Matcher[object], object] = None) -> Matcher[object]:
6371
"""Matches if object has a property with a given name whose value satisfies
6472
a given matcher.
6573

0 commit comments

Comments
 (0)