예제 #1
0
def test_warning_filter() -> None:
    # We load the testprojects pants-plugins to get some testing tasks and subsystems.
    cmdline = [
        "--no-pantsd",
        f"--pythonpath=+['{Path(get_buildroot(), 'testprojects/pants-plugins/src/python')}']",
        "--backend-packages=+['test_pants_plugin']",
        # This task will always emit a DeprecationWarning.
        "deprecation-warning",
    ]

    warning_run = run_pants(cmdline)
    warning_run.assert_success()
    assert bool(
        re.search(
            r"\[WARN\].*DeprecationWarning: DEPRECATED: This is a test warning!", warning_run.stderr
        )
    )

    non_warning_run = run_pants(
        cmdline,
        config={
            GLOBAL_SCOPE_CONFIG_SECTION: {
                # NB: We do *not* include the exclamation point at the end, which tests that the
                # regexps match from the beginning of the warning string, and don't require
                # matching the entire string! We also lowercase the message to check that they are
                # matched case-insensitively.
                "ignore_pants_warnings": ["deprecated: this is a test warning"]
            },
        },
    )
    non_warning_run.assert_success()
    assert "test warning" not in non_warning_run.stderr
예제 #2
0
def assert_backends_load(backends: List[str]) -> None:
    run_pants(["--no-verify-config", "help-all"],
              config={
                  "GLOBAL": {
                      "backend_packages": backends
                  }
              }).assert_success(f"Failed to load: {backends}")
예제 #3
0
def test_invalid_options() -> None:
    config = {
        "DEFAULT": {
            "some_ludicrous_thing": 123
        },
        "GLOBAL": {
            "backend_packages": ["pants.backend.python"],
            "invalid_global": True
        },
        "invalid_scope": {
            "foo": "bar"
        },
        "pytest": {
            "bad_option": True
        },
    }
    config_errors = [
        "ERROR] Invalid option 'invalid_global' under [GLOBAL]",
        "ERROR] Invalid scope [invalid_scope]",
        "ERROR] Invalid option 'bad_option' under [pytest]",
    ]

    # We error on invalid CLI options before validating the config file.
    result = run_pants(["--pytest-invalid=ALL", "help"], config=config)
    result.assert_failure()
    assert "Unknown flags --invalid on scope pytest" in result.stderr
    for error in config_errors:
        assert error not in result.stderr

    result = run_pants(["help"], config=config)
    result.assert_failure()
    assert "Unknown flags" not in result.stderr
    for error in config_errors:
        assert error in result.stderr
예제 #4
0
def test_no_leak_pex_root_issues_12055() -> None:
    read_config_result = run_pants(["help-all"])
    read_config_result.assert_success()
    config_data = json.loads(read_config_result.stdout)
    global_advanced_options = {
        option["config_key"]: [
            ranked_value["value"]
            for ranked_value in option["value_history"]["ranked_values"]
        ][-1]
        for option in config_data["scope_to_help_info"][""]["advanced"]
    }
    named_caches_dir = global_advanced_options["named_caches_dir"]

    sources = {
        "src/app.py":
        "import os; print(os.environ['PEX_ROOT'])",
        "src/BUILD":
        dedent("""\
            python_sources(name="lib")
            pex_binary(entry_point="app.py")
            """),
    }
    with setup_tmpdir(sources) as tmpdir:
        args = [
            "--backend-packages=pants.backend.python",
            f"--source-root-patterns=['/{tmpdir}/src']",
            "run",
            f"{tmpdir}/src/app.py",
        ]
        result = run_pants(args)
        result.assert_success()
        assert os.path.join(named_caches_dir,
                            "pex_root") == result.stdout.strip()
