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

pantsbuild / pants / 25405422172

05 May 2026 10:18PM UTC coverage: 92.879% (-0.07%) from 92.944%
25405422172

Pull #23319

github

web-flow
Merge c82d0f333 into e8b784f89
Pull Request #23319: [pants_ng] Scaffolding for a pants_ng mode.

25 of 76 new or added lines in 9 files covered. (32.89%)

209 existing lines in 15 files now uncovered.

92234 of 99306 relevant lines covered (92.88%)

4.05 hits per line

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

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

4

5
import importlib
×
6
import locale
×
NEW
7
import logging
×
8
import os
×
9
import sys
×
10
import time
×
11
import warnings
×
NEW
12
from datetime import datetime
×
13

14
from pants.base.exiter import PANTS_FAILED_EXIT_CODE
×
15
from pants.bin.pants_env_vars import (
×
16
    DAEMON_ENTRYPOINT,
17
    IGNORE_UNRECOGNIZED_ENCODING,
18
    RECURSION_LIMIT,
19
)
20
from pants.bin.pants_runner import PantsRunner
×
21
from pants.engine.internals import native_engine
×
22
from pants.util.strutil import softwrap
×
23

24
# pants: infer-dep(/src/python/pants/backend/**/register.py)
25
# pants: infer-dep(/src/python/pants/core/**/*)
26

27

28
class PantsLoader:
×
29
    """Initial entrypoint for pants.
30

31
    Executes a pants_runner by default, or executes a pantsd-specific entrypoint.
32
    """
33

34
    @staticmethod
×
35
    def setup_warnings() -> None:
×
36
        # We want to present warnings to the user, set this up before importing any of our own code,
37
        # to ensure all deprecation warnings are seen, including module deprecations.
38
        # The "default" action displays a warning for a particular file and line number exactly once.
39
        # See https://docs.python.org/3/library/warnings.html#the-warnings-filter for the complete list.
40
        #
41
        # However, we do turn off deprecation warnings for libraries that Pants uses for which we do
42
        # not have a fixed upstream version, typically because the library is no longer maintained.
43
        warnings.simplefilter("default", category=DeprecationWarning)
×
44
        # TODO: Eric-Arellano has emailed the author to see if he is willing to accept a PR fixing the
45
        # deprecation warnings and to release the fix. If he says yes, remove this once fixed.
46
        warnings.filterwarnings("ignore", category=DeprecationWarning, module="ansicolors")
×
47
        # Silence ctypes _pack_/_layout_ warning from HdrHistogram; due by Python 3.19
48
        # See: https://github.com/HdrHistogram/HdrHistogram/issues/216
49
        warnings.filterwarnings(
×
50
            "ignore",
51
            category=DeprecationWarning,
52
            message=r"Due to '_pack_', the '.+' Structure will use memory layout compatible with MSVC",
53
        )
54
        # Silence this ubiquitous warning. Several of our 3rd party deps incur this.
55
        warnings.filterwarnings(
×
56
            "ignore",
57
            category=DeprecationWarning,
58
            message="Using or importing the ABCs from 'collections' instead of from 'collections.abc' is deprecated",
59
        )
60

61
    @classmethod
×
62
    def ensure_locale(cls) -> None:
×
63
        """Ensure the locale uses UTF-8 encoding, or prompt for an explicit bypass."""
64

65
        encoding = locale.getpreferredencoding()
×
66
        if (
×
67
            encoding.lower() != "utf-8"
68
            and os.environ.get(IGNORE_UNRECOGNIZED_ENCODING, None) is None
69
        ):
70
            raise RuntimeError(
×
71
                softwrap(
72
                    f"""
73
                    Your system's preferred encoding is `{encoding}`, but Pants requires `UTF-8`.
74
                    Specifically, Python's `locale.getpreferredencoding()` must resolve to `UTF-8`.
75

76
                    You can fix this by setting the LC_* and LANG environment variables, e.g.:
77
                      LC_ALL=en_US.UTF-8
78
                      LANG=en_US.UTF-8
79
                    Or, bypass it by setting {IGNORE_UNRECOGNIZED_ENCODING}=1. Note that
80
                    pants may exhibit inconsistent behavior if this check is bypassed.
81
                    """
82
                )
83
            )
