• 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

81.97
/src/python/pants/help/help_tools.py
1
# Copyright 2021 Pants project contributors (see CONTRIBUTORS.md).
2
# Licensed under the Apache License, Version 2.0 (see LICENSE).
3
from __future__ import annotations
13✔
4

5
from collections.abc import Generator, Iterable
13✔
6
from dataclasses import dataclass
13✔
7
from functools import partial
13✔
8
from itertools import chain
13✔
9
from textwrap import wrap
13✔
10
from typing import cast
13✔
11

12
from pants.help.help_info_extracter import AllHelpInfo, OptionScopeHelpInfo
13✔
13
from pants.help.maybe_color import MaybeColor
13✔
14
from pants.util.docutil import terminal_width
13✔
15

16

17
@dataclass(frozen=True)
13✔
18
class ToolHelpInfo:
13✔
19
    name: str
13✔
20
    description: str
13✔
21
    version: str
13✔
22
    url_template: str | None
13✔
23

24
    @classmethod
13✔
25
    def from_option_scope_help_info(cls, oshi: OptionScopeHelpInfo) -> ToolHelpInfo | None:
13✔
26
        version, url_template = cls._get_tool_info(oshi)
1✔
27
        if not version:
1✔
28
            return None
1✔
29
        return cls(
1✔
30
            name=oshi.scope,
31
            description=oshi.description,
32
            version=version,
33
            url_template=url_template,
34
        )
35

36
    @classmethod
13✔
37
    def iter(cls, all_help_info: AllHelpInfo) -> Generator[ToolHelpInfo, None, None]:
13✔
38
        for oshi in all_help_info.non_deprecated_option_scope_help_infos():
×
39
            tool_info = cls.from_option_scope_help_info(oshi)
×
40
            if tool_info:
×
41
                yield tool_info
×
42

43
    @staticmethod
13✔
44
    def print_all(tool_help_infos: Iterable[ToolHelpInfo], color: MaybeColor) -> None:
13✔
45
        this = tuple(tool_help_infos)
×
46
        longest_name = max(len(tool.name) for tool in this)
×
47
        width = terminal_width()
×
48

49
        for tool in this:
×
50
            tool.print(color, description_padding=longest_name + 2, width=width)
×
51

52
    def print(self, color: MaybeColor, description_padding: int, width: int) -> None:
13✔
53
        _wrap = partial(wrap, width=width)
1✔
54
        _max_padding = partial(
1✔
55
            min, int(width / 4)
56
        )  # Do not use more than 25% of the width on padding.
57

58
        def _indent(indent: int) -> str:
1✔
59
            return " " * cast(int, _max_padding(indent))
1✔
60

61
        lines = _wrap(
1✔
62
            f"{self.name.ljust(description_padding)}{self.description}",
63
            subsequent_indent=_indent(description_padding),
64
        )
65
        lines[0] = lines[0].replace(self.name, color.maybe_cyan(self.name), 1)
1✔
66
        version = _wrap(
1✔
67
            f"Version: {self.version}",
68
            initial_indent=_indent(description_padding),
69
            subsequent_indent=_indent(description_padding),
70
        )
71
        if not self.url_template:
1✔
72
            url_template = []
×
73
        else:
74
            url_template = _wrap(
1✔
75
                f"URL template: {self.url_template}",
76
                initial_indent=_indent(description_padding),
77
                subsequent_indent=_indent(description_padding),
78
            )
79
        print("\n".join(lines))
1✔
80
        print(color.maybe_magenta("\n".join([*version, *url_template, ""])))
1✔
81

82
    @classmethod
13✔
83
    def _get_tool_info(cls, oshi: OptionScopeHelpInfo) -> tuple[str | None, str | None]:
13✔
84
        return (
1✔
85
            cls._get_option_value(oshi, "version"),
86
            cls._get_option_value(oshi, "url_template"),
87
        )
88

89
    @staticmethod
13✔
90
    def _get_option_value(oshi: OptionScopeHelpInfo, config_key: str) -> str | None:
13✔
91
        for ohi in chain(oshi.basic, oshi.advanced):
1✔
92
            if ohi.config_key == config_key and ohi.typ is str:
1✔
93
                rank = ohi.value_history and ohi.value_history.final_value
1✔
94
                if rank:
1✔
95
                    info = f" ({rank.details})" if rank.details else ""
1✔
96
                    return f"{rank.value}{info}"
1✔
97
                return cast(str, ohi.default)
×
98
        return None
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