From 7406d4222f1d105cf9f3c2b2b36d0700658148d1 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Sun, 26 Jan 2025 19:41:15 +0000 Subject: [PATCH] Move mypy test module exclusions to per-module ignores (#13265) --- pyproject.toml | 121 ++++++++++-------- tests/test_config/test_config.py | 4 +- tests/test_extensions/test_ext_autodoc.py | 2 +- .../test_ext_autodoc_events.py | 2 +- tests/test_extensions/test_ext_autosummary.py | 4 +- tests/test_extensions/test_ext_doctest.py | 2 +- .../test_ext_inheritance_diagram.py | 2 +- tests/test_extensions/test_ext_intersphinx.py | 2 +- tests/test_intl/test_intl.py | 4 +- tests/test_search.py | 8 +- .../test_transforms_post_transforms.py | 4 +- tests/test_util/test_util_inspect.py | 2 +- tests/test_util/test_util_typing.py | 50 ++++---- 13 files changed, 113 insertions(+), 94 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 14235cf981e..8f13f78706c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -146,59 +146,6 @@ files = [ ] exclude = [ "tests/roots", - # tests/ - "^tests/test_quickstart\\.py$", - "^tests/test_search\\.py$", - # tests/test_builders - "^tests/test_builders/test_build_epub\\.py$", - "^tests/test_builders/test_build_gettext\\.py$", - "^tests/test_builders/test_build_latex\\.py$", - "^tests/test_builders/test_build_texinfo\\.py$", - # tests/test_config - "^tests/test_config/test_config\\.py$", - # tests/test_directives - "^tests/test_directives/test_directive_only\\.py$", - "^tests/test_directives/test_directive_other\\.py$", - "^tests/test_directives/test_directive_patch\\.py$", - # tests/test_domains - "^tests/test_domains/test_domain_c\\.py$", - "^tests/test_domains/test_domain_cpp\\.py$", - "^tests/test_domains/test_domain_js\\.py$", - "^tests/test_domains/test_domain_py\\.py$", - "^tests/test_domains/test_domain_py_fields\\.py$", - "^tests/test_domains/test_domain_py_pyfunction\\.py$", - "^tests/test_domains/test_domain_py_pyobject\\.py$", - "^tests/test_domains/test_domain_rst\\.py$", - "^tests/test_domains/test_domain_std\\.py$", - # tests/test_environment - "^tests/test_environment/test_environment_toctree\\.py$", - # tests/test_extensions - "^tests/test_extensions/test_ext_apidoc\\.py$", - "^tests/test_extensions/test_ext_autodoc\\.py$", - "^tests/test_extensions/test_ext_autodoc_events\\.py$", - "^tests/test_extensions/test_ext_autodoc_mock\\.py$", - "^tests/test_extensions/test_ext_autosummary\\.py$", - "^tests/test_extensions/test_ext_doctest\\.py$", - "^tests/test_extensions/test_ext_inheritance_diagram\\.py$", - "^tests/test_extensions/test_ext_intersphinx\\.py$", - "^tests/test_extensions/test_ext_napoleon_docstring\\.py$", - # tests/test_intl - "^tests/test_intl/test_intl\\.py$", - # tests/test_pycode - "^tests/test_pycode/test_pycode\\.py$", - "^tests/test_pycode/test_pycode_ast\\.py$", - # tests/test_transforms - "^tests/test_transforms/test_transforms_post_transforms\\.py$", - # tests/test_util - "^tests/test_util/test_util_fileutil\\.py$", - "^tests/test_util/test_util_i18n\\.py$", - "^tests/test_util/test_util_inspect\\.py$", - "^tests/test_util/test_util_logging\\.py$", - "^tests/test_util/test_util_nodes\\.py$", - "^tests/test_util/test_util_rst\\.py$", - "^tests/test_util/test_util_template\\.py$", - "^tests/test_util/test_util_typing\\.py$", - "^tests/test_util/typing_test_data\\.py$", ] python_version = "3.11" strict = true @@ -231,6 +178,7 @@ strict_optional = false module = [ "imagesize", "pypi_attestations", + "pyximport", "sigstore.models", "sigstore.verify", "sigstore.verify.policy", @@ -351,6 +299,73 @@ module = [ ] disallow_untyped_defs = false +[[tool.mypy.overrides]] +module = [ + # tests/ + "tests.test_quickstart", + "tests.test_search", + # tests/test_builders + "tests.test_builders.test_build_epub", + "tests.test_builders.test_build_gettext", + "tests.test_builders.test_build_latex", + "tests.test_builders.test_build_texinfo", + # tests/test_config + "tests.test_config.test_config", + # tests/test_directives + "tests.test_directives.test_directive_only", + "tests.test_directives.test_directive_other", + "tests.test_directives.test_directive_patch", + # tests/test_domains + "tests.test_domains.test_domain_c", + "tests.test_domains.test_domain_cpp", + "tests.test_domains.test_domain_js", + "tests.test_domains.test_domain_py", + "tests.test_domains.test_domain_py_fields", + "tests.test_domains.test_domain_py_pyfunction", + "tests.test_domains.test_domain_py_pyobject", + "tests.test_domains.test_domain_rst", + "tests.test_domains.test_domain_std", + # tests/test_environment + "tests.test_environment.test_environment_toctree", + # tests/test_extensions + "tests.test_extensions.test_ext_apidoc", + "tests.test_extensions.test_ext_autodoc", + "tests.test_extensions.test_ext_autodoc_events", + "tests.test_extensions.test_ext_autodoc_mock", + "tests.test_extensions.test_ext_autosummary", + "tests.test_extensions.test_ext_doctest", + "tests.test_extensions.test_ext_inheritance_diagram", + "tests.test_extensions.test_ext_intersphinx", + "tests.test_extensions.test_ext_napoleon_docstring", + # tests/test_intl + "tests.test_intl.test_intl", + # tests/test_pycode + "tests.test_pycode.test_pycode", + "tests.test_pycode.test_pycode_ast", + # tests/test_transforms + "tests.test_transforms.test_transforms_post_transforms", + # tests/test_util + "tests.test_util.test_util_fileutil", + "tests.test_util.test_util_i18n", + "tests.test_util.test_util_inspect", + "tests.test_util.test_util_logging", + "tests.test_util.test_util_nodes", + "tests.test_util.test_util_rst", + "tests.test_util.test_util_template", + "tests.test_util.test_util_typing", +] +check_untyped_defs = false +disable_error_code = [ + "annotation-unchecked", +] +disallow_incomplete_defs = false +disallow_untyped_calls = false +disallow_untyped_defs = false + +[[tool.mypy.overrides]] +module = ["tests.test_util.typing_test_data"] +ignore_errors = true + [tool.pytest.ini_options] minversion = "6.0" addopts = [ diff --git a/tests/test_config/test_config.py b/tests/test_config/test_config.py index 50241d17e65..4b8321583e5 100644 --- a/tests/test_config/test_config.py +++ b/tests/test_config/test_config.py @@ -216,7 +216,7 @@ def check( assert v.__class__ is u.__class__ for u_i, v_i in zip(u, v, strict=True): counter[type(u)] += 1 - check(u_i, v_i, counter=counter, guard=guard | {id(u), id(v)}) + check(u_i, v_i, counter=counter, guard=guard | {id(u), id(v)}) # type: ignore[arg-type] return counter @@ -280,7 +280,7 @@ def check( assert v.__class__ is u.__class__ for u_i, v_i in zip(u, v, strict=True): counter[type(u)] += 1 - check(u[u_i], v[v_i], counter=counter, guard=guard | {id(u), id(v)}) + check(u[u_i], v[v_i], counter=counter, guard=guard | {id(u), id(v)}) # type: ignore[arg-type] return counter counters = check(actual.x, x, counter=Counter()) diff --git a/tests/test_extensions/test_ext_autodoc.py b/tests/test_extensions/test_ext_autodoc.py index afbcb14de82..c0ab204589c 100644 --- a/tests/test_extensions/test_ext_autodoc.py +++ b/tests/test_extensions/test_ext_autodoc.py @@ -320,7 +320,7 @@ def process_signature(*args): app.connect('autodoc-process-signature', process_signature) - def func(x: int, y: int) -> int: + def func(x: int, y: int) -> int: # type: ignore[empty-body] pass directive = make_directive_bridge(app.env) diff --git a/tests/test_extensions/test_ext_autodoc_events.py b/tests/test_extensions/test_ext_autodoc_events.py index d7139e88019..c2e9940a92b 100644 --- a/tests/test_extensions/test_ext_autodoc_events.py +++ b/tests/test_extensions/test_ext_autodoc_events.py @@ -71,7 +71,7 @@ def test_cut_lines_no_objtype(): ] process = cut_lines(2) - process(None, 'function', 'func', None, {}, docstring_lines) # type: ignore[arg-type] + process(None, 'function', 'func', None, {}, docstring_lines) assert docstring_lines == [ 'second line', '---', diff --git a/tests/test_extensions/test_ext_autosummary.py b/tests/test_extensions/test_ext_autosummary.py index c80753bef13..47589718fdc 100644 --- a/tests/test_extensions/test_ext_autosummary.py +++ b/tests/test_extensions/test_ext_autosummary.py @@ -240,7 +240,7 @@ def test_escaping(app): @pytest.mark.sphinx('html', testroot='ext-autosummary') def test_autosummary_generate_content_for_module(app): - import autosummary_dummy_module + import autosummary_dummy_module # type: ignore[import-not-found] template = Mock() @@ -457,7 +457,7 @@ def test_autosummary_generate_content_for_module_imported_members(app): @pytest.mark.sphinx('html', testroot='ext-autosummary') def test_autosummary_generate_content_for_module_imported_members_inherited_module(app): - import autosummary_dummy_inherited_module + import autosummary_dummy_inherited_module # type: ignore[import-not-found] template = Mock() diff --git a/tests/test_extensions/test_ext_doctest.py b/tests/test_extensions/test_ext_doctest.py index 4cfbe69ddde..d075ca0485b 100644 --- a/tests/test_extensions/test_ext_doctest.py +++ b/tests/test_extensions/test_ext_doctest.py @@ -75,7 +75,7 @@ def cleanup_call(): cleanup_called += 1 -recorded_calls = Counter() +recorded_calls: Counter[tuple[str, str, int]] = Counter() @pytest.mark.sphinx('doctest', testroot='ext-doctest-skipif') diff --git a/tests/test_extensions/test_ext_inheritance_diagram.py b/tests/test_extensions/test_ext_inheritance_diagram.py index 9bb6389ae66..20c2dc6a8fe 100644 --- a/tests/test_extensions/test_ext_inheritance_diagram.py +++ b/tests/test_extensions/test_ext_inheritance_diagram.py @@ -327,7 +327,7 @@ def test_import_classes(rootdir): saved_path = sys.path.copy() sys.path.insert(0, str(rootdir / 'test-ext-inheritance_diagram')) try: - from example.sphinx import DummyClass + from example.sphinx import DummyClass # type: ignore[import-not-found] # got exception for unknown class or module with pytest.raises(InheritanceException): diff --git a/tests/test_extensions/test_ext_intersphinx.py b/tests/test_extensions/test_ext_intersphinx.py index 8d29d539bdd..f5c83ac4eb5 100644 --- a/tests/test_extensions/test_ext_intersphinx.py +++ b/tests/test_extensions/test_ext_intersphinx.py @@ -38,7 +38,7 @@ from tests.utils import http_server -class FakeList(list): # NoQA: FURB189 +class FakeList(list[str]): def __iter__(self) -> NoReturn: raise NotImplementedError diff --git a/tests/test_intl/test_intl.py b/tests/test_intl/test_intl.py index 3f25773ec91..398d9d18b88 100644 --- a/tests/test_intl/test_intl.py +++ b/tests/test_intl/test_intl.py @@ -23,6 +23,7 @@ from sphinx.util.nodes import NodeMatcher if TYPE_CHECKING: + from collections.abc import Iterator from io import StringIO from pathlib import Path @@ -825,7 +826,7 @@ def sleep(self, ds: float) -> None: @pytest.fixture -def mock_time_and_i18n() -> tuple[pytest.MonkeyPatch, _MockClock]: +def mock_time_and_i18n() -> Iterator[tuple[pytest.MonkeyPatch, _MockClock]]: from sphinx.util.i18n import CatalogInfo # save the 'original' definition @@ -838,6 +839,7 @@ def mock_write_mo(self, locale, use_fuzzy=False): # see: https://github.com/pytest-dev/pytest/issues/363 with pytest.MonkeyPatch.context() as mock: + clock: _MockClock if os.name == 'posix': clock = _MockUnixClock() else: diff --git a/tests/test_search.py b/tests/test_search.py index 87d4896b8d9..46d841e5a4d 100644 --- a/tests/test_search.py +++ b/tests/test_search.py @@ -16,7 +16,7 @@ from tests.utils import TESTS_ROOT if TYPE_CHECKING: - from collections.abc import Iterator + from collections.abc import Iterable, Iterator from pathlib import Path from typing import Any @@ -53,12 +53,14 @@ def __str__(self) -> str: class DummyDomain: - def __init__(self, name: str, data: dict) -> None: + def __init__( + self, name: str, data: Iterable[tuple[str, str, str, str, str, int]] + ) -> None: self.name = name self.data = data self.object_types: dict[str, ObjType] = {} - def get_objects(self) -> list[tuple[str, str, str, str, str, int]]: + def get_objects(self) -> Iterable[tuple[str, str, str, str, str, int]]: return self.data diff --git a/tests/test_transforms/test_transforms_post_transforms.py b/tests/test_transforms/test_transforms_post_transforms.py index edd28749431..962202d22b0 100644 --- a/tests/test_transforms/test_transforms_post_transforms.py +++ b/tests/test_transforms/test_transforms_post_transforms.py @@ -173,7 +173,7 @@ def mark_node(self, node: nodes.Node) -> NoReturn: visitor_methods = {f'visit_{tp.__name__}' for tp in desc_sig_elements_list} visitor_methods.update(f'visit_{name}' for name in add_visitor_method_for) class_dict = dict.fromkeys(visitor_methods, BaseCustomTranslatorClass.mark_node) - return type('CustomTranslatorClass', (BaseCustomTranslatorClass,), class_dict) # type: ignore[return-value] + return type('CustomTranslatorClass', (BaseCustomTranslatorClass,), class_dict) @pytest.mark.parametrize( 'add_visitor_method_for', @@ -266,7 +266,7 @@ def test_custom_implementation( strict=True, ): assert_node(node, node_type) - assert not node.hasattr('_sig_node_type') + assert not hasattr(node, '_sig_node_type') assert mess == f'mark: {node_type.__name__!r}' else: # desc_sig_* nodes are converted into inline nodes diff --git a/tests/test_util/test_util_inspect.py b/tests/test_util/test_util_inspect.py index c04086ccad9..81eb3af2398 100644 --- a/tests/test_util/test_util_inspect.py +++ b/tests/test_util/test_util_inspect.py @@ -890,7 +890,7 @@ def test_isattributedescriptor(): try: # _testcapi module cannot be importable in some distro # refs: https://github.com/sphinx-doc/sphinx/issues/9868 - import _testcapi + import _testcapi # type: ignore[import-not-found] # instancemethod (C-API) testinstancemethod = _testcapi.instancemethod(str.__repr__) diff --git a/tests/test_util/test_util_typing.py b/tests/test_util/test_util_typing.py index f3f452fae1e..f02a88e0d1d 100644 --- a/tests/test_util/test_util_typing.py +++ b/tests/test_util/test_util_typing.py @@ -75,7 +75,7 @@ ) from weakref import WeakSet -from sphinx.ext.autodoc import mock +from sphinx.ext.autodoc.mock import mock from sphinx.util.typing import _INVALID_BUILTIN_CLASSES, restify, stringify_annotation @@ -472,7 +472,7 @@ def test_restify_type_ForwardRef(): restify(list[ForwardRef('MyInt')]) == ':py:class:`list`\\ [:py:class:`MyInt`]' ) - ann_rst = restify(Tuple[dict[ForwardRef('MyInt'), str], list[List[int]]]) # type: ignore[attr-defined] + ann_rst = restify(Tuple[dict[ForwardRef('MyInt'), str], list[List[int]]]) assert ann_rst == ( ':py:class:`~typing.Tuple`\\ [:py:class:`dict`\\ [:py:class:`MyInt`, :py:class:`str`], :py:class:`list`\\ [:py:class:`~typing.List`\\ [:py:class:`int`]]]' ) @@ -493,14 +493,14 @@ def test_restify_type_Literal(): def test_restify_pep_585(): - assert restify(list[str]) == ':py:class:`list`\\ [:py:class:`str`]' # type: ignore[attr-defined] - ann_rst = restify(dict[str, str]) # type: ignore[attr-defined] + assert restify(list[str]) == ':py:class:`list`\\ [:py:class:`str`]' + ann_rst = restify(dict[str, str]) assert ann_rst == ':py:class:`dict`\\ [:py:class:`str`, :py:class:`str`]' assert restify(tuple[str, ...]) == ':py:class:`tuple`\\ [:py:class:`str`, ...]' assert restify(tuple[str, str, str]) == ( ':py:class:`tuple`\\ [:py:class:`str`, :py:class:`str`, :py:class:`str`]' ) - ann_rst = restify(dict[str, tuple[int, ...]]) # type: ignore[attr-defined] + ann_rst = restify(dict[str, tuple[int, ...]]) assert ann_rst == ( ':py:class:`dict`\\ ' '[:py:class:`str`, :py:class:`tuple`\\ ' @@ -548,10 +548,10 @@ class X(t.TypedDict): def test_restify_type_union_operator(): - assert restify(int | None) == ':py:class:`int` | :py:obj:`None`' # type: ignore[attr-defined] - assert restify(None | int) == ':py:obj:`None` | :py:class:`int`' # type: ignore[attr-defined] - assert restify(int | str) == ':py:class:`int` | :py:class:`str`' # type: ignore[attr-defined] - ann_rst = restify(int | str | None) # type: ignore[attr-defined] + assert restify(int | None) == ':py:class:`int` | :py:obj:`None`' + assert restify(None | int) == ':py:obj:`None` | :py:class:`int`' + assert restify(int | str) == ':py:class:`int` | :py:class:`str`' + ann_rst = restify(int | str | None) assert ann_rst == ':py:class:`int` | :py:class:`str` | :py:obj:`None`' @@ -564,7 +564,7 @@ def test_restify_broken_type_hints(): def test_restify_mock(): with mock(['unknown']): - import unknown + import unknown # type: ignore[import-not-found] assert restify(unknown) == ':py:class:`unknown`' assert restify(unknown.secret.Class) == ':py:class:`unknown.secret.Class`' @@ -982,8 +982,8 @@ def test_stringify_type_hints_alias(): assert stringify_annotation(MyStr, 'fully-qualified-except-typing') == 'str' assert stringify_annotation(MyStr, 'smart') == 'str' - assert stringify_annotation(MyTuple) == 'Tuple[str, str]' # type: ignore[attr-defined] - assert stringify_annotation(MyTuple, 'smart') == '~typing.Tuple[str, str]' # type: ignore[attr-defined] + assert stringify_annotation(MyTuple) == 'Tuple[str, str]' + assert stringify_annotation(MyTuple, 'smart') == '~typing.Tuple[str, str]' def test_stringify_type_Literal(): @@ -1005,26 +1005,26 @@ def test_stringify_type_Literal(): def test_stringify_type_union_operator(): - assert stringify_annotation(int | None) == 'int | None' # type: ignore[attr-defined] - assert stringify_annotation(int | None, 'smart') == 'int | None' # type: ignore[attr-defined] + assert stringify_annotation(int | None) == 'int | None' + assert stringify_annotation(int | None, 'smart') == 'int | None' - assert stringify_annotation(int | str) == 'int | str' # type: ignore[attr-defined] - assert stringify_annotation(int | str, 'smart') == 'int | str' # type: ignore[attr-defined] + assert stringify_annotation(int | str) == 'int | str' + assert stringify_annotation(int | str, 'smart') == 'int | str' - assert stringify_annotation(int | str | None) == 'int | str | None' # type: ignore[attr-defined] - assert stringify_annotation(int | str | None, 'smart') == 'int | str | None' # type: ignore[attr-defined] + assert stringify_annotation(int | str | None) == 'int | str | None' + assert stringify_annotation(int | str | None, 'smart') == 'int | str | None' ann_str = stringify_annotation( int | tuple[dict[str, int | None], list[int | str]] | None ) - assert ann_str == 'int | tuple[dict[str, int | None], list[int | str]] | None' # type: ignore[attr-defined] + assert ann_str == 'int | tuple[dict[str, int | None], list[int | str]] | None' ann_str = stringify_annotation( int | tuple[dict[str, int | None], list[int | str]] | None, 'smart' ) - assert ann_str == 'int | tuple[dict[str, int | None], list[int | str]] | None' # type: ignore[attr-defined] + assert ann_str == 'int | tuple[dict[str, int | None], list[int | str]] | None' - assert stringify_annotation(int | Struct) == 'int | struct.Struct' # type: ignore[attr-defined] - assert stringify_annotation(int | Struct, 'smart') == 'int | ~struct.Struct' # type: ignore[attr-defined] + assert stringify_annotation(int | Struct) == 'int | struct.Struct' + assert stringify_annotation(int | Struct, 'smart') == 'int | ~struct.Struct' def test_stringify_broken_type_hints(): @@ -1058,16 +1058,16 @@ def test_stringify_type_ForwardRef(): ann_str = stringify_annotation( Tuple[dict[ForwardRef('MyInt'), str], list[List[int]]] ) - assert ann_str == 'Tuple[dict[MyInt, str], list[List[int]]]' # type: ignore[attr-defined] + assert ann_str == 'Tuple[dict[MyInt, str], list[List[int]]]' ann_str = stringify_annotation( Tuple[dict[ForwardRef('MyInt'), str], list[List[int]]], 'fully-qualified-except-typing', ) - assert ann_str == 'Tuple[dict[MyInt, str], list[List[int]]]' # type: ignore[attr-defined] + assert ann_str == 'Tuple[dict[MyInt, str], list[List[int]]]' ann_str = stringify_annotation( Tuple[dict[ForwardRef('MyInt'), str], list[List[int]]], 'smart' ) - assert ann_str == '~typing.Tuple[dict[MyInt, str], list[~typing.List[int]]]' # type: ignore[attr-defined] + assert ann_str == '~typing.Tuple[dict[MyInt, str], list[~typing.List[int]]]' def test_stringify_type_hints_paramspec():