mirror of
https://github.com/davidhalter/typeshed.git
synced 2026-07-29 11:16:44 +08:00
Apply mypy-tests custom config to other mypy-based tests (#13825)
This commit is contained in:
@@ -166,6 +166,7 @@ _KNOWN_METADATA_FIELDS: Final = frozenset(
|
||||
"tool",
|
||||
"partial_stub",
|
||||
"requires_python",
|
||||
"mypy-tests",
|
||||
}
|
||||
)
|
||||
_KNOWN_METADATA_TOOL_FIELDS: Final = {
|
||||
|
||||
@@ -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
@@ -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
|
||||
# ====================================================================
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user