• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

pantsbuild / pants / 18517631058

15 Oct 2025 04:18AM UTC coverage: 69.207% (-11.1%) from 80.267%
18517631058

Pull #22745

github

web-flow
Merge 642a76ca1 into 99919310e
Pull Request #22745: [windows] Add windows support in the stdio crate.

53815 of 77759 relevant lines covered (69.21%)

2.42 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

76.92
/src/python/pants/backend/python/providers/pyenv/rules_integration_test.py
1
# Copyright 2023 Pants project contributors (see CONTRIBUTORS.md).
2
# Licensed under the Apache License, Version 2.0 (see LICENSE).
3

4
from __future__ import annotations
2✔
5

6
import shutil
2✔
7
from textwrap import dedent
2✔
8

9
import pytest
2✔
10

11
from pants.backend.python import target_types_rules
2✔
12
from pants.backend.python.dependency_inference import rules as dependency_inference_rules
2✔
13
from pants.backend.python.goals.run_python_source import PythonSourceFieldSet
2✔
14
from pants.backend.python.goals.run_python_source import rules as run_rules
2✔
15
from pants.backend.python.providers.pyenv.rules import rules as pyenv_rules
2✔
16
from pants.backend.python.target_types import PythonSourcesGeneratorTarget
2✔
17
from pants.build_graph.address import Address
2✔
18
from pants.core.goals.run import RunRequest
2✔
19
from pants.engine.internals.scheduler import ExecutionError
2✔
20
from pants.engine.process import InteractiveProcess
2✔
21
from pants.engine.rules import QueryRule
2✔
22
from pants.engine.target import Target
2✔
23
from pants.testutil.rule_runner import RuleRunner, mock_console
2✔
24

25

26
@pytest.fixture
2✔
27
def rule_runner() -> RuleRunner:
2✔
28
    return RuleRunner(
2✔
29
        rules=[
30
            *run_rules(),
31
            *pyenv_rules(),
32
            *dependency_inference_rules.rules(),
33
            *target_types_rules.rules(),
34
            QueryRule(RunRequest, (PythonSourceFieldSet,)),
35
        ],
36
        target_types=[
37
            PythonSourcesGeneratorTarget,
38
        ],
39
    )
40

41

42
def run_run_request(
2✔
43
    rule_runner: RuleRunner,
44
    target: Target,
45
) -> str:
46
    args = [
2✔
47
        "--backend-packages=['pants.backend.python', 'pants.backend.python.providers.experimental.pyenv']",
48
        "--source-root-patterns=['src']",
49
        "--pyenv-python-provider-installation-extra-env-vars=['HOME']",
50
    ]
51
    rule_runner.set_options(args, env_inherit={"PATH", "PYENV_ROOT", "HOME"})
2✔
52
    run_request = rule_runner.request(RunRequest, [PythonSourceFieldSet.create(target)])
2✔
53
    run_process = InteractiveProcess(
2✔
54
        argv=run_request.args,
55
        env=run_request.extra_env,
56
        input_digest=run_request.digest,
57
        run_in_workspace=True,
58
        immutable_input_digests=run_request.immutable_input_digests,
59
        append_only_caches=run_request.append_only_caches,
60
    )
61
    with mock_console(rule_runner.options_bootstrapper) as mocked_console:
2✔
62
        rule_runner.run_interactive_process(run_process)
2✔
63
        return mocked_console[1].get_stdout().strip()
2✔
64

65

66
@pytest.mark.platform_specific_behavior
2✔
67
@pytest.mark.parametrize(
2✔
68
    "interpreter_constraints, expected_version_substring",
69
    [("2.7.*", "2.7"), ("3.9.*", "3.9"), ("3.10.4", "3.10.4")],
70
)
71
def test_using_pyenv(rule_runner, interpreter_constraints, expected_version_substring):
2✔
72
    rule_runner.write_files(
2✔
73
        {
74
            "src/app.py": dedent(
75
                """\
76
                import os.path
77
                import sys
78
                import sysconfig
79

80
                print(sysconfig.get_config_var("prefix"))
81
                print(sys.version.replace("\\n", " "))
82
                """
83
            ),
84
            "src/BUILD": f"python_sources(interpreter_constraints=['=={interpreter_constraints}'])",
85
        }
86
    )
87

88
    target = rule_runner.get_target(Address("src", relative_file_path="app.py"))
2✔
89
    stdout = run_run_request(rule_runner, target)
2✔
90
    named_caches_dir = (
2✔
91
        rule_runner.options_bootstrapper.bootstrap_options.for_global_scope().named_caches_dir
92
    )
93
    prefix_dir, version = stdout.splitlines()
2✔
94
    assert prefix_dir.startswith(f"{named_caches_dir}/pyenv")
2✔
95
    assert expected_version_substring in version
2✔
96

97

98
def test_venv_pex_reconstruction(rule_runner):
2✔
99
    """A VenvPex refers to the location of the venv so it doesn't have to re-construct if it exists.
100

101
    Part of this location is a hash of the interpreter. Without careful consideration it can be easy
102
    for this hash to drift from build-time to run-time. This test validates the assumption that the
103
    venv could be reconstructed exactly if the underlying directory was wiped clean.
104
    """
105
    rule_runner.write_files(
×
106
        {
107
            "src/app.py": dedent(
108
                """\
109
                import pathlib
110
                import sys
111

112
                in_venv_python_path = pathlib.Path(sys.executable)
113
                venv_link = in_venv_python_path.parent.parent
114
                venv_location = venv_link.resolve()
115
                print(venv_location)
116
                """
117
            ),
118
            "src/BUILD": "python_sources(interpreter_constraints=['==3.9.*'])",
119
        }
120
    )
121

122
    target = rule_runner.get_target(Address("src", relative_file_path="app.py"))
×
123
    stdout1 = run_run_request(rule_runner, target)
×
124
    assert "pex_root/venvs/" in stdout1
×
125
    venv_location = stdout1
×
126
    shutil.rmtree(venv_location)
×
127
    stdout2 = run_run_request(rule_runner, target)
×
128
    assert stdout1 == stdout2
×
129

130

131
def test_using_pyenv_with_incompatible_interpreter_constraints(rule_runner):
2✔
132
    rule_runner.write_files(
×
133
        {
134
            "src/app.py": "",
135
            # 3.7.17 was the final release in the 3.7 series:
136
            # https://peps.python.org/pep-0537/#schedule-last-security-only-release
137
            "src/BUILD": "python_sources(interpreter_constraints=['==3.7.20'])",
138
        }
139
    )
140

141
    target = rule_runner.get_target(Address("src", relative_file_path="app.py"))
×
142
    with pytest.raises(
×
143
        ExecutionError,
144
        match=r"(?si)couldn't find a Python 3.7 .* compatible with .* CPython==3.7.20 .*latest known version 3.7.1[0-9].* Suggestion: .*",
145
    ):
146
        run_run_request(rule_runner, target)
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc