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

pantsbuild / pants / 19015773527

02 Nov 2025 05:33PM UTC coverage: 17.872% (-62.4%) from 80.3%
19015773527

Pull #22816

github

web-flow
Merge a12d75757 into 6c024e162
Pull Request #22816: Update Pants internal Python to 3.14

4 of 5 new or added lines in 3 files covered. (80.0%)

28452 existing lines in 683 files now uncovered.

9831 of 55007 relevant lines covered (17.87%)

0.18 hits per line

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

0.0
/src/python/pants/bin/pants_runner.py
1
# Copyright 2015 Pants project contributors (see CONTRIBUTORS.md).
2
# Licensed under the Apache License, Version 2.0 (see LICENSE).
3

4
import logging
×
5
import os
×
6
import platform
×
7
import sys
×
8
import warnings
×
9
from collections.abc import Mapping
×
10
from dataclasses import dataclass
×
11

12
from packaging.version import Version
×
13

14
from pants.base.deprecated import warn_or_error
×
15
from pants.base.exception_sink import ExceptionSink
×
16
from pants.base.exiter import ExitCode
×
17
from pants.engine.env_vars import CompleteEnvironmentVars
×
18
from pants.init.logging import initialize_stdio, stdio_destination
×
19
from pants.init.util import init_workdir
×
20
from pants.option.option_value_container import OptionValueContainer
×
21
from pants.option.options_bootstrapper import OptionsBootstrapper
×
22
from pants.util.docutil import doc_url
×
23
from pants.util.osutil import get_normalized_arch_name, macos_major_version
×
24
from pants.util.strutil import softwrap
×
25

26
logger = logging.getLogger(__name__)
×
27

28
# First version with working Python 3.11 support:
29
# https://github.com/pantsbuild/scie-pants/releases/tag/v0.12.2
30
# TODO: Likely still need to update scie-pants
UNCOV
31
MINIMUM_SCIE_PANTS_VERSION = Version("0.12.2")
×
32

33

34
@dataclass(frozen=True)
×
35
class PantsRunner:
×
36
    """A higher-level runner that delegates runs to either a LocalPantsRunner or
37
    RemotePantsRunner."""
38

39
    args: list[str]
40
    env: Mapping[str, str]
41

42
    # This could be a bootstrap option, but it's preferable to keep these very limited to make it
43
    # easier to make the daemon the default use case. Once the daemon lifecycle is stable enough we
44
    # should be able to avoid needing to kill it at all.
45
    def will_terminate_pantsd(self) -> bool:
×
46
        _DAEMON_KILLING_GOALS = frozenset(["kill-pantsd", "clean-all"])
×
47
        return not frozenset(self.args).isdisjoint(_DAEMON_KILLING_GOALS)
×
48

49
    def _should_run_with_pantsd(self, global_bootstrap_options: OptionValueContainer) -> bool:
×
50
        terminate_pantsd = self.will_terminate_pantsd()
×
51

52
        if terminate_pantsd:
×
53
            logger.debug(f"Pantsd terminating goal detected: {self.args}")
×
54

55
        # If we want concurrent pants runs, we can't have pantsd enabled.
56
        return (
×
57
            global_bootstrap_options.pantsd
58
            and not terminate_pantsd
59
            and not global_bootstrap_options.concurrent
60
        )
61

62
    @staticmethod
×
63
    def scrub_pythonpath() -> None:
×
64
        # Do not propagate any PYTHONPATH that happens to have been set in our environment
65
        # to our subprocesses.
66
        # Note that don't warn (but still scrub) if RUNNING_PANTS_FROM_SOURCES is set. This allows
67
        # scripts that run pants directly from sources, and therefore must set PYTHONPATH, to mute
68
        # this warning.
69
        pythonpath = os.environ.pop("PYTHONPATH", None)
×
70
        if pythonpath and not os.environ.pop("RUNNING_PANTS_FROM_SOURCES", None):
×
71
            logger.debug(f"Scrubbed PYTHONPATH={pythonpath} from the environment.")
×
72

73
    def run(self, start_time: float) -> ExitCode:
×
74
        self.scrub_pythonpath()
×
75

76
        options_bootstrapper = OptionsBootstrapper.create(
×
77
            args=self.args, env=self.env, allow_pantsrc=True
78
        )
79
        with warnings.catch_warnings(record=True):
×
80
            bootstrap_options = options_bootstrapper.bootstrap_options
×
81
            global_bootstrap_options = bootstrap_options.for_global_scope()
×
82

83
        # We enable logging here, and everything before it will be routed through regular
84
        # Python logging.
85
        stdin_fileno = sys.stdin.fileno()
×
86
        stdout_fileno = sys.stdout.fileno()
×
87
        stderr_fileno = sys.stderr.fileno()
×
88
        with (
×
89
            initialize_stdio(global_bootstrap_options),
90
            stdio_destination(
91
                stdin_fileno=stdin_fileno,
92
                stdout_fileno=stdout_fileno,
93
                stderr_fileno=stderr_fileno,
94
            ),
95
        ):
96
            run_via_scie = "SCIE" in os.environ
×
97
            enable_scie_warnings = "NO_SCIE_WARNING" not in os.environ
×
98
            scie_pants_version = os.environ.get("SCIE_PANTS_VERSION")
×
99

100
            if enable_scie_warnings:
×
101
                if not run_via_scie:
×
102
                    raise RuntimeError(
×
103
                        softwrap(
104
                            f"""
105
                            The `pants` launcher binary is now the only supported way of running Pants.
106
                            See {doc_url("docs/getting-started/installing-pants")} for details.
107
                            """
108
                        ),
109
                    )
110

111
                if run_via_scie and (
×
112
                    # either scie-pants is too old to communicate its version:
113
                    scie_pants_version is None
114
                    # or the version itself is too old:
115
                    or Version(scie_pants_version) < MINIMUM_SCIE_PANTS_VERSION
116
                ):
117
                    current_version_text = (
×
118
                        f"The current version of the `pants` launcher binary is {scie_pants_version}"
119
                        if scie_pants_version
120
                        else "Run `PANTS_BOOTSTRAP_VERSION=report pants` to see the current version of the `pants` launcher binary"
121
                    )
122
                    warn_or_error(
×
123
                        "2.25.0.dev0",
124
                        f"using a `pants` launcher binary older than {MINIMUM_SCIE_PANTS_VERSION}",
125
                        softwrap(
126
                            f"""
127
                            {current_version_text}, and see {doc_url("docs/getting-started/installing-pants#upgrading-pants")} for how to upgrade.
128
                            """
129
                        ),
130
                    )
131

132
            _validate_macos_version(global_bootstrap_options)
×
133

134
            # N.B. We inline imports to speed up the python thin client run, and avoids importing
135
            # engine types until after the runner has had a chance to set __PANTS_BIN_NAME.
136
            if self._should_run_with_pantsd(global_bootstrap_options):
×
137
                from pants.bin.remote_pants_runner import RemotePantsRunner
×
138

139
                try:
×
140
                    remote_runner = RemotePantsRunner(self.args, self.env, options_bootstrapper)
×
141
                    return remote_runner.run(start_time)
×
142
                except RemotePantsRunner.Fallback as e:
×
143
                    logger.warning(f"Client exception: {e!r}, falling back to non-daemon mode")
×
144

145
            from pants.bin.local_pants_runner import LocalPantsRunner
×
146

147
            # We only install signal handling via ExceptionSink if the run will execute in this process.
148
            ExceptionSink.install(
×
149
                log_location=init_workdir(global_bootstrap_options), pantsd_instance=False
150
            )
151
            runner = LocalPantsRunner.create(
×
152
                env=CompleteEnvironmentVars(self.env),
153
                working_dir=os.getcwd(),
154
                options_bootstrapper=options_bootstrapper,
155
            )
156
            return runner.run(start_time)
×
157

158

159
# for each architecture, indicate the first Pants version that doesn't support the given version of
160
# macOS, if it is (soon to be) unsupported:
161
_MACOS_VERSION_BECOMES_UNSUPPORTED_IN = {
×
162
    # macos-14 is currently oldest github hosted runner for arm
163
    "arm64": {
164
        10: "2.24.0.dev0",
165
        11: "2.24.0.dev0",
166
        12: "2.25.0.dev0",
167
        13: "2.25.0.dev0",
168
        # adding new values here should update the phrasing of the message below
169
    },
170
    # macos-13 will soon be the oldest (and only) github hosted runner for x86-64 (see https://github.com/pantsbuild/pants/issues/21333)
171
    "x86_64": {
172
        10: "2.24.0.dev0",
173
        11: "2.24.0.dev0",
174
        12: "2.25.0.dev0",
175
        # adding new values here should update the phrasing of the message below
176
    },
177
}
178

179

180
def _validate_macos_version(global_bootstrap_options: OptionValueContainer) -> None:
×
181
    """Check for running on deprecated/unsupported versions of macOS, and similar."""
182

183
    macos_version = macos_major_version()
×
184
    if macos_version is None:
×
185
        # Not macOS, no validation/deprecations required!
186
        return
×
187

188
    arch_versions = _MACOS_VERSION_BECOMES_UNSUPPORTED_IN[get_normalized_arch_name()]
×
189
    unsupported_version = arch_versions.get(macos_version)
×
190

191
    is_permitted_deprecated_macos_version = (
×
192
        str(macos_version) in global_bootstrap_options.allow_deprecated_macos_versions
193
    )
194

195
    if unsupported_version is not None and not is_permitted_deprecated_macos_version:
×
196
        warn_or_error(
×
197
            unsupported_version,
198
            "using Pants on older macOS",
199
            softwrap(
200
                f"""
201
                Recent versions of Pants only support macOS 13 and newer (on x86-64) and macOS
202
                14 and newer (on arm64), but this machine appears older ({platform.platform()}
203
                implies macOS version {macos_version}). This version also isn't permitted by your
204
                `[GLOBAL].allow_deprecated_macos_versions` configuration
205
                ({global_bootstrap_options.allow_deprecated_macos_versions}).
206

207
                Either upgrade your operating system(s), or silence this message (and thus opt-in to
208
                potential breakage) by adding "{macos_version}" to the
209
                `[GLOBAL].allow_deprecated_macos_versions` list.
210

211
                If you have questions or concerns about this, please reach out to us at
212
                {doc_url("community/getting-help")}.
213
                """
214
            ),
215
        )
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