• 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

0.0
/src/python/pants/backend/tools/yamllint/rules.py
1
# Copyright 2022 Pants project contributors (see CONTRIBUTORS.md).
2
# Licensed under the Apache License, Version 2.0 (see LICENSE).
3

UNCOV
4
from __future__ import annotations
×
5

UNCOV
6
import os
×
UNCOV
7
from collections import defaultdict
×
UNCOV
8
from dataclasses import dataclass
×
UNCOV
9
from typing import Any
×
10

UNCOV
11
from pants.backend.python.util_rules.pex import PexProcess, create_pex
×
UNCOV
12
from pants.backend.tools.yamllint.subsystem import Yamllint
×
UNCOV
13
from pants.core.goals.lint import LintFilesRequest, LintResult
×
UNCOV
14
from pants.core.util_rules.config_files import (
×
15
    GatherConfigFilesByDirectoriesRequest,
16
    gather_config_files_by_workspace_dir,
17
)
UNCOV
18
from pants.core.util_rules.partitions import Partition, Partitions
×
UNCOV
19
from pants.engine.fs import DigestSubset, MergeDigests, PathGlobs
×
UNCOV
20
from pants.engine.internals.native_engine import FilespecMatcher, Snapshot
×
UNCOV
21
from pants.engine.intrinsics import digest_to_snapshot, execute_process, merge_digests
×
UNCOV
22
from pants.engine.rules import collect_rules, concurrently, implicitly, rule
×
UNCOV
23
from pants.util.dirutil import group_by_dir
×
UNCOV
24
from pants.util.logging import LogLevel
×
UNCOV
25
from pants.util.strutil import pluralize
×
26

27

UNCOV
28
class YamllintRequest(LintFilesRequest):
×
UNCOV
29
    tool_subsystem = Yamllint  # type: ignore[assignment]
×
30

31

UNCOV
32
@dataclass(frozen=True)
×
UNCOV
33
class PartitionInfo:
×
UNCOV
34
    config_snapshot: Snapshot | None
×
35

UNCOV
36
    @property
×
UNCOV
37
    def description(self) -> str:
×
38
        if self.config_snapshot:
×
39
            return self.config_snapshot.files[0]
×
40
        else:
41
            return "<default>"
×
42

43

UNCOV
44
@rule
×
UNCOV
45
async def partition_inputs(
×
46
    request: YamllintRequest.PartitionRequest, yamllint: Yamllint
47
) -> Partitions[Any, PartitionInfo]:
48
    if yamllint.skip:
×
49
        return Partitions()
×
50

51
    matching_filepaths = FilespecMatcher(
×
52
        includes=yamllint.file_glob_include, excludes=yamllint.file_glob_exclude
53
    ).matches(request.files)
54

55
    config_files = await gather_config_files_by_workspace_dir(
×
56
        GatherConfigFilesByDirectoriesRequest(
57
            tool_name=yamllint.name,
58
            config_filename=yamllint.config_file_name,
59
            filepaths=tuple(sorted(matching_filepaths)),
60
            orphan_filepath_behavior=yamllint.orphan_files_behavior,
61
        )
62
    )
63

64
    default_source_files: set[str] = set()
×
65
    source_files_by_config_file: dict[str, set[str]] = defaultdict(set)
×
66
    for source_dir, files_in_source_dir in group_by_dir(matching_filepaths).items():
×
67
        files = (os.path.join(source_dir, name) for name in files_in_source_dir)
×
68
        if source_dir in config_files.source_dir_to_config_file:
×
69
            config_file = config_files.source_dir_to_config_file[source_dir]
×
70
            source_files_by_config_file[config_file].update(files)
×
71
        else:
72
            default_source_files.update(files)
×
73

74
    config_file_snapshots = await concurrently(
×
75
        digest_to_snapshot(
76
            **implicitly(DigestSubset(config_files.snapshot.digest, PathGlobs([config_file])))
77
        )
78
        for config_file in source_files_by_config_file
79
    )
80

81
    return Partitions(
×
82
        (
83
            *(
84
                Partition(tuple(sorted(files)), PartitionInfo(config_snapshot=config_snapshot))
85
                for files, config_snapshot in zip(
86
                    source_files_by_config_file.values(), config_file_snapshots
87
                )
88
            ),
89
            *(
90
                (
91
                    Partition(
92
                        tuple(sorted(default_source_files)), PartitionInfo(config_snapshot=None)
93
                    ),
94
                )
95
                if default_source_files
96
                else ()
97
            ),
98
        )
99
    )
100

101

UNCOV
102
@rule(desc="Lint using yamllint", level=LogLevel.DEBUG)
×
UNCOV
103
async def run_yamllint(
×
104
    request: YamllintRequest.Batch[str, PartitionInfo], yamllint: Yamllint
105
) -> LintResult:
106
    partition_info = request.partition_metadata
×
107

108
    yamllint_bin = await create_pex(yamllint.to_pex_request())
×
109
    snapshot = await digest_to_snapshot(**implicitly(PathGlobs(request.elements)))
×
110
    input_digest = await merge_digests(
×
111
        MergeDigests(
112
            (
113
                snapshot.digest,
114
                yamllint_bin.digest,
115
                *(
116
                    (partition_info.config_snapshot.digest,)
117
                    if partition_info.config_snapshot
118
                    else ()
119
                ),
120
            )
121
        )
122
    )
123

124
    process_result = await execute_process(
×
125
        **implicitly(
126
            PexProcess(
127
                yamllint_bin,
128
                argv=(
129
                    *(
130
                        ("-c", partition_info.config_snapshot.files[0])
131
                        if partition_info.config_snapshot
132
                        else ()
133
                    ),
134
                    *yamllint.args,
135
                    *snapshot.files,
136
                ),
137
                input_digest=input_digest,
138
                description=f"Run yamllint on {pluralize(len(request.elements), 'file')}.",
139
                level=LogLevel.DEBUG,
140
            )
141
        )
142
    )
143
    return LintResult.create(request, process_result)
×
144

145

UNCOV
146
def rules():
×
UNCOV
147
    return [*collect_rules(), *YamllintRequest.rules()]
×
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