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

pantsbuild / pants / 20332790708

18 Dec 2025 09:48AM UTC coverage: 64.992% (-15.3%) from 80.295%
20332790708

Pull #22949

github

web-flow
Merge f730a56cd into 407284c67
Pull Request #22949: Add experimental uv resolver for Python lockfiles

54 of 97 new or added lines in 5 files covered. (55.67%)

8270 existing lines in 295 files now uncovered.

48990 of 75379 relevant lines covered (64.99%)

1.81 hits per line

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

51.06
/src/python/pants/core/goals/multi_tool_goal_helper.py
1
# Copyright 2020 Pants project contributors (see CONTRIBUTORS.md).
2
# Licensed under the Apache License, Version 2.0 (see LICENSE).
3

4
from __future__ import annotations
5✔
5

6
import logging
5✔
7
import os.path
5✔
8
from collections.abc import Iterable, Mapping, Sequence
5✔
9
from typing import Protocol, TypeVar
5✔
10

11
from pants.core.util_rules.distdir import DistDir
5✔
12
from pants.engine.fs import EMPTY_DIGEST, Digest, Workspace
5✔
13
from pants.option.option_types import IntOption, SkipOption, StrListOption
5✔
14
from pants.util.strutil import path_safe, softwrap
5✔
15

16
logger = logging.getLogger(__name__)
5✔
17

18

19
class SkippableSubsystem(Protocol):
5✔
20
    options_scope: str
5✔
21
    skip: SkipOption
5✔
22

23

24
class OnlyOption(StrListOption):
5✔
25
    """An --only option to select a subset of applicable tools."""
26

27
    def __new__(cls, tool_description: str, example1: str, example2: str):
5✔
28
        return super().__new__(
5✔
29
            cls,
30
            "--only",
31
            help=lambda cls: softwrap(
32
                f"""
33
                Only run these {tool_description}s and skip all others.
34

35
                The {tool_description} names are outputted at the final summary of running this goal,
36
                e.g. `{example1}` and `{example2}`. You can also run `{cls.name} --only=fake` to
37
                get a list of all activated {tool_description}s.
38

39
                You can repeat this option, e.g. `{cls.name} --only={example1} --only={example2}` or
40
                `{cls.name} --only=['{example1}', '{example2}']`.
41
                """
42
            ),
43
        )
44

45

46
class BatchSizeOption(IntOption):
5✔
47
    """A --batch-size option to help with caching tool runs."""
48

49
    def __new__(cls, uppercase: str, lowercase: str):
5✔
50
        return super().__new__(
5✔
51
            cls,
52
            "--batch-size",
53
            advanced=True,
54
            default=128,
55
            help=softwrap(
56
                f"""
57
                The target number of files to be included in each {lowercase} batch.
58

59
                {uppercase} processes are batched for a few reasons:
60

61
                  1. to avoid OS argument length limits (in processes which don't support argument files)
62
                  2. to support more stable cache keys than would be possible if all files were operated \
63
                     on in a single batch.
64
                  3. to allow for parallelism in {lowercase} processes which don't have internal \
65
                     parallelism, or -- if they do support internal parallelism -- to improve scheduling \
66
                     behavior when multiple processes are competing for cores and so internal \
67
                     parallelism cannot be used perfectly.
68

69
                In order to improve cache hit rates (see 2.), batches are created at stable boundaries,
70
                and so this value is only a "target" batch size (rather than an exact value).
71
                """
72
            ),
73
        )
74

75

76
def determine_specified_tool_ids(
5✔
77
    goal_name: str,
78
    only_option: Iterable[str],
79
    all_requests: Iterable[type],
80
) -> set[str]:
UNCOV
81
    all_valid_ids = {request.tool_id for request in all_requests}  # type: ignore[attr-defined]
×
UNCOV
82
    if not only_option:
×
UNCOV
83
        return all_valid_ids
×
84

UNCOV
85
    specified = set(only_option)
×
UNCOV
86
    unrecognized_names = specified - all_valid_ids
×
UNCOV
87
    if unrecognized_names:
×
UNCOV
88
        plural = (
×
89
            ("s", repr(sorted(unrecognized_names)))
90
            if len(unrecognized_names) > 1
91
            else ("", repr(next(iter(unrecognized_names))))
92
        )
UNCOV
93
        raise ValueError(
×
94
            softwrap(
95
                f"""
96
                Unrecognized name{plural[0]} with the option `--{goal_name}-only`: {plural[1]}
97

98
                All valid names: {sorted(all_valid_ids)}
99
                """
100
            )
101
        )
UNCOV
102
    return specified
×
103

104

105
class _ResultWithReport(Protocol):
5✔
106
    @property
107
    def report(self) -> Digest: ...
108

109
    @property
110
    def partition_description(self) -> str | None: ...
111

112

113
class _ResultsWithReports(Protocol):
5✔
114
    @property
115
    def results(self) -> Sequence[_ResultWithReport]: ...
116

117

118
_R = TypeVar("_R", bound=_ResultsWithReports)
5✔
119

120

121
def write_reports(
5✔
122
    results_by_tool_name: Mapping[str, Sequence[_ResultWithReport]],
123
    workspace: Workspace,
124
    dist_dir: DistDir,
125
    *,
126
    goal_name: str,
127
) -> None:
UNCOV
128
    disambiguated_dirs: set[str] = set()
×
129

UNCOV
130
    def write_report(digest: Digest, subdir: str) -> None:
×
UNCOV
131
        while subdir in disambiguated_dirs:
×
132
            # It's unlikely that two distinct partition descriptions will become the
133
            # same after path_safe(), but might as well be safe.
UNCOV
134
            subdir += "_"
×
UNCOV
135
        disambiguated_dirs.add(subdir)
×
UNCOV
136
        output_dir = str(dist_dir.relpath / goal_name / subdir)
×
UNCOV
137
        workspace.write_digest(digest, path_prefix=output_dir)
×
UNCOV
138
        logger.info(f"Wrote {goal_name} report files to {output_dir}.")
×
139

UNCOV
140
    for tool_name, results in results_by_tool_name.items():
×
UNCOV
141
        if len(results) == 1 and results[0].report != EMPTY_DIGEST:
×
UNCOV
142
            write_report(results[0].report, tool_name)
×
143
        else:
UNCOV
144
            for result in results:
×
UNCOV
145
                if result.report != EMPTY_DIGEST:
×
UNCOV
146
                    write_report(
×
147
                        result.report,
148
                        os.path.join(tool_name, path_safe(result.partition_description or "all")),
149
                    )
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