84

85
    @staticmethod
×
86
    def sandboxer_bin() -> str | None:
×
87
        # In theory as_file could return a temporary file and clean it up, so we'd be returning
88
        # an invalid path. But in practice we know that we're running either in a venv with all
89
        # resources expanded on disk, or from sources, and either way we will get a persistent
90
        # valid path that will not be cleaned up.
91
        with importlib.resources.as_file(
×
92
            importlib.resources.files("pants.bin").joinpath("sandboxer")
93
        ) as sandboxer_bin:
94
            if os.path.isfile(sandboxer_bin):
×
95
                os.chmod(sandboxer_bin, 0o755)
×
96
                return str(sandboxer_bin)
×
97
        return None
×
98

99
    @staticmethod
×
100
    def run_alternate_entrypoint(entrypoint: str) -> None:
×
101
        try:
×
102
            module_path, func_name = entrypoint.split(":", 1)
×
103
        except ValueError:
×
104
            print(
×
105
                f"{DAEMON_ENTRYPOINT} must be of the form `module.path:callable`", file=sys.stderr
106
            )
107
            sys.exit(PANTS_FAILED_EXIT_CODE)
×
108

109
        module = importlib.import_module(module_path)
×
110
        entrypoint_fn = getattr(module, func_name)
×
111
        entrypoint_fn()
×
112

113
    @staticmethod
×
114
    def run_default_entrypoint() -> None:
×
115
        start_time = time.time()
×
116
        try:
×
117
            runner = PantsRunner(args=sys.argv, env=os.environ)
×
118
            exit_code = runner.run(start_time)
×
119
        except KeyboardInterrupt as e:
×
120
            print(f"Interrupted by user:\n{e}", file=sys.stderr)
×
121
            exit_code = PANTS_FAILED_EXIT_CODE
×
122
        sys.exit(exit_code)
×
123

124
    @classmethod
×
125
    def main(cls) -> None:
×
126
        # Set up logging. This is just temporary, as the PantsRunner will re-initialize logging to
127
        # be emitted via Rust, but until that happens we want basic logging to do something useful.
128
        # We set it up to be visually compatible with the Rust logging.
NEW
129
        class HundredthsFormatter(logging.Formatter):
×
NEW
130
            def formatTime(self, record, datefmt=None):
×
NEW
131
                dt = datetime.fromtimestamp(record.created)
×
NEW
132
                formatted_time = dt.strftime(datefmt or "%H:%M:%S")
×
NEW
133
                hundredths = str(dt.microsecond // 10000).zfill(2)
×
NEW
134
                return f"{formatted_time}.{hundredths}"
×
135

NEW
136
        handler = logging.StreamHandler()
×
NEW
137
        handler.setFormatter(HundredthsFormatter(fmt="%(asctime)s [%(levelname)s] %(message)s"))
×
NEW
138
        logging.basicConfig(level=logging.INFO, handlers=[handler])
×
139

140
        native_engine.initialize()
×
141
        cls.setup_warnings()
×
142
        cls.ensure_locale()
×
143

144
        sys.setrecursionlimit(int(os.environ.get(RECURSION_LIMIT, "10000")))
×
145

146
        os.environ["PANTS_SANDBOXER_BINARY_PATH"] = cls.sandboxer_bin() or ""
×
147
        entrypoint = os.environ.pop(DAEMON_ENTRYPOINT, None)
×
148
        if entrypoint:
×
149
            cls.run_alternate_entrypoint(entrypoint)
×
150
        else:
151
            cls.run_default_entrypoint()
×
152

153

154
def main() -> None:
×
155
    PantsLoader.main()
×
156

157

158
if __name__ == "__main__":
×
159
    main()
×
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

© 2026 Coveralls, Inc