[lint] whitelist all test files except configuration and utils in tests (#12109)

This commit is contained in:
Bénédikt Tran
2024-03-16 18:06:58 +01:00
committed by GitHub
parent 6aaeee206b
commit 2df5b0a8ab
4 changed files with 201 additions and 25 deletions

View File

@@ -131,7 +131,8 @@ exclude = [
]
[tool.mypy]
files = ["sphinx", "utils"]
files = ["sphinx", "utils", "tests"]
exclude = ["tests/certs", "tests/js", "tests/roots"]
check_untyped_defs = true
disallow_incomplete_defs = true
python_version = "3.9"
@@ -212,6 +213,154 @@ module = [
]
disallow_any_generics = false
[[tool.mypy.overrides]]
module = [
# tests/
# "tests.conftest",
"tests.test_addnodes",
"tests.test_application",
"tests.test_errors",
"tests.test_events",
"tests.test_highlighting",
"tests.test_project",
"tests.test_quickstart",
"tests.test_roles",
"tests.test_search",
"tests.test_toctree",
"tests.test_versioning",
# "tests.utils",
# tests/test_builders
# "tests.test_builders.conftest",
"tests.test_builders.test_build",
"tests.test_builders.test_build_changes",
"tests.test_builders.test_build_dirhtml",
"tests.test_builders.test_build_epub",
"tests.test_builders.test_builder",
"tests.test_builders.test_build_gettext",
"tests.test_builders.test_build_html",
"tests.test_builders.test_build_html_5_output",
"tests.test_builders.test_build_html_assets",
"tests.test_builders.test_build_html_code",
"tests.test_builders.test_build_html_download",
"tests.test_builders.test_build_html_highlight",
"tests.test_builders.test_build_html_image",
"tests.test_builders.test_build_html_maths",
"tests.test_builders.test_build_html_numfig",
"tests.test_builders.test_build_html_tocdepth",
"tests.test_builders.test_build_latex",
"tests.test_builders.test_build_linkcheck",
"tests.test_builders.test_build_manpage",
"tests.test_builders.test_build_texinfo",
"tests.test_builders.test_build_text",
"tests.test_builders.test_build_warnings",
# tests/test_config
"tests.test_config.test_config",
"tests.test_config.test_correct_year",
# tests/test_directives
"tests.test_directives.test_directive_code",
"tests.test_directives.test_directive_object_description",
"tests.test_directives.test_directive_only",
"tests.test_directives.test_directive_option",
"tests.test_directives.test_directive_other",
"tests.test_directives.test_directive_patch",
"tests.test_directives.test_directives_no_typesetting",
# 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_canonical",
"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",
"tests.test_environment.test_environment_indexentries",
"tests.test_environment.test_environment_record_dependencies",
"tests.test_environment.test_environment_toctree",
# tests/test_extensions
"tests.test_extensions.ext_napoleon_pep526_data_google",
"tests.test_extensions.ext_napoleon_pep526_data_numpy",
"tests.test_extensions.test_ext_apidoc",
"tests.test_extensions.test_ext_autodoc",
"tests.test_extensions.test_ext_autodoc_autoattribute",
"tests.test_extensions.test_ext_autodoc_autoclass",
"tests.test_extensions.test_ext_autodoc_autodata",
"tests.test_extensions.test_ext_autodoc_autofunction",
"tests.test_extensions.test_ext_autodoc_automodule",
"tests.test_extensions.test_ext_autodoc_autoproperty",
"tests.test_extensions.test_ext_autodoc_configs",
"tests.test_extensions.test_ext_autodoc_events",
"tests.test_extensions.test_ext_autodoc_mock",
"tests.test_extensions.test_ext_autodoc_preserve_defaults",
"tests.test_extensions.test_ext_autodoc_private_members",
"tests.test_extensions.test_ext_autosectionlabel",
"tests.test_extensions.test_ext_autosummary",
"tests.test_extensions.test_ext_coverage",
"tests.test_extensions.test_ext_doctest",
"tests.test_extensions.test_ext_duration",
"tests.test_extensions.test_extension",
"tests.test_extensions.test_ext_extlinks",
"tests.test_extensions.test_ext_githubpages",
"tests.test_extensions.test_ext_graphviz",
"tests.test_extensions.test_ext_ifconfig",
"tests.test_extensions.test_ext_imgconverter",
"tests.test_extensions.test_ext_imgmockconverter",
"tests.test_extensions.test_ext_inheritance_diagram",
"tests.test_extensions.test_ext_intersphinx",
"tests.test_extensions.test_ext_math",
"tests.test_extensions.test_ext_napoleon",
"tests.test_extensions.test_ext_napoleon_docstring",
"tests.test_extensions.test_ext_todo",
"tests.test_extensions.test_ext_viewcode",
# tests/test_intl
"tests.test_intl.test_catalogs",
"tests.test_intl.test_intl",
"tests.test_intl.test_locale",
# tests/test_markup
"tests.test_markup.test_markup",
"tests.test_markup.test_metadata",
"tests.test_markup.test_parser",
"tests.test_markup.test_smartquotes",
# tests/test_pycode
"tests.test_pycode.test_pycode",
"tests.test_pycode.test_pycode_ast",
"tests.test_pycode.test_pycode_parser",
# tests/test_theming
"tests.test_theming.test_html_theme",
"tests.test_theming.test_templating",
"tests.test_theming.test_theming",
# tests/test_transforms
"tests.test_transforms.test_transforms_move_module_targets",
"tests.test_transforms.test_transforms_post_transforms",
"tests.test_transforms.test_transforms_post_transforms_code",
"tests.test_transforms.test_transforms_reorder_nodes",
# tests/test_util
"tests.test_util.test_util",
"tests.test_util.test_util_display",
"tests.test_util.test_util_docstrings",
"tests.test_util.test_util_docutils",
"tests.test_util.test_util_fileutil",
"tests.test_util.test_util_i18n",
"tests.test_util.test_util_images",
"tests.test_util.test_util_inspect",
"tests.test_util.test_util_inventory",
"tests.test_util.test_util_logging",
"tests.test_util.test_util_matching",
"tests.test_util.test_util_nodes",
"tests.test_util.test_util_rst",
"tests.test_util.test_util_template",
"tests.test_util.test_util_typing",
"tests.test_util.typing_test_data",
# tests/test_writers
"tests.test_writers.test_api_translator",
"tests.test_writers.test_docutilsconf",
"tests.test_writers.test_writer_latex",
]
ignore_errors = true
[tool.pytest.ini_options]
minversion = 6.0
addopts = [

View File

@@ -1,6 +1,9 @@
from __future__ import annotations
import os
import sys
from pathlib import Path
from typing import TYPE_CHECKING
import docutils
import pytest
@@ -10,8 +13,13 @@ import sphinx.locale
import sphinx.pycode
from sphinx.testing.util import _clean_up_global_state
if TYPE_CHECKING:
from collections.abc import Generator
def _init_console(locale_dir=sphinx.locale._LOCALE_DIR, catalog='sphinx'):
def _init_console(
locale_dir: str | None = sphinx.locale._LOCALE_DIR, catalog: str = 'sphinx',
) -> tuple[sphinx.locale.NullTranslations, bool]:
"""Monkeypatch ``init_console`` to skip its action.
Some tests rely on warning messages in English. We don't want
@@ -23,7 +31,7 @@ def _init_console(locale_dir=sphinx.locale._LOCALE_DIR, catalog='sphinx'):
sphinx.locale.init_console = _init_console
pytest_plugins = 'sphinx.testing.fixtures'
pytest_plugins = ['sphinx.testing.fixtures']
# Exclude 'roots' dirs for pytest test collector
collect_ignore = ['roots']
@@ -32,11 +40,11 @@ os.environ['SPHINX_AUTODOC_RELOAD_MODULES'] = '1'
@pytest.fixture(scope='session')
def rootdir():
def rootdir() -> Path:
return Path(__file__).parent.resolve() / 'roots'
def pytest_report_header(config):
def pytest_report_header(config: pytest.Config) -> str:
header = f"libraries: Sphinx-{sphinx.__display_version__}, docutils-{docutils.__version__}"
if hasattr(config, '_tmp_path_factory'):
header += f"\nbase tmp_path: {config._tmp_path_factory.getbasetemp()}"
@@ -44,7 +52,7 @@ def pytest_report_header(config):
@pytest.fixture(autouse=True)
def _cleanup_docutils():
def _cleanup_docutils() -> Generator[None, None, None]:
saved_path = sys.path
yield # run the test
sys.path[:] = saved_path

View File

@@ -6,12 +6,14 @@ import pytest
from html5lib import HTMLParser
if TYPE_CHECKING:
from collections.abc import Callable, Generator
from pathlib import Path
from xml.etree.ElementTree import Element
etree_cache = {}
etree_cache: dict[Path, Element] = {}
def _parse(fname: Path) -> HTMLParser:
def _parse(fname: Path) -> Element:
if fname in etree_cache:
return etree_cache[fname]
with fname.open('rb') as fp:
@@ -21,6 +23,6 @@ def _parse(fname: Path) -> HTMLParser:
@pytest.fixture(scope='package')
def cached_etree_parse():
def cached_etree_parse() -> Generator[Callable[[Path], Element], None, None]:
yield _parse
etree_cache.clear()

View File

@@ -1,54 +1,71 @@
from __future__ import annotations
import contextlib
import http.server
import pathlib
import threading
from http.server import ThreadingHTTPServer
from pathlib import Path
from ssl import PROTOCOL_TLS_SERVER, SSLContext
from threading import Thread
from typing import TYPE_CHECKING, TypeVar
import filelock
if TYPE_CHECKING:
from collections.abc import Callable, Generator
from contextlib import AbstractContextManager
from socketserver import BaseRequestHandler
from typing import Any, Final
# Generated with:
# $ openssl req -new -x509 -days 3650 -nodes -out cert.pem \
# -keyout cert.pem -addext "subjectAltName = DNS:localhost"
TESTS_ROOT = pathlib.Path(__file__).parent
CERT_FILE = str(TESTS_ROOT / "certs" / "cert.pem")
TESTS_ROOT: Final[Path] = Path(__file__).parent
CERT_FILE: Final[str] = str(TESTS_ROOT / "certs" / "cert.pem")
# File lock for tests
LOCK_PATH = str(TESTS_ROOT / 'test-server.lock')
LOCK_PATH: Final[str] = str(TESTS_ROOT / 'test-server.lock')
class HttpServerThread(threading.Thread):
def __init__(self, handler, *args, **kwargs):
class HttpServerThread(Thread):
def __init__(self, handler: type[BaseRequestHandler], /, *args: Any, **kwargs: Any) -> None:
super().__init__(*args, **kwargs)
self.server = http.server.ThreadingHTTPServer(("localhost", 7777), handler)
self.server = ThreadingHTTPServer(("localhost", 7777), handler)
def run(self):
def run(self) -> None:
self.server.serve_forever(poll_interval=0.001)
def terminate(self):
def terminate(self) -> None:
self.server.shutdown()
self.server.server_close()
self.join()
class HttpsServerThread(HttpServerThread):
def __init__(self, handler, *args, **kwargs):
def __init__(
self, handler: type[BaseRequestHandler], /, *args: Any, **kwargs: Any,
) -> None:
super().__init__(handler, *args, **kwargs)
sslcontext = SSLContext(PROTOCOL_TLS_SERVER)
sslcontext.load_cert_chain(CERT_FILE)
self.server.socket = sslcontext.wrap_socket(self.server.socket, server_side=True)
def create_server(thread_class):
def server(handler):
_T_co = TypeVar('_T_co', bound=HttpServerThread, covariant=True)
def create_server(
server_thread_class: type[_T_co],
) -> Callable[[type[BaseRequestHandler]], AbstractContextManager[_T_co]]:
@contextlib.contextmanager
def server(handler_class: type[BaseRequestHandler]) -> Generator[_T_co, None, None]:
lock = filelock.FileLock(LOCK_PATH)
with lock:
server_thread = thread_class(handler, daemon=True)
server_thread = server_thread_class(handler_class, daemon=True)
server_thread.start()
try:
yield server_thread
finally:
server_thread.terminate()
return contextlib.contextmanager(server)
return server
http_server = create_server(HttpServerThread)