Further improve typing in tests/ (#12816)

Co-authored-by: Adam Turner <9087854+aa-turner@users.noreply.github.com>
This commit is contained in:
danieleades 2024-10-03 20:17:40 +01:00 committed by GitHub
parent b6f818f600
commit 7546545876
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 49 additions and 37 deletions

View File

@ -146,7 +146,6 @@ files = [
exclude = [ exclude = [
"tests/roots", "tests/roots",
# tests/ # tests/
"^tests/test_events\\.py$",
"^tests/test_quickstart\\.py$", "^tests/test_quickstart\\.py$",
"^tests/test_search\\.py$", "^tests/test_search\\.py$",
# tests/test_builders # tests/test_builders
@ -175,14 +174,12 @@ exclude = [
# tests/test_extensions # tests/test_extensions
"^tests/test_extensions/test_ext_apidoc\\.py$", "^tests/test_extensions/test_ext_apidoc\\.py$",
"^tests/test_extensions/test_ext_autodoc\\.py$", "^tests/test_extensions/test_ext_autodoc\\.py$",
"^tests/test_extensions/test_ext_autodoc_autofunction\\.py$",
"^tests/test_extensions/test_ext_autodoc_events\\.py$", "^tests/test_extensions/test_ext_autodoc_events\\.py$",
"^tests/test_extensions/test_ext_autodoc_mock\\.py$", "^tests/test_extensions/test_ext_autodoc_mock\\.py$",
"^tests/test_extensions/test_ext_autosummary\\.py$", "^tests/test_extensions/test_ext_autosummary\\.py$",
"^tests/test_extensions/test_ext_doctest\\.py$", "^tests/test_extensions/test_ext_doctest\\.py$",
"^tests/test_extensions/test_ext_inheritance_diagram\\.py$", "^tests/test_extensions/test_ext_inheritance_diagram\\.py$",
"^tests/test_extensions/test_ext_intersphinx\\.py$", "^tests/test_extensions/test_ext_intersphinx\\.py$",
"^tests/test_extensions/test_ext_napoleon\\.py$",
"^tests/test_extensions/test_ext_napoleon_docstring\\.py$", "^tests/test_extensions/test_ext_napoleon_docstring\\.py$",
# tests/test_intl # tests/test_intl
"^tests/test_intl/test_intl\\.py$", "^tests/test_intl/test_intl\\.py$",

View File

@ -8,7 +8,8 @@ from sphinx.events import EventManager
def test_event_priority(): def test_event_priority():
result = [] result = []
events = EventManager(object()) # pass an dummy object as an app app = object() # pass a dummy object as an app
events = EventManager(app) # type: ignore[arg-type]
events.connect('builder-inited', lambda app: result.append(1), priority=500) events.connect('builder-inited', lambda app: result.append(1), priority=500)
events.connect('builder-inited', lambda app: result.append(2), priority=500) events.connect('builder-inited', lambda app: result.append(2), priority=500)
# earlier # earlier
@ -30,7 +31,8 @@ def test_event_allowed_exceptions():
def raise_error(app): def raise_error(app):
raise RuntimeError raise RuntimeError
events = EventManager(FakeApp()) # pass an dummy object as an app app = FakeApp() # pass a dummy object as an app
events = EventManager(app) # type: ignore[arg-type]
events.connect('builder-inited', raise_error, priority=500) events.connect('builder-inited', raise_error, priority=500)
# all errors are converted to ExtensionError # all errors are converted to ExtensionError
@ -46,7 +48,8 @@ def test_event_pdb():
def raise_error(app): def raise_error(app):
raise RuntimeError raise RuntimeError
events = EventManager(FakeApp(pdb=True)) # pass an dummy object as an app app = FakeApp(pdb=True) # pass a dummy object as an app
events = EventManager(app) # type: ignore[arg-type]
events.connect('builder-inited', raise_error, priority=500) events.connect('builder-inited', raise_error, priority=500)
# errors aren't converted # errors aren't converted

View File

@ -4,6 +4,8 @@ This tests mainly the Documenters; the auto directives are tested in a test
source file translated by test_build. source file translated by test_build.
""" """
from typing import Any
import pytest import pytest
from tests.test_extensions.autodoc_util import do_autodoc from tests.test_extensions.autodoc_util import do_autodoc
@ -109,7 +111,7 @@ def test_decorated(app):
@pytest.mark.sphinx('html', testroot='ext-autodoc') @pytest.mark.sphinx('html', testroot='ext-autodoc')
def test_singledispatch(app): def test_singledispatch(app):
options = {} options: dict[str, Any] = {}
actual = do_autodoc(app, 'function', 'target.singledispatch.func', options) actual = do_autodoc(app, 'function', 'target.singledispatch.func', options)
assert list(actual) == [ assert list(actual) == [
'', '',

View File

@ -2,7 +2,6 @@
import functools import functools
from collections import namedtuple from collections import namedtuple
from typing import Any
from unittest import mock from unittest import mock
import pytest import pytest
@ -111,7 +110,7 @@ class TestProcessDocstring:
class TestSetup: class TestSetup:
def test_unknown_app_type(self): def test_unknown_app_type(self):
setup(object()) setup(object()) # type: ignore[arg-type]
def test_add_config_values(self): def test_add_config_values(self):
app = mock.Mock(Sphinx) app = mock.Mock(Sphinx)
@ -146,7 +145,7 @@ class TestSkipMember:
self, self,
what: str, what: str,
member: str, member: str,
obj: Any, obj: object,
expect_default_skip: bool, expect_default_skip: bool,
config_name: str, config_name: str,
) -> None: ) -> None:

View File

@ -1,8 +1,11 @@
"""Test the sphinx.quickstart module.""" """Test the sphinx.quickstart module."""
import time import time
from collections.abc import Callable
from io import StringIO from io import StringIO
from os import path from os import path
from pathlib import Path
from typing import Any
import pytest import pytest
@ -17,10 +20,12 @@ def setup_module():
nocolor() nocolor()
def mock_input(answers, needanswer=False): def mock_input(
answers: dict[str, str], needanswer: bool = False
) -> Callable[[str], str]:
called = set() called = set()
def input_(prompt): def input_(prompt: str) -> str:
if prompt in called: if prompt in called:
raise AssertionError( raise AssertionError(
'answer for %r missing and no default present' % prompt 'answer for %r missing and no default present' % prompt
@ -36,7 +41,7 @@ def mock_input(answers, needanswer=False):
return input_ return input_
real_input = input real_input: Callable[[str], str] = input
def teardown_module(): def teardown_module():
@ -95,13 +100,13 @@ def test_quickstart_defaults(tmp_path):
'Project version': '0.1', 'Project version': '0.1',
} }
qs.term_input = mock_input(answers) qs.term_input = mock_input(answers)
d = {} d: dict[str, Any] = {}
qs.ask_user(d) qs.ask_user(d)
qs.generate(d) qs.generate(d)
conffile = tmp_path / 'conf.py' conffile = tmp_path / 'conf.py'
assert conffile.is_file() assert conffile.is_file()
ns = {} ns: dict[str, Any] = {}
exec(conffile.read_text(encoding='utf8'), ns) # NoQA: S102 exec(conffile.read_text(encoding='utf8'), ns) # NoQA: S102
assert ns['extensions'] == [] assert ns['extensions'] == []
assert ns['templates_path'] == ['_templates'] assert ns['templates_path'] == ['_templates']
@ -145,13 +150,13 @@ def test_quickstart_all_answers(tmp_path):
'Do you want to use the epub builder': 'yes', 'Do you want to use the epub builder': 'yes',
} }
qs.term_input = mock_input(answers, needanswer=True) qs.term_input = mock_input(answers, needanswer=True)
d = {} d: dict[str, Any] = {}
qs.ask_user(d) qs.ask_user(d)
qs.generate(d) qs.generate(d)
conffile = tmp_path / 'source' / 'conf.py' conffile = tmp_path / 'source' / 'conf.py'
assert conffile.is_file() assert conffile.is_file()
ns = {} ns: dict[str, Any] = {}
exec(conffile.read_text(encoding='utf8'), ns) # NoQA: S102 exec(conffile.read_text(encoding='utf8'), ns) # NoQA: S102
assert ns['extensions'] == [ assert ns['extensions'] == [
'sphinx.ext.autodoc', 'sphinx.ext.autodoc',
@ -184,11 +189,11 @@ def test_generated_files_eol(tmp_path):
'Project version': '0.1', 'Project version': '0.1',
} }
qs.term_input = mock_input(answers) qs.term_input = mock_input(answers)
d = {} d: dict[str, Any] = {}
qs.ask_user(d) qs.ask_user(d)
qs.generate(d) qs.generate(d)
def assert_eol(filename, eol): def assert_eol(filename: Path, eol: str) -> None:
content = filename.read_bytes().decode() content = filename.read_bytes().decode()
assert all(l[-len(eol) :] == eol for l in content.splitlines(keepends=True)) assert all(l[-len(eol) :] == eol for l in content.splitlines(keepends=True))
@ -204,7 +209,7 @@ def test_quickstart_and_build(tmp_path):
'Project version': '0.1', 'Project version': '0.1',
} }
qs.term_input = mock_input(answers) qs.term_input = mock_input(answers)
d = {} d: dict[str, Any] = {}
qs.ask_user(d) qs.ask_user(d)
qs.generate(d) qs.generate(d)
@ -223,13 +228,13 @@ def test_default_filename(tmp_path):
'Project version': '0.1', 'Project version': '0.1',
} }
qs.term_input = mock_input(answers) qs.term_input = mock_input(answers)
d = {} d: dict[str, Any] = {}
qs.ask_user(d) qs.ask_user(d)
qs.generate(d) qs.generate(d)
conffile = tmp_path / 'conf.py' conffile = tmp_path / 'conf.py'
assert conffile.is_file() assert conffile.is_file()
ns = {} ns: dict[str, Any] = {}
exec(conffile.read_text(encoding='utf8'), ns) # NoQA: S102 exec(conffile.read_text(encoding='utf8'), ns) # NoQA: S102
@ -247,7 +252,7 @@ def test_extensions(tmp_path):
conffile = tmp_path / 'conf.py' conffile = tmp_path / 'conf.py'
assert conffile.is_file() assert conffile.is_file()
ns = {} ns: dict[str, Any] = {}
exec(conffile.read_text(encoding='utf8'), ns) # NoQA: S102 exec(conffile.read_text(encoding='utf8'), ns) # NoQA: S102
assert ns['extensions'] == ['foo', 'bar', 'baz'] assert ns['extensions'] == ['foo', 'bar', 'baz']
@ -263,6 +268,6 @@ def test_exits_when_existing_confpy(monkeypatch):
qs.term_input = mock_input({ qs.term_input = mock_input({
'Please enter a new root path (or just Enter to exit)': '', 'Please enter a new root path (or just Enter to exit)': '',
}) })
d = {} d: dict[str, Any] = {}
with pytest.raises(SystemExit): with pytest.raises(SystemExit):
qs.ask_user(d) qs.ask_user(d)

