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

pantsbuild / pants / 18225878979

03 Oct 2025 02:59PM UTC coverage: 80.269% (-0.006%) from 80.275%
18225878979

Pull #22717

github

web-flow
Merge b17e03226 into f7b1ba442
Pull Request #22717: wip: run tests on mac arm

77232 of 96217 relevant lines covered (80.27%)

3.63 hits per line

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

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

4
from __future__ import annotations
13✔
5

6
import json
13✔
7
import textwrap
13✔
8
from enum import Enum
13✔
9

10
from pants.help.help_info_extracter import OptionHelpInfo, OptionScopeHelpInfo, to_help_str
13✔
11
from pants.help.maybe_color import MaybeColor
13✔
12
from pants.option.ranked_value import Rank, RankedValue
13✔
13
from pants.util.docutil import bin_name, terminal_width
13✔
14
from pants.util.strutil import hard_wrap
13✔
15

16

17
class HelpFormatter(MaybeColor):
13✔
18
    def __init__(self, *, show_advanced: bool, show_deprecated: bool, color: bool) -> None:
13✔
19
        super().__init__(color=color)
1✔
20
        self._show_advanced = show_advanced
1✔
21
        self._show_deprecated = show_deprecated
1✔
22
        self._width = terminal_width()
1✔
23

24
    def format_options(self, oshi: OptionScopeHelpInfo) -> list[str]:
13✔
25
        """Return a help message for the specified options."""
26
        lines = []
1✔
27

28
        def add_option(ohis, *, category=None) -> None:
1✔
29
            lines.append("")
1✔
30
            goal_or_subsystem = "goal" if oshi.is_goal else "subsystem"
1✔
31
            display_scope = f"`{oshi.scope}` {goal_or_subsystem}" if oshi.scope else "Global"
1✔
32
            if category:
1✔
33
                title = f"{display_scope} {category} options"
1✔
34
                lines.append(self.maybe_green(f"{title}\n{'-' * len(title)}"))
1✔
35
            else:
36
                # The basic options section gets the description and options scope info.
37
                # No need to repeat those in the advanced section.
38
                title = f"{display_scope} options"
1✔
39
                lines.append(self.maybe_green(f"{title}\n{'-' * len(title)}\n"))
1✔
40
                lines.extend(hard_wrap(oshi.description, width=self._width))
1✔
41
                lines.append(" ")
1✔
42
                lines.append(f"Activated by {self.maybe_magenta(oshi.provider)}")
1✔
43
                config_section = f"[{oshi.scope or 'GLOBAL'}]"
1✔
44
                lines.append(f"Config section: {self.maybe_magenta(config_section)}")
1✔
45
            lines.append(" ")
1✔
46
            if not ohis:
1✔
47
                lines.append("None available.")
1✔
48
                return
1✔
49
            for ohi in ohis:
1✔
50
                lines.extend([*self.format_option(ohi), ""])
1✔
51

52
        add_option(oshi.basic)
1✔
53
        show_advanced = self._show_advanced or (not oshi.basic and oshi.advanced)
1✔
54
        if show_advanced:  # show advanced options if there are no basic ones.
1✔
55
            add_option(oshi.advanced, category="advanced")
1✔
56
        if self._show_deprecated and oshi.deprecated:
1✔
57
            add_option(oshi.deprecated, category="deprecated")
1✔
58
        if not show_advanced and oshi.advanced:
1✔
59
            lines.append(
1✔
60
                self.maybe_green(
61
                    f"Advanced options available. You can list them by running "
62
                    f"{bin_name()} help-advanced {oshi.scope}."
63
                )
64
            )
65
        return [*lines, ""]
1✔
66

67
    def format_option(self, ohi: OptionHelpInfo) -> list[str]:
13✔
68
        """Format the help output for a single option.
69

70
        :param ohi: Extracted information for option to print
71
        :return: Formatted help text for this option
72
        """
73

74
        def maybe_parens(s: str | None) -> str:
1✔
75
            return f" ({s})" if s else ""
1✔
76

77
        def format_value(ranked_val: RankedValue, prefix: str, left_padding: str) -> list[str]:
1✔
78
            if isinstance(ranked_val.value, (list, dict)):
1✔
79
                is_enum_list = (
×
80
                    isinstance(ranked_val.value, list)
81
                    and len(ranked_val.value) > 0
82
                    and isinstance(ranked_val.value[0], Enum)
83
                )
84
                normalized_val = (
×
85
                    [enum_elmt.value for enum_elmt in ranked_val.value]
86
                    if is_enum_list
87
                    else ranked_val.value
88
                )
89
                val_lines = json.dumps(normalized_val, sort_keys=True, indent=4).split("\n")
×
90
            else:
91
                val_lines = [to_help_str(ranked_val.value)]
1✔
92
            val_lines[0] = f"{prefix}{val_lines[0]}"
1✔
93
            val_lines[-1] = f"{val_lines[-1]}{maybe_parens(ranked_val.details)}"
1✔
94
            val_lines = [self.maybe_cyan(f"{left_padding}{line}") for line in val_lines]
1✔
95
            return val_lines
1✔
96

97
        def wrap(s: str) -> list[str]:
1✔
98
            return hard_wrap(s, indent=len(indent), width=self._width)
1✔
99

100
        indent = "      "
1✔
101

102
        arg_lines = [f"  {self.maybe_magenta(args)}" for args in ohi.display_args]
1✔
103
        arg_lines.append(self.maybe_magenta(f"  {ohi.env_var}"))
1✔
104
        arg_lines.append(self.maybe_magenta(f"  {ohi.config_key}"))
1✔
105

106
        choices = "" if ohi.choices is None else f"one of: [{', '.join(ohi.choices)}]"
1✔
107
        choices_lines = [
1✔
108
            f"{indent}{'  ' if i != 0 else ''}{self.maybe_cyan(s)}"
109
            for i, s in enumerate(textwrap.wrap(f"{choices}", self._width))
110
        ]
111

112
        deprecated_lines = []
1✔
113
        if ohi.deprecated_message:
1✔
114
            maybe_colorize = self.maybe_red if ohi.deprecation_active else self.maybe_yellow
1✔
115
            deprecated_lines.extend(wrap(maybe_colorize(ohi.deprecated_message)))
1✔
116
            if ohi.removal_hint:
1✔
117
                deprecated_lines.extend(wrap(maybe_colorize(ohi.removal_hint)))
×
118

119
        default_lines = format_value(RankedValue(Rank.HARDCODED, ohi.default), "default: ", indent)
1✔
120
        if not ohi.value_history:
1✔
121
            # Should never happen, but this keeps mypy happy.
122
            raise ValueError("No value history - options not parsed.")
×
123

124
        final_val = ohi.value_history.final_value
1✔
125
        curr_value_lines = format_value(final_val, "current value: ", indent)
1✔
126

127
        interesting_ranked_values = [
1✔
128
            rv
129
            for rv in reversed(ohi.value_history.ranked_values)
130
            if rv.rank not in (Rank.NONE, Rank.HARDCODED, final_val.rank)
131
        ]
132
        value_derivation_lines = [
1✔
133
            line
134
            for rv in interesting_ranked_values
135
            for line in format_value(rv, "overrode: ", f"{indent}    ")
136
        ]
137
        description_lines = wrap(ohi.help)
1✔
138
        if ohi.target_field_name:
1✔
139
            description_lines.extend(
×
140
                wrap(
141
                    f"\nCan be overriden by field `{ohi.target_field_name}` on "
142
                    "`local_environment`, `docker_environment`, or `remote_environment` targets."
143
                )
144
            )
145
        lines = [
1✔
146
            *arg_lines,
147
            *choices_lines,
148
            *default_lines,
149
            *curr_value_lines,
150
            *value_derivation_lines,
151
            *deprecated_lines,
152
            *description_lines,
153
        ]
154
        return lines
1✔
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