• 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

55.1
/src/python/pants/option/options_bootstrapper.py
1
# Copyright 2014 Pants project contributors (see CONTRIBUTORS.md).
2
# Licensed under the Apache License, Version 2.0 (see LICENSE).
3

4
from __future__ import annotations
1✔
5

6
from collections.abc import Iterable, Mapping, Sequence
1✔
7
from dataclasses import dataclass
1✔
8
from typing import TYPE_CHECKING
1✔
9

10
from pants.engine.unions import UnionMembership
1✔
11
from pants.option.bootstrap_options import BootstrapOptions
1✔
12
from pants.option.option_types import collect_options_info
1✔
13
from pants.option.options import Options
1✔
14
from pants.option.scope import GLOBAL_SCOPE, ScopeInfo
1✔
15
from pants.util.frozendict import FrozenDict
1✔
16
from pants.util.memo import memoized_method, memoized_property
1✔
17

18
if TYPE_CHECKING:
19
    pass
20

21

22
# TODO: Rebrand this. It isn't actually about "bootstrapping" any more (and the term
23
#  "bootstrap options" now means just "options needed to create a Scheduler").
24

25

26
@dataclass(frozen=True)
1✔
27
class OptionsBootstrapper:
1✔
28
    """Creates Options instances with appropriately registered options."""
29

30
    args: tuple[str, ...]
1✔
31
    env: FrozenDict[str, str]
1✔
32
    allow_pantsrc: bool
1✔
33

34
    def __repr__(self) -> str:
1✔
35
        # Bootstrap args are included in `args`. We also drop the first argument, which is the path
36
        # to `pants_loader.py`.
37
        args = list(self.args[1:])
×
38
        return f"OptionsBootstrapper(args={args}, env={self.env})"
×
39

40
    @classmethod
1✔
41
    def create(
1✔
42
        cls,
43
        *,
44
        args: Sequence[str],
45
        env: Mapping[str, str],
46
        allow_pantsrc: bool = True,
47
    ) -> OptionsBootstrapper:
48
        """Parses the minimum amount of configuration necessary to create an OptionsBootstrapper.
49

50
        :param args: An args array.
51
        :param env: An environment dictionary.
52
        :param allow_pantsrc: True to allow pantsrc files to be used. Unless tests are expecting to
53
          consume pantsrc files, they should pass False in order to avoid reading files from
54
          absolute paths. Production use-cases should pass True to allow options values to make the
55
          decision of whether to respect pantsrc files.
56
        """
UNCOV
57
        args = tuple(args)
×
58

59
        # TODO: We really only need the env vars starting with PANTS_, plus any env
60
        #  vars used in env.FOO-style interpolation in config files.
61
        #  Filtering to just those would allow OptionsBootstrapper to have a less
62
        #  unwieldy __str__.
63
        #  We used to filter all but PANTS_* (https://github.com/pantsbuild/pants/pull/7312),
64
        #  but we can't now because of env interpolation in the native config file parser.
65
        #  We can revisit this once the legacy python parser is no more, and we refactor
66
        #  the OptionsBootstrapper and/or convert it to Rust.
UNCOV
67
        return cls(
×
68
            args=args,
69
            env=FrozenDict(env),
70
            allow_pantsrc=allow_pantsrc,
71
        )
72

73
    @staticmethod
1✔
74
    def _create_bootstrap_options(
1✔
75
        args: Sequence[str], env: Mapping[str, str], allow_pantsrc: bool
76
    ) -> Options:
77
        """Create an Options instance containing just the bootstrap options.
78

79
        These are the options needed to create a scheduler.
80
        """
UNCOV
81
        ret = Options.create(
×
82
            args=args,
83
            env=env,
84
            config_sources=None,
85
            known_scope_infos=[ScopeInfo(scope=GLOBAL_SCOPE)],
86
            allow_unknown_options=True,
87
            allow_pantsrc=allow_pantsrc,
88
        )
UNCOV
89
        for option_info in collect_options_info(BootstrapOptions):
×
UNCOV
90
            ret.register(GLOBAL_SCOPE, *option_info.args, **option_info.kwargs)
×
UNCOV
91
        return ret
×
92

93
    @memoized_property
1✔
94
    def bootstrap_options(self) -> Options:
1✔
95
        """An Options instance containing just the bootstrap options.
96

97
        These are the options needed to create a scheduler.
98
        """
UNCOV
99
        return self._create_bootstrap_options(self.args, self.env, self.allow_pantsrc)
×
100

101
    @memoized_method
1✔
102
    def _full_options(
1✔
103
        self,
104
        known_scope_infos: Sequence[ScopeInfo],
105
        union_membership: UnionMembership,
106
        allow_unknown_options: bool = False,
107
    ) -> Options:
UNCOV
108
        options = Options.create(
×
109
            args=self.args,
110
            env=self.env,
111
            config_sources=None,
112
            known_scope_infos=known_scope_infos,
113
            allow_unknown_options=allow_unknown_options,
114
            allow_pantsrc=self.allow_pantsrc,
115
        )
116

UNCOV
117
        distinct_subsystem_classes = set()
×
UNCOV
118
        for ksi in known_scope_infos:
×
UNCOV
119
            if ksi.subsystem_cls is not None:
×
UNCOV
120
                if ksi.subsystem_cls in distinct_subsystem_classes:
×
121
                    continue
×
UNCOV
122
                distinct_subsystem_classes.add(ksi.subsystem_cls)
×
UNCOV
123
                ksi.subsystem_cls.register_options_on_scope(options, union_membership)
×
124

UNCOV
125
        return options
×
126

127
    def full_options_for_scopes(
1✔
128
        self,
129
        known_scope_infos: Iterable[ScopeInfo],
130
        union_membership: UnionMembership,
131
        allow_unknown_options: bool = False,
132
    ) -> Options:
133
        """Get the full Options instance bootstrapped by this object for the given known scopes."""
UNCOV
134
        return self._full_options(
×
135
            tuple(sorted(set(known_scope_infos), key=lambda si: si.scope)),
136
            union_membership,
137
            allow_unknown_options=allow_unknown_options,
138
        )
139

140
    def full_options(
1✔
141
        self,
142
        known_scope_infos: Sequence[ScopeInfo],
143
        union_membership: UnionMembership,
144
        allow_unknown_options: bool = False,
145
    ) -> Options:
146
        # Parse and register options.
UNCOV
147
        options = self.full_options_for_scopes(
×
148
            known_scope_infos,
149
            union_membership,
150
            allow_unknown_options=allow_unknown_options,
151
        )
152

UNCOV
153
        BootstrapOptions.validate_instance(options.for_global_scope())
×
UNCOV
154
        return options
×
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