def test_scripts_directory(code: int, args: TestConfig) -> TestResults: files_to_test = list(Path("scripts").rglob("*.py")) num_test_files_to_test = len(files_to_test) flags = get_mypy_flags(args, None, strict=True, ignore_missing_imports=True) print(f"Testing the scripts directory ({num_test_files_to_test} files)...") print("Running mypy " + " ".join(flags)) if args.dry_run: this_code = 0 else: this_code = run_mypy_as_subprocess("scripts", flags) if not this_code: print_success_msg() code = max(code, this_code) return TestResults(code, num_test_files_to_test)
def run_mypy( args: argparse.Namespace, configurations: list[MypyDistConf], major: int, minor: int, files: list[str], *, custom_typeshed: bool = False, ) -> int: try: from mypy.api import run as mypy_run except ImportError: print_error("Cannot import mypy. Did you install it?") sys.exit(1) with tempfile.NamedTemporaryFile("w+") as temp: temp.write("[mypy]\n") for dist_conf in configurations: temp.write("[mypy-%s]\n" % dist_conf.module_name) for k, v in dist_conf.values.items(): temp.write(f"{k} = {v}\n") temp.flush() flags = get_mypy_flags(args, major, minor, temp.name, custom_typeshed=custom_typeshed) mypy_args = [*flags, *files] if args.verbose: print("running mypy", " ".join(mypy_args)) if args.dry_run: exit_code = 0 else: stdout_redirect, stderr_redirect = StringIO(), StringIO() with redirect_stdout(stdout_redirect), redirect_stderr(stderr_redirect): returned_stdout, returned_stderr, exit_code = mypy_run(mypy_args) if exit_code: print_error("failure\n") captured_stdout = stdout_redirect.getvalue() captured_stderr = stderr_redirect.getvalue() if returned_stderr: print_error(returned_stderr) if captured_stderr: print_error(captured_stderr) if returned_stdout: print_error(returned_stdout) if captured_stdout: print_error(captured_stdout, end="") else: print_success_msg() return exit_code
def test_the_test_scripts(code: int, major: int, minor: int, args: argparse.Namespace) -> TestResults: files_to_test = list(Path("tests").rglob("*.py")) if sys.platform == "win32": files_to_test.remove(Path("tests/pytype_test.py")) num_test_files_to_test = len(files_to_test) flags = get_mypy_flags(args, major, minor, None, strict=True, test_suite_run=True) print(f"Testing the test suite ({num_test_files_to_test} files)...") print("Running mypy " + " ".join(flags)) if args.dry_run: this_code = 0 else: this_code = run_mypy_as_subprocess("tests", flags) if not this_code: print_success_msg() code = max(code, this_code) return TestResults(code, num_test_files_to_test)
def test_the_test_cases(code: int, major: int, minor: int, args: argparse.Namespace) -> TestResults: test_case_files = list(map(str, Path("test_cases").rglob("*.py"))) num_test_case_files = len(test_case_files) flags = get_mypy_flags(args, major, minor, None, strict=True, custom_typeshed=True) print(f"Running mypy on the test_cases directory ({num_test_case_files} files)...") print("Running mypy " + " ".join(flags)) if args.dry_run: this_code = 0 else: # --warn-unused-ignores doesn't work for files inside typeshed. # SO, to work around this, we copy the test_cases directory into a TemporaryDirectory. with tempfile.TemporaryDirectory() as td: shutil.copytree(Path("test_cases"), Path(td) / "test_cases") this_code = run_mypy_as_subprocess(td, flags) if not this_code: print_success_msg() code = max(code, this_code) return TestResults(code, num_test_case_files)
def run_stubtest(dist: Path, *, verbose: bool = False) -> bool: with open(dist / "METADATA.toml") as f: metadata = dict(tomli.loads(f.read())) print(f"{dist.name}... ", end="") stubtest_meta = metadata.get("tool", {}).get("stubtest", {}) if stubtest_meta.get("skip", False): print(colored("skipping", "yellow")) return True with tempfile.TemporaryDirectory() as tmp: venv_dir = Path(tmp) venv.create(venv_dir, with_pip=True, clear=True) pip_exe = str(venv_dir / "bin" / "pip") python_exe = str(venv_dir / "bin" / "python") dist_version = metadata["version"] assert isinstance(dist_version, str) dist_req = f"{dist.name}=={dist_version}" # If @tests/requirements-stubtest.txt exists, run "pip install" on it. req_path = dist / "@tests" / "requirements-stubtest.txt" if req_path.exists(): try: pip_cmd = [pip_exe, "install", "-r", str(req_path)] subprocess.run(pip_cmd, check=True, capture_output=True) except subprocess.CalledProcessError as e: print_command_failure("Failed to install requirements", e) return False # We need stubtest to be able to import the package, so install mypy into the venv # Hopefully mypy continues to not need too many dependencies # TODO: Maybe find a way to cache these in CI dists_to_install = [dist_req, get_mypy_req()] dists_to_install.extend(metadata.get("requires", [])) pip_cmd = [pip_exe, "install"] + dists_to_install try: subprocess.run(pip_cmd, check=True, capture_output=True) except subprocess.CalledProcessError as e: print_command_failure("Failed to install", e) return False ignore_missing_stub = ["--ignore-missing-stub"] if stubtest_meta.get("ignore_missing_stub", True) else [] packages_to_check = [d.name for d in dist.iterdir() if d.is_dir() and d.name.isidentifier()] modules_to_check = [d.stem for d in dist.iterdir() if d.is_file() and d.suffix == ".pyi"] stubtest_cmd = [ python_exe, "-m", "mypy.stubtest", # Use --custom-typeshed-dir in case we make linked changes to stdlib or _typeshed "--custom-typeshed-dir", str(dist.parent.parent), *ignore_missing_stub, *packages_to_check, *modules_to_check, ] allowlist_path = dist / "@tests/stubtest_allowlist.txt" if allowlist_path.exists(): stubtest_cmd.extend(["--allowlist", str(allowlist_path)]) try: subprocess.run(stubtest_cmd, env={"MYPYPATH": str(dist), "MYPY_FORCE_COLOR": "1"}, check=True, capture_output=True) except subprocess.CalledProcessError as e: print_error("fail") print_commands(dist, pip_cmd, stubtest_cmd) print_command_output(e) print("Ran with the following environment:", file=sys.stderr) ret = subprocess.run([pip_exe, "freeze", "--all"], capture_output=True) print_command_output(ret) if allowlist_path.exists(): print( f'To fix "unused allowlist" errors, remove the corresponding entries from {allowlist_path}', file=sys.stderr ) print(file=sys.stderr) else: print(f"Re-running stubtest with --generate-allowlist.\nAdd the following to {allowlist_path}:", file=sys.stderr) ret = subprocess.run(stubtest_cmd + ["--generate-allowlist"], env={"MYPYPATH": str(dist)}, capture_output=True) print_command_output(ret) return False else: print_success_msg() if verbose: print_commands(dist, pip_cmd, stubtest_cmd) return True