View File

@ -17,6 +17,10 @@ from tests.utils import TESTS_ROOT
if TYPE_CHECKING: if TYPE_CHECKING:
from collections.abc import Iterator from collections.abc import Iterator
from pathlib import Path
from typing import Any
from sphinx.domains import ObjType
JAVASCRIPT_TEST_ROOTS = [ JAVASCRIPT_TEST_ROOTS = [
directory directory
@ -52,9 +56,9 @@ class DummyDomain:
def __init__(self, name: str, data: dict) -> None: def __init__(self, name: str, data: dict) -> None:
self.name = name self.name = name
self.data = data self.data = data
self.object_types = {} self.object_types: dict[str, ObjType] = {}
def get_objects(self): def get_objects(self) -> list[tuple[str, str, str, str, str, int]]:
return self.data return self.data
@ -72,7 +76,7 @@ def setup_module():
parser = rst.Parser() parser = rst.Parser()
def load_searchindex(path): def load_searchindex(path: Path) -> Any:
searchindex = path.read_text(encoding='utf8') searchindex = path.read_text(encoding='utf8')
assert searchindex.startswith('Search.setIndex(') assert searchindex.startswith('Search.setIndex(')
assert searchindex.endswith(')') assert searchindex.endswith(')')
@ -80,7 +84,7 @@ def load_searchindex(path):
return json.loads(searchindex[16:-1]) return json.loads(searchindex[16:-1])
def is_registered_term(index, keyword): def is_registered_term(index: Any, keyword: str) -> bool:
return index['terms'].get(keyword, []) != [] return index['terms'].get(keyword, []) != []
@ -191,12 +195,12 @@ def test_IndexBuilder():
], ],
) )
env = DummyEnvironment('1.0', DummyDomainsContainer(dummy1=domain1, dummy2=domain2)) env = DummyEnvironment('1.0', DummyDomainsContainer(dummy1=domain1, dummy2=domain2))
doc = utils.new_document(b'test data', settings) doc = utils.new_document('test data', settings)
doc['file'] = 'dummy' doc['file'] = 'dummy'
parser.parse(FILE_CONTENTS, doc) parser.parse(FILE_CONTENTS, doc)
# feed # feed
index = IndexBuilder(env, 'en', {}, None) index = IndexBuilder(env, 'en', {}, '')
index.feed('docname1_1', 'filename1_1', 'title1_1', doc) index.feed('docname1_1', 'filename1_1', 'title1_1', doc)
index.feed('docname1_2', 'filename1_2', 'title1_2', doc) index.feed('docname1_2', 'filename1_2', 'title1_2', doc)
index.feed('docname2_2', 'filename2_2', 'title2_2', doc) index.feed('docname2_2', 'filename2_2', 'title2_2', doc)
@ -285,7 +289,7 @@ def test_IndexBuilder():
index.dump(stream, 'pickle') index.dump(stream, 'pickle')
stream.seek(0) stream.seek(0)
index2 = IndexBuilder(env, 'en', {}, None) index2 = IndexBuilder(env, 'en', {}, '')
index2.load(stream, 'pickle') index2.load(stream, 'pickle')
assert index2._titles == index._titles assert index2._titles == index._titles
@ -366,11 +370,11 @@ def test_IndexBuilder_lookup():
env = DummyEnvironment('1.0', {}) env = DummyEnvironment('1.0', {})
# zh # zh
index = IndexBuilder(env, 'zh', {}, None) index = IndexBuilder(env, 'zh', {}, '')
assert index.lang.lang == 'zh' assert index.lang.lang == 'zh'
# zh_CN # zh_CN
index = IndexBuilder(env, 'zh_CN', {}, None) index = IndexBuilder(env, 'zh_CN', {}, '')
assert index.lang.lang == 'zh' assert index.lang.lang == 'zh'
@ -426,7 +430,7 @@ def test_search_index_is_deterministic(app):
assert_is_sorted(index, '') assert_is_sorted(index, '')
def is_title_tuple_type(item: list[int | str]): def is_title_tuple_type(item: list[int | str]) -> bool:
""" """
In the search index, titles inside .alltitles are stored as a tuple of In the search index, titles inside .alltitles are stored as a tuple of
(document_idx, title_anchor). Tuples are represented as lists in JSON, (document_idx, title_anchor). Tuples are represented as lists in JSON,
@ -436,7 +440,9 @@ def is_title_tuple_type(item: list[int | str]):
return len(item) == 2 and isinstance(item[0], int) and isinstance(item[1], str) return len(item) == 2 and isinstance(item[0], int) and isinstance(item[1], str)
def assert_is_sorted(item, path: str): def assert_is_sorted(
item: dict[str, str] | list[int | str] | int | str, path: str
) -> None:
lists_not_to_sort = { lists_not_to_sort = {
# Each element of .titles is related to the element of .docnames in the same position. # Each element of .titles is related to the element of .docnames in the same position.
# The ordering is deterministic because .docnames is sorted. # The ordering is deterministic because .docnames is sorted.

View File

@ -6,12 +6,12 @@ from unittest import mock
import pytest import pytest
from sphinx.jinja2glue import BuiltinTemplateLoader from sphinx.jinja2glue import BuiltinTemplateLoader
from sphinx.util import strip_colors from sphinx.util.console import strip_colors
from sphinx.util.fileutil import _template_basename, copy_asset, copy_asset_file from sphinx.util.fileutil import _template_basename, copy_asset, copy_asset_file
class DummyTemplateLoader(BuiltinTemplateLoader): class DummyTemplateLoader(BuiltinTemplateLoader):
def __init__(self): def __init__(self) -> None:
super().__init__() super().__init__()
builder = mock.Mock() builder = mock.Mock()
builder.config.templates_path = [] builder.config.templates_path = []