예제 #5
0
def test_export() -> None:
    with setup_tmpdir(SOURCES) as tmpdir:
        run_pants(["generate-lockfiles", "export", f"{tmpdir}/::"],
                  config=build_config(tmpdir)).assert_success()

    export_prefix = os.path.join("dist", "export", "python", "virtualenvs")
    py_minor_version = f"{platform.python_version_tuple()[0]}.{platform.python_version_tuple()[1]}"
    for resolve, ansicolors_version in [("a", "1.1.8"), ("b", "1.0.2")]:
        export_dir = os.path.join(export_prefix, resolve,
                                  platform.python_version())
        assert os.path.isdir(
            export_dir), f"expected export dir '{export_dir}' does not exist"

        lib_dir = os.path.join(export_dir, "lib", f"python{py_minor_version}",
                               "site-packages")
        expected_ansicolors_dir = os.path.join(
            lib_dir, f"ansicolors-{ansicolors_version}.dist-info")
        assert os.path.isdir(
            expected_ansicolors_dir
        ), f"expected dist-info for ansicolors '{expected_ansicolors_dir}' does not exist"

    for tool_config in EXPORTED_TOOLS:
        export_dir = os.path.join(export_prefix, "tools", tool_config.name)
        assert os.path.isdir(
            export_dir), f"expected export dir '{export_dir}' does not exist"

        # NOTE: Not every tool implements --version so this is the best we can do.
        lib_dir = os.path.join(export_dir, "lib", f"python{py_minor_version}",
                               "site-packages")
        expected_tool_dir = os.path.join(
            lib_dir, f"{tool_config.name}-{tool_config.version}.dist-info")
        assert os.path.isdir(
            expected_tool_dir
        ), f"expected dist-info for {tool_config.name} '{expected_tool_dir}' does not exist"
예제 #6
0
def test_generate_lockfile_without_python_backend() -> None:
    """Regression test for https://github.com/pantsbuild/pants/issues/14876."""
    run_pants([
        "--backend-packages=pants.backend.docker",
        "--dockerfile-parser-lockfile=dp.lock",
        "generate-lockfiles",
        "--resolve=dockerfile-parser",
    ]).assert_success()
예제 #7
0
def test_build_ignore_list() -> None:
    with setup_tmpdir({"dir/BUILD": "files(sources=[])"}) as tmpdir:
        ignore_result = run_pants([f"--build-ignore={tmpdir}/dir", "list", f"{tmpdir}/dir"])
        no_ignore_result = run_pants(["list", f"{tmpdir}/dir"])
    ignore_result.assert_failure()
    assert f"{tmpdir}/dir" in ignore_result.stderr
    no_ignore_result.assert_success()
    assert f"{tmpdir}/dir" in no_ignore_result.stdout
예제 #8
0
 def run() -> None:
     run_pants(
         [
             "--backend-packages=['pants.backend.python', 'pants.backend.python.lint.black']",
             "fmt",
             f,
         ],
         use_pantsd=use_pantsd,
     ).assert_success()
예제 #9
0
def test_generate_lockfile_without_python_backend() -> None:
    """Regression test for https://github.com/pantsbuild/pants/issues/14876."""
    run_pants(
        [
            "--backend-packages=pants.backend.experimental.cc.lint.clangformat",
            "--clang-format-lockfile=cf.lock",
            "generate-lockfiles",
            "--resolve=clang-format",
        ]
    ).assert_success()
예제 #10
0
def test_deprecation_and_ignore_warnings(use_pantsd: bool) -> None:
    plugin = dedent("""\
        from pants.option.subsystem import Subsystem
        from pants.engine.rules import SubsystemRule

        class Options(Subsystem):
            help = "Options just for a test."
            options_scope = "mock-options"

            @classmethod
            def register_options(cls, register):
                super().register_options(register)
                register(
                    "--deprecated",
                    removal_version="999.99.9.dev0",
                    removal_hint="blah",
                )

        def rules():
            return [SubsystemRule(Options)]
        """)
    with setup_tmpdir({
            "plugins/mock_options/register.py": plugin,
            "BUILD": "files(name='t', sources=['fake'])",
    }) as tmpdir:
        config = {
            "GLOBAL": {
                "pythonpath": [f"%(buildroot)s/{tmpdir}/plugins"],
                "backend_packages": ["mock_options"],
            },
            "mock-options": {
                "deprecated": "foo"
            },
        }
        unmatched_glob_warning = f"Unmatched glob from {tmpdir}:t's `sources` field"

        result = run_pants(["filedeps", f"{tmpdir}:t"],
                           config=config,
                           use_pantsd=use_pantsd)
        result.assert_success()
        assert unmatched_glob_warning in result.stderr
        assert (
            "DEPRECATED: option 'deprecated' in scope 'mock-options' will be removed in version "
            "999.99.9.dev0.") in result.stderr

        config["GLOBAL"]["ignore_warnings"] = [  # type: ignore[index]
            unmatched_glob_warning,
            "$regex$DeprecationWarning: DEPRECATED: option 'de.+ted'",
        ]
        ignore_result = run_pants(["filedeps", f"{tmpdir}:t"],
                                  config=config,
                                  use_pantsd=use_pantsd)
        ignore_result.assert_success()
        assert unmatched_glob_warning not in ignore_result.stderr
        assert "DEPRECATED: option 'another_deprecated'" not in ignore_result.stderr
