Skip to content

Commit 52d0fc4

Browse files
authored
Regression tests: Handle no packages case gracefully (#15933)
Before, when running regression tests for a certain version/platform combination that doesn't have any cases, mypy is run with invalid arguments (no files), and the tests fail. Now, a message is printed instead (unless the verbosity is `QUIET`) and the tests succeed.
1 parent c9e422d commit 52d0fc4

2 files changed

Lines changed: 45 additions & 11 deletions

File tree

lib/ts_utils/utils.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,10 @@ def print_warning(message: str) -> None:
8383
print(colored(message, "yellow"))
8484

8585

86+
def print_skipped(message: str) -> None:
87+
print(colored(message, "yellow"))
88+
89+
8690
def print_error(error: str, end: str = "\n", fix_path: tuple[str, str] = ("", "")) -> None:
8791
error_split = error.split("\n")
8892
old, new = fix_path

tests/regr_test.py

Lines changed: 41 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,15 @@
1313
import sys
1414
import tempfile
1515
import threading
16+
from abc import ABCMeta, abstractmethod
1617
from collections.abc import Callable, Generator
1718
from contextlib import ExitStack, contextmanager, suppress
1819
from dataclasses import dataclass
1920
from enum import IntEnum
2021
from functools import partial
2122
from pathlib import Path
2223
from typing import TypeAlias
24+
from typing_extensions import override
2325

2426
from ts_utils.metadata import get_recursive_requirements, read_metadata
2527
from ts_utils.mypy import mypy_configuration_from_distribution, temporary_mypy_config_file
@@ -33,6 +35,7 @@
3335
get_all_testcase_directories,
3436
get_mypy_req,
3537
print_error,
38+
print_skipped,
3639
venv_python,
3740
)
3841

@@ -167,7 +170,7 @@ def setup_testcase_dir(package: DistributionTests, tempdir: Path, verbosity: Ver
167170

168171
def run_testcases(
169172
package: DistributionTests, version: str, platform: str, *, tempdir: Path, verbosity: Verbosity
170-
) -> subprocess.CompletedProcess[str]:
173+
) -> subprocess.CompletedProcess[str] | None:
171174
env_vars = dict(os.environ)
172175
new_test_case_dir = tempdir / TEST_CASES_DIR
173176

@@ -177,7 +180,6 @@ def run_testcases(
177180
configurations = mypy_configuration_from_distribution(package.name)
178181

179182
with temporary_mypy_config_file(configurations) as temp_config:
180-
181183
# "--enable-error-code ignore-without-code" is purposefully omitted.
182184
# See https://github.com/python/typeshed/pull/8083
183185
flags = [
@@ -216,18 +218,22 @@ def run_testcases(
216218

217219
flags.extend(["--custom-typeshed-dir", str(custom_typeshed)])
218220

219-
# If the test-case filename ends with -py39,
220-
# only run the test if --python-version was set to 3.9 or higher (for example)
221+
# If the test-case filename ends with e.g. -py314,
222+
# only run the test if --python-version was set to 3.14 or higher (for example)
223+
files: list[str] = []
221224
for path in new_test_case_dir.rglob("*.py"):
222-
if match := re.fullmatch(r".*-py3(\d{1,2})", path.stem):
225+
if match := re.fullmatch(r".*-py3(\d\d)", path.stem):
223226
minor_version_required = int(match[1])
224227
assert f"3.{minor_version_required}" in SUPPORTED_VERSIONS
225228
python_minor_version = int(version.split(".")[1])
226229
if minor_version_required > python_minor_version:
227230
continue
228-
flags.append(str(path))
231+
files.append(str(path))
232+
233+
if len(files) == 0:
234+
return None
229235

230-
mypy_command = [python_exe, "-m", "mypy", *flags]
236+
mypy_command = [python_exe, "-m", "mypy", *flags, *files]
231237
if verbosity is Verbosity.VERBOSE:
232238
description = f"{package.name}/{version}/{platform}"
233239
msg = f"{description}: {mypy_command=}\n"
@@ -241,15 +247,24 @@ def run_testcases(
241247

242248

243249
@dataclass(frozen=True)
244-
class Result:
250+
class Result(metaclass=ABCMeta):
245251
code: int
252+
253+
@abstractmethod
254+
def print_description(self, verbosity: Verbosity) -> None:
255+
raise NotImplementedError
256+
257+
258+
@dataclass(frozen=True)
259+
class RunResult(Result):
246260
command_run: str
247261
stderr: str
248262
stdout: str
249263
test_case_dir: Path
250264
tempdir: Path
251265

252-
def print_description(self) -> None:
266+
@override
267+
def print_description(self, verbosity: Verbosity) -> None:
253268
if self.code:
254269
print(f"{self.command_run}:", end=" ")
255270
print_error("FAILURE\n")
@@ -260,6 +275,18 @@ def print_description(self) -> None:
260275
print_error(self.stdout, fix_path=replacements)
261276

262277

278+
@dataclass(frozen=True)
279+
class NoTestsResult(Result):
280+
package: str
281+
version: str
282+
platform: str
283+
284+
@override
285+
def print_description(self, verbosity: Verbosity) -> None:
286+
if verbosity != Verbosity.QUIET:
287+
print_skipped(f"No test cases found for {self.package!r} on Python {self.version} for platform {self.platform!r}.")
288+
289+
263290
def test_testcase_directory(
264291
package: DistributionTests, version: str, platform: str, *, verbosity: Verbosity, tempdir: Path
265292
) -> Result:
@@ -269,7 +296,10 @@ def test_testcase_directory(
269296
_PRINT_QUEUE.put(f"Running {msg}...")
270297

271298
proc_info = run_testcases(package=package, version=version, platform=platform, tempdir=tempdir, verbosity=verbosity)
272-
return Result(
299+
if proc_info is None:
300+
return NoTestsResult(0, package.name, version, platform)
301+
302+
return RunResult(
273303
code=proc_info.returncode,
274304
command_run=msg,
275305
stderr=proc_info.stderr,
@@ -399,7 +429,7 @@ def main() -> ReturnCode:
399429
print()
400430

401431
for result in results:
402-
result.print_description()
432+
result.print_description(verbosity)
403433

404434
code = max(result.code for result in results)
405435

0 commit comments

Comments
 (0)