From 231d06d105fe37e80fbb8d293bf854b719832d5a Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Sun, 5 Apr 2026 21:07:32 +0100 Subject: [PATCH 1/2] typing: Fix compatibility with mypy 1.20.0 Beyond some tweaks to `type: ignore` comments, we need to disable the `warn_unused_configs = true` option to work around [1]. We also take the opportunity to drop the unnecessary `warn_unused_ignores = true` option which is already handled by `strict = true` [1] https://github.com/python/mypy/issues/21137 Signed-off-by: Stephen Finucane --- pyproject.toml | 6 ++++-- testtools/testcase.py | 4 ++-- testtools/testsuite.py | 2 +- tox.ini | 2 +- 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 67782eee..68fb18c6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -38,7 +38,7 @@ test = ["testscenarios", "testresources"] twisted = ["Twisted", "fixtures"] dev = [ "ruff==0.15.8", - "mypy>=1.0.0", + "mypy>=1.20.0", "typing-extensions;python_version<'3.11'", ] @@ -63,7 +63,9 @@ python_version = "3.10" show_column_numbers = true show_error_context = true strict = true -warn_unused_ignores = true +# remove this when 1.20.1 is released +# https://github.com/python/mypy/issues/21137 +warn_unused_configs = false # FIXME(stephenfin): We should remove this implicit_reexport = true exclude = 'doc' diff --git a/testtools/testcase.py b/testtools/testcase.py index e60ba339..746cb862 100644 --- a/testtools/testcase.py +++ b/testtools/testcase.py @@ -928,7 +928,7 @@ def _validate_setup_called(result: object) -> object: ) return result - ret.addBoth(_validate_setup_called) + ret.addBoth(_validate_setup_called) # type: ignore[attr-defined] else: # Synchronous: validate immediately if not self.__setup_called: @@ -964,7 +964,7 @@ def _validate_teardown_called(result: object) -> object: ) return result - ret.addBoth(_validate_teardown_called) + ret.addBoth(_validate_teardown_called) # type: ignore[attr-defined] else: # Synchronous: validate immediately if not self.__teardown_called: diff --git a/testtools/testsuite.py b/testtools/testsuite.py index 119624df..8dcae5cd 100644 --- a/testtools/testsuite.py +++ b/testtools/testsuite.py @@ -62,7 +62,7 @@ def iterate_tests( for test in test_suite_or_case: yield from iterate_tests(test) else: - yield test_suite_or_case # type: ignore[misc] + yield test_suite_or_case class ConcurrentTestSuite(unittest.TestSuite): diff --git a/tox.ini b/tox.ini index 6cf33bac..70e91ff5 100644 --- a/tox.ini +++ b/tox.ini @@ -19,6 +19,6 @@ commands = [testenv:mypy] deps = - mypy + mypy>=1.20.0 commands = mypy --cache-dir="{envdir}/mypy_cache" {posargs:testtools} From ec15b814161f0ffbd66f892194225f7f39d21910 Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Sun, 5 Apr 2026 00:07:57 +0100 Subject: [PATCH 2/2] typing: Make less use of ParamSpec This is a partial revert of 107864786f8a40af7984f8cc0638751a42f341e5. mypy (and possibly others) are not able to correctly resolve a ParamSpec for an overridden method. This causes a lot of false positives when using assertRaises (as a function) on methods with overrides, which cannot be resolved except through `type: ignore` statements. In addition, it's often desirable to test functions with incorrect types to assert runtime validation. Given these two issues, it's easier to just drop the use of ParamSpec. Signed-off-by: Stephen Finucane --- testtools/testcase.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/testtools/testcase.py b/testtools/testcase.py index 746cb862..bdd640a9 100644 --- a/testtools/testcase.py +++ b/testtools/testcase.py @@ -577,18 +577,18 @@ def assertIsInstance( # type: ignore[override] def assertRaises( self, expected_exception: type[_E], - callable: Callable[_P, _R], - *args: _P.args, - **kwargs: _P.kwargs, + callable: Callable[..., Any], + *args: Any, + **kwargs: Any, ) -> _E: ... @overload def assertRaises( self, expected_exception: tuple[type[BaseException], ...], - callable: Callable[_P, _R], - *args: _P.args, - **kwargs: _P.kwargs, + callable: Callable[..., Any], + *args: Any, + **kwargs: Any, ) -> BaseException: ... @overload