예제 #11
0
def test_unimplemented_goals_noop() -> None:
    # Running on a `files` target should usually fail, but it should no-op if no `run`
    # implementations are activated.
    with setup_tmpdir({
            "bad.txt": "",
            "BUILD": "files(sources=['f.txt')"
    }) as tmpdir:
        run_pants(["run", tmpdir]).assert_success()
        run_pants(
            ["--backend-packages=['pants.backend.python']", "run",
             tmpdir]).assert_failure()
예제 #12
0
def test_visualize_to():
    # Tests usage of the `--engine-visualize-to=` option, which triggers background
    # visualization of the graph. There are unit tests confirming the content of the rendered
    # results.
    with temporary_dir(root_dir=os.getcwd()) as destdir:
        run_pants([
            f"--engine-visualize-to={destdir}",
            "--backend-packages=pants.backend.python",
            "list",
            "testprojects/src/python/hello/greet",
        ]).assert_success()
        destdir_files = list(Path(destdir).iterdir())
        assert len(destdir_files) > 0
예제 #13
0
def test_native_logging() -> None:
    expected_msg = r"\[DEBUG\] Launching \d+ root"
    pants_run = run_pants(
        ["-linfo", "--backend-packages=pants.backend.python", "list", "3rdparty::"]
    )
    pants_run.assert_success()
    assert not bool(re.search(expected_msg, pants_run.stderr))

    pants_run = run_pants(
        ["-ldebug", "--backend-packages=pants.backend.python", "list", "3rdparty::"]
    )
    pants_run.assert_success()
    assert bool(re.search(expected_msg, pants_run.stderr))
예제 #14
0
def test_build_ignore_dependency() -> None:
    sources = {
        "dir1/BUILD": "files(sources=[])",
        "dir2/BUILD": "files(sources=[], dependencies=['{tmpdir}/dir1'])",
    }
    with setup_tmpdir(sources) as tmpdir:
        ignore_result = run_pants(
            [f"--build-ignore={tmpdir}/dir1", "dependencies", f"{tmpdir}/dir2"]
        )
        no_ignore_result = run_pants(["dependencies", f"{tmpdir}/dir2"])
    ignore_result.assert_failure()
    assert f"{tmpdir}/dir1" in ignore_result.stderr
    no_ignore_result.assert_success()
    assert f"{tmpdir}/dir1" in no_ignore_result.stdout
def test_native_logging() -> None:
    expected_msg = r"\[DEBUG\] Launching \d+ root"

    with setup_tmpdir({"foo/BUILD": "files(sources=[])"}) as tmpdir:
        pants_run = run_pants(
            ["-linfo", "--backend-packages=pants.backend.python", "list", f"{tmpdir}/foo::"]
        )
        pants_run.assert_success()
        assert not bool(re.search(expected_msg, pants_run.stderr))

        pants_run = run_pants(
            ["-ldebug", "--backend-packages=pants.backend.python", "list", f"{tmpdir}/foo::"]
        )
        pants_run.assert_success()
        assert bool(re.search(expected_msg, pants_run.stderr))
예제 #16
0
def test_warns_on_remote_cache_errors():
    executor = PyExecutor(2, 4)
    builder = PyStubCAS.builder()
    builder.always_errors()
    cas = builder.build(executor)
    address = cas.address()

    pants_run = run_pants(
        [
            "--backend-packages=['pants.backend.python']",
            "--no-dynamic-ui",
            "--level=info",
            "package",
            "testprojects/src/python/hello/main:main",
        ],
        use_pantsd=False,
        config={
            GLOBAL_SCOPE_CONFIG_SECTION: {
                "remote_cache_read": True,
                "remote_cache_write": True,
                "remote_store_server": address,
            }
        },
    )

    pants_run.assert_success()
    assert "Failed to read from remote cache: Unimplemented" in pants_run.stderr
    assert (re.search(
        "Failed to write to remote cache:.*StubCAS is configured to always fail",
        pants_run.stderr,
        re.MULTILINE,
    ) is not None)
예제 #17
0
def test_help_provided_target_plugin_field() -> None:
    pants_run = run_pants([
        "--backend-packages=['pants.backend.python', 'pants.backend.experimental.python']",
        "help",
        "python_distribution",
    ])
    pants_run.assert_success()

    assert (textwrap.dedent(f"""
            `python_distribution` target
            ----------------------------

            A publishable Python setuptools distribution (e.g. an sdist or wheel).

            See {doc_url("python-distributions")}.


            Activated by pants.backend.python
            Valid fields:
            """) in pants_run.stdout)

    assert (textwrap.dedent("""
            skip_twine
                from: pants.backend.experimental.python
                type: bool
                default: False

                If true, don't publish this target's packages using Twine.

            tags
                type: Iterable[str] | None
                default: None

                Arbitrary strings to describe a target.
            """) in pants_run.stdout)
예제 #18
0
def test_global_flag_in_scoped_position() -> None:
    pants_run = run_pants(
        ["test", "--pants-distdir=dist/"],
    )
    pants_run.assert_failure()
    assert "Unknown flag --pants-distdir on test scope" in pants_run.stdout
    assert "Did you mean to use the global --pants-distdir?" in pants_run.stdout
예제 #19
0
def test_native_code() -> None:
    dist_dir = "dist"
    pyver = f"{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}"

    pants_run = run_pants(
        [
            "--backend-packages=pants.backend.python",
            f"--python-setup-interpreter-constraints=['=={pyver}']",
            "package",
            "testprojects/src/python/native:dist",
        ],
        extra_env={"PYTHON": sys.executable},
    )
    pants_run.assert_success()
    wheels = os.listdir(dist_dir)
    assert len(wheels) == 1
    wheel = os.path.join(dist_dir, wheels[0])

    with TemporaryDirectory() as venvdir:
        venv.create(venvdir, with_pip=True, clear=True, symlinks=True)
        subprocess.run([os.path.join(venvdir, "bin", "pip"), "install", wheel],
                       check=True)
        proc = subprocess.run(
            [
                os.path.join(venvdir, "bin", "python"),
                "-c",
                "from native import name; print(name.get_name())",
            ],
            check=True,
            capture_output=True,
        )
        assert proc.stdout == b"Professor Native\n"
예제 #20
0
def test_help_specific_target() -> None:
    pants_run = run_pants(["help", "archive"])
    pants_run.assert_success()

    assert (
        textwrap.dedent(
            """
            archive
            -------

            A ZIP or TAR file containing loose files and code packages.


            Valid fields:
            """
        )
        in pants_run.stdout
    )

    assert (
        textwrap.dedent(
            """
            format
                type: 'tar' | 'tar.bz2' | 'tar.gz' | 'tar.xz' | 'zip'
                required
                The type of archive file to be generated.
            """
        )
        in pants_run.stdout
    )
예제 #21
0
def test_no_strip_pex_env_issues_12057() -> None:
    sources = {
        "src/app.py":
        dedent("""\
            import os
            import sys


            if __name__ == "__main__":
                exit_code = os.environ.get("PANTS_ISSUES_12057")
                if exit_code is None:
                    os.environ["PANTS_ISSUES_12057"] = "42"
                    os.execv(sys.executable, [sys.executable, *sys.argv])
                sys.exit(int(exit_code))
            """),
        "src/BUILD":
        dedent("""\
            python_sources(name="lib")
            pex_binary(entry_point="app.py")
            """),
    }
    with setup_tmpdir(sources) as tmpdir:
        args = [
            "--backend-packages=pants.backend.python",
            f"--source-root-patterns=['/{tmpdir}/src']",
            "run",
            f"{tmpdir}/src/app.py",
        ]
        result = run_pants(args)
        assert result.exit_code == 42, result.stderr
예제 #22
0
def test_goals() -> None:
    pants_run = run_pants(["goals"])
    pants_run.assert_success()
    assert "to get help for a particular goal" in pants_run.stdout
    # Spot check a few core goals.
    for goal in ["filedeps", "list", "roots", "validate"]:
        assert goal in pants_run.stdout
예제 #23
0
def test_pants_bin_name(use_pantsd) -> None:
    pants_run = run_pants(
        ["--pants-bin-name='./pantsV2'", "help", "target"],
        use_pantsd=use_pantsd,
    )
    pants_run.assert_success()
    assert "Use `'./pantsV2' list --documented ::`" in pants_run.stdout
예제 #24
0
def test_mypyc_build() -> None:
    dist_dir = "dist"
    pyver = f"{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}"

    pants_run = run_pants(
        [
            "--backend-packages=['pants.backend.python','pants.backend.python.typecheck.mypy']",
            f"--python-interpreter-constraints=['=={pyver}']",
            "package",
            "testprojects/src/python/mypyc_fib:dist",
        ],
        extra_env={"PYTHON": sys.executable},
    )
    pants_run.assert_success()
    wheels = os.listdir(dist_dir)
    assert len(wheels) == 1
    wheel = os.path.join(dist_dir, wheels[0])

    with TemporaryDirectory() as venvdir:
        venv.create(venvdir, with_pip=True, clear=True, symlinks=True)
        subprocess.run([os.path.join(venvdir, "bin", "pip"), "install", wheel],
                       check=True)
        proc = subprocess.run(
            [
                os.path.join(venvdir, "bin", "python"),
                "-c",
                "import mypyc_fib.fib",
            ],
            check=True,
            capture_output=True,
        )
        assert proc.stdout.splitlines(keepends=False)[0] == b"compiled"
예제 #25
0
def test_invalid_locale() -> None:
    pants_run = run_pants(
        command=["help"], extra_env={"LC_ALL": "iNvALiD-lOcALe", "PYTHONUTF8": "0"}
    )

    pants_run.assert_failure()
    assert "Pants requires" in pants_run.stderr
    assert IGNORE_UNRECOGNIZED_ENCODING in pants_run.stderr
    run_pants(
        command=["help"],
        extra_env={
            "LC_ALL": "iNvALiD-lOcALe",
            "PYTHONUTF8": "0",
            IGNORE_UNRECOGNIZED_ENCODING: "1",
        },
    ).assert_success()
 def run(behavior: RemoteCacheWarningsBehavior) -> str:
     pants_run = run_pants(
         [
             "--backend-packages=['pants.backend.python']",
             "--no-dynamic-ui",
             "package",
             "testprojects/src/python/hello/main:main",
         ],
         use_pantsd=False,
         config={
             GLOBAL_SCOPE_CONFIG_SECTION: {
                 "remote_cache_read":
                 True,
                 "remote_cache_write":
                 True,
                 "remote_cache_warnings":
                 behavior.value,
                 # NB: Our options code expects `grpc://`, which it will then convert back to
                 # `http://` before sending over FFI.
                 "remote_store_address":
                 cas.address.replace("http://", "grpc://"),
             }
         },
     )
     pants_run.assert_success()
     return pants_run.stderr
예제 #27
0
def test_help() -> None:
    pants_run = run_pants(["help"])
    pants_run.assert_success()
    assert "Usage:" in pants_run.stdout
    # spot check to see that a public global option is printed
    assert "--level" in pants_run.stdout
    assert "Global options" in pants_run.stdout
예제 #28
0
def test_missing_sources_warnings():
    target_to_unmatched_globs = {
        "missing-globs": ["*.a"],
        "missing-rglobs": ["**/*.a"],
        "missing-literal-files":
        ["another_nonexistent_file.txt", "nonexistent_test_file.txt"],
    }
    with setup_sources_targets():
        for target in target_to_unmatched_globs:
            target_full = f"{_SOURCES_TARGET_BASE}:{target}"
            pants_run = run_pants(
                ["filedeps", target_full],
                config={
                    GLOBAL_SCOPE_CONFIG_SECTION: {
                        "files_not_found_behavior": "warn"
                    }
                },
            )
            pants_run.assert_success()
            unmatched_globs = target_to_unmatched_globs[target]
            formatted_globs = ", ".join(
                f'"{os.path.join(_SOURCES_TARGET_BASE, glob)}"'
                for glob in unmatched_globs)
            error_origin = f"from {_SOURCES_TARGET_BASE}:{target}'s `sources` field"
            if len(unmatched_globs) == 1:
                assert (
                    f"[WARN] Unmatched glob {error_origin}: {formatted_globs}"
                    in pants_run.stderr)
            else:
                assert (
                    f"[WARN] Unmatched globs {error_origin}: [{formatted_globs}]"
                    in pants_run.stderr)
예제 #29
0
def test_help_goals() -> None:
    pants_run = run_pants(["help", "goals"])
    pants_run.assert_success()
    assert "to get help for a specific goal" in pants_run.stdout
    # Spot check a few core goals.
    for goal in ["filedeps", "list", "roots"]:
        assert goal in pants_run.stdout
예제 #30
0
def test_alternate_entrypoint_not_callable() -> None:
    pants_run = run_pants(
        command=["help"],
        extra_env={"PANTS_ENTRYPOINT": "pants.bin.pants_exe:TEST_STR"})
    pants_run.assert_failure()
    assert "TEST_STR" in pants_run.stderr
    assert "not callable" in pants_run.stderr