Apply mypy-tests custom config to other mypy-based tests (#13825)

This commit is contained in:
Avasam
2025-04-28 12:24:26 +02:00
committed by GitHub
parent 23f94ffbc4
commit 5faa04038b
7 changed files with 269 additions and 220 deletions
+1
View File
@@ -166,6 +166,7 @@ _KNOWN_METADATA_FIELDS: Final = frozenset(
"tool",
"partial_stub",
"requires_python",
"mypy-tests",
}
)
_KNOWN_METADATA_TOOL_FIELDS: Final = {
+64
View File
@@ -0,0 +1,64 @@
from __future__ import annotations
from collections.abc import Generator, Iterable
from contextlib import contextmanager
from typing import Any, NamedTuple
import tomli
from ts_utils.metadata import metadata_path
from ts_utils.utils import NamedTemporaryFile, TemporaryFileWrapper
class MypyDistConf(NamedTuple):
module_name: str
values: dict[str, dict[str, Any]]
# The configuration section in the metadata file looks like the following, with multiple module sections possible
# [mypy-tests]
# [mypy-tests.yaml]
# module_name = "yaml"
# [mypy-tests.yaml.values]
# disallow_incomplete_defs = true
# disallow_untyped_defs = true
def mypy_configuration_from_distribution(distribution: str) -> list[MypyDistConf]:
with metadata_path(distribution).open("rb") as f:
data = tomli.load(f)
# TODO: This could be added to ts_utils.metadata
mypy_tests_conf: dict[str, dict[str, Any]] = data.get("mypy-tests", {})
if not mypy_tests_conf:
return []
def validate_configuration(section_name: str, mypy_section: dict[str, Any]) -> MypyDistConf:
assert isinstance(mypy_section, dict), f"{section_name} should be a section"
module_name = mypy_section.get("module_name")
assert module_name is not None, f"{section_name} should have a module_name key"
assert isinstance(module_name, str), f"{section_name} should be a key-value pair"
assert "values" in mypy_section, f"{section_name} should have a values section"
values: dict[str, dict[str, Any]] = mypy_section["values"]
assert isinstance(values, dict), "values should be a section"
return MypyDistConf(module_name, values.copy())
assert isinstance(mypy_tests_conf, dict), "mypy-tests should be a section"
return [validate_configuration(section_name, mypy_section) for section_name, mypy_section in mypy_tests_conf.items()]
@contextmanager
def temporary_mypy_config_file(configurations: Iterable[MypyDistConf]) -> Generator[TemporaryFileWrapper[str]]:
temp = NamedTemporaryFile("w+")
try:
for dist_conf in configurations:
temp.write(f"[mypy-{dist_conf.module_name}]\n")
for k, v in dist_conf.values.items():
temp.write(f"{k} = {v}\n")
temp.write("[mypy]\n")
temp.flush()
yield temp
finally:
temp.close()
+30 -4
View File
@@ -3,16 +3,24 @@
from __future__ import annotations
import functools
import os
import re
import sys
import tempfile
from collections.abc import Iterable, Mapping
from pathlib import Path
from typing import Any, Final, NamedTuple
from types import MethodType
from typing import TYPE_CHECKING, Any, Final, NamedTuple
from typing_extensions import TypeAlias
import pathspec
from packaging.requirements import Requirement
from .paths import REQUIREMENTS_PATH, STDLIB_PATH, STUBS_PATH, TEST_CASES_DIR, allowlists_path, test_cases_path
if TYPE_CHECKING:
from _typeshed import OpenTextMode
try:
from termcolor import colored as colored # pyright: ignore[reportAssignmentType]
except ImportError:
@@ -21,8 +29,6 @@ except ImportError:
return text
from .paths import REQUIREMENTS_PATH, STDLIB_PATH, STUBS_PATH, TEST_CASES_DIR, allowlists_path, test_cases_path
PYTHON_VERSION: Final = f"{sys.version_info.major}.{sys.version_info.minor}"
@@ -196,6 +202,26 @@ def allowlists(distribution_name: str) -> list[str]:
return ["stubtest_allowlist.txt", platform_allowlist]
# Re-exposing as a public name to avoid many pyright reportPrivateUsage
TemporaryFileWrapper = tempfile._TemporaryFileWrapper # pyright: ignore[reportPrivateUsage]
# We need to work around a limitation of tempfile.NamedTemporaryFile on Windows
# For details, see https://github.com/python/typeshed/pull/13620#discussion_r1990185997
# Python 3.12 added a cross-platform solution with `tempfile.NamedTemporaryFile("w+", delete_on_close=False)`
if sys.platform != "win32":
NamedTemporaryFile = tempfile.NamedTemporaryFile # noqa: TID251
else:
def NamedTemporaryFile(mode: OpenTextMode) -> TemporaryFileWrapper[str]: # noqa: N802
def close(self: TemporaryFileWrapper[str]) -> None:
TemporaryFileWrapper.close(self) # pyright: ignore[reportUnknownMemberType]
os.remove(self.name)
temp = tempfile.NamedTemporaryFile(mode, delete=False) # noqa: SIM115, TID251
temp.close = MethodType(close, temp) # type: ignore[method-assign]
return temp
# ====================================================================
# Parsing .gitignore
# ====================================================================
@@ -215,7 +241,7 @@ def spec_matches_path(spec: pathspec.PathSpec, path: Path) -> bool:
# ====================================================================
# mypy/stubtest call
# stubtest call
# ====================================================================