Ejemplo n.º 1
0
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)
Ejemplo n.º 2
0
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
Ejemplo n.º 3
0
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)
Ejemplo n.º 4
0
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)
Ejemplo n.º 5
0
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