• 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/jvm/goals/lockfile.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
from collections import defaultdict
×
UNCOV
7
from collections.abc import Coroutine, Mapping
×
UNCOV
8
from dataclasses import dataclass
×
UNCOV
9
from typing import Any
×
10

UNCOV
11
from pants.core.goals.generate_lockfiles import (
×
12
    DEFAULT_TOOL_LOCKFILE,
13
    GenerateLockfile,
14
    GenerateLockfileResult,
15
    GenerateLockfilesSubsystem,
16
    KnownUserResolveNames,
17
    KnownUserResolveNamesRequest,
18
    RequestedUserResolveNames,
19
    UserGenerateLockfiles,
20
    WrappedGenerateLockfile,
21
)
UNCOV
22
from pants.core.goals.resolves import ExportableTool
×
UNCOV
23
from pants.engine.environment import EnvironmentName
×
UNCOV
24
from pants.engine.fs import CreateDigest, FileContent
×
UNCOV
25
from pants.engine.internals.selectors import concurrently
×
UNCOV
26
from pants.engine.intrinsics import create_digest
×
UNCOV
27
from pants.engine.rules import collect_rules, implicitly, rule
×
UNCOV
28
from pants.engine.target import AllTargets
×
UNCOV
29
from pants.engine.unions import UnionMembership, UnionRule, union
×
UNCOV
30
from pants.jvm.resolve import coursier_fetch
×
UNCOV
31
from pants.jvm.resolve.common import (
×
32
    ArtifactRequirement,
33
    ArtifactRequirements,
34
    GatherJvmCoordinatesRequest,
35
)
UNCOV
36
from pants.jvm.resolve.coursier_fetch import coursier_resolve_lockfile
×
UNCOV
37
from pants.jvm.resolve.jvm_tool import (
×
38
    GenerateJvmLockfileFromTool,
39
    JvmToolBase,
40
    gather_coordinates_for_jvm_lockfile,
41
)
UNCOV
42
from pants.jvm.resolve.lockfile_metadata import JVMLockfileMetadata
×
UNCOV
43
from pants.jvm.subsystems import JvmSubsystem
×
UNCOV
44
from pants.jvm.target_types import JvmArtifactResolveField, JvmResolveField
×
UNCOV
45
from pants.option.subsystem import _construct_subsystem
×
UNCOV
46
from pants.util.docutil import bin_name
×
UNCOV
47
from pants.util.logging import LogLevel
×
UNCOV
48
from pants.util.ordered_set import OrderedSet
×
49

50

UNCOV
51
@dataclass(frozen=True)
×
UNCOV
52
class GenerateJvmLockfile(GenerateLockfile):
×
UNCOV
53
    artifacts: ArtifactRequirements
×
54

55

UNCOV
56
@union(in_scope_types=[EnvironmentName])
×
UNCOV
57
@dataclass(frozen=True)
×
UNCOV
58
class ValidateJvmArtifactsForResolveRequest:
×
59
    """Hook for backends to validate the artifact requirements requested for a resolve.
60

61
    The main user is the Scala backend which will ensure scala-library is present in the resolve.
62
    """
63

UNCOV
64
    artifacts: ArtifactRequirements
×
UNCOV
65
    resolve_name: str
×
66

67

UNCOV
68
@dataclass(frozen=True)
×
UNCOV
69
class ValidateJvmArtifactsForResolveResult:
×
70
    """Sentinel type that represents that a backend is satisfied with the artifacts for a JVM
71
    resolve."""
72

73

UNCOV
74
@rule(polymorphic=True)
×
UNCOV
75
async def _validate_jvm_artifacts_for_resolve(
×
76
    req: ValidateJvmArtifactsForResolveRequest, env_name: EnvironmentName
77
) -> ValidateJvmArtifactsForResolveResult:
78
    raise NotImplementedError()
×
79

80

UNCOV
81
@rule
×
UNCOV
82
async def wrap_jvm_lockfile_request(request: GenerateJvmLockfile) -> WrappedGenerateLockfile:
×
83
    return WrappedGenerateLockfile(request)
×
84

85

UNCOV
86
@rule(desc="Generate JVM lockfile", level=LogLevel.DEBUG)
×
UNCOV
87
async def generate_jvm_lockfile(
×
88
    request: GenerateJvmLockfile,
89
    generate_lockfiles_subsystem: GenerateLockfilesSubsystem,
90
) -> GenerateLockfileResult:
91
    resolved_lockfile = await coursier_resolve_lockfile(request.artifacts)
×
92
    regenerate_command = (
×
93
        generate_lockfiles_subsystem.custom_command or f"{bin_name()} generate-lockfiles"
94
    )
95

96
    resolved_lockfile_contents = resolved_lockfile.to_serialized()
×
97
    metadata = JVMLockfileMetadata.new(request.artifacts)
×
98
    resolved_lockfile_contents = metadata.add_header_to_lockfile(
×
99
        resolved_lockfile_contents,
100
        regenerate_command=regenerate_command,
101
        delimeter="#",
102
    )
103

104
    lockfile_digest = await create_digest(
×
105
        CreateDigest([FileContent(request.lockfile_dest, resolved_lockfile_contents)])
106
    )
107
    return GenerateLockfileResult(lockfile_digest, request.resolve_name, request.lockfile_dest)
×
108

109

UNCOV
110
class RequestedJVMUserResolveNames(RequestedUserResolveNames):
×
UNCOV
111
    pass
×
112

113

UNCOV
114
class KnownJVMUserResolveNamesRequest(KnownUserResolveNamesRequest):
×
UNCOV
115
    pass
×
116

117

UNCOV
118
@rule
×
UNCOV
119
async def determine_jvm_user_resolves(
×
120
    _: KnownJVMUserResolveNamesRequest,
121
    jvm_subsystem: JvmSubsystem,
122
    union_membership: UnionMembership,
123
) -> KnownUserResolveNames:
124
    jvm_tool_resolves = ExportableTool.filter_for_subclasses(union_membership, JvmToolBase)
×
125
    names = (*jvm_subsystem.resolves.keys(), *jvm_tool_resolves.keys())
×
126
    return KnownUserResolveNames(
×
127
        names=names,
128
        option_name=f"[{jvm_subsystem.options_scope}].resolves",
129
        requested_resolve_names_cls=RequestedJVMUserResolveNames,
130
    )
131

132

UNCOV
133
@dataclass(frozen=True)
×
UNCOV
134
class _ValidateJvmArtifactsRequest:
×
UNCOV
135
    artifacts: ArtifactRequirements
×
UNCOV
136
    resolve_name: str
×
137

138

UNCOV
139
@rule
×
UNCOV
140
async def validate_jvm_artifacts_for_resolve(
×
141
    request: _ValidateJvmArtifactsRequest,
142
    union_membership: UnionMembership,
143
    jvm_subsystem: JvmSubsystem,
144
) -> GenerateJvmLockfile:
145
    impls = union_membership.get(ValidateJvmArtifactsForResolveRequest)
×
146
    for impl in impls:
×
147
        validate_request = impl(artifacts=request.artifacts, resolve_name=request.resolve_name)
×
148
        _ = await _validate_jvm_artifacts_for_resolve(  # noqa: PNT30: requires triage
×
149
            **implicitly({validate_request: ValidateJvmArtifactsForResolveRequest})
150
        )
151

152
    return GenerateJvmLockfile(
×
153
        artifacts=request.artifacts,
154
        resolve_name=request.resolve_name,
155
        lockfile_dest=jvm_subsystem.resolves[request.resolve_name],
156
        diff=False,
157
    )
158

159

UNCOV
160
@rule
×
UNCOV
161
async def setup_lockfile_request_from_tool(
×
162
    request: GenerateJvmLockfileFromTool,
163
) -> GenerateJvmLockfile:
164
    artifacts = await gather_coordinates_for_jvm_lockfile(
×
165
        GatherJvmCoordinatesRequest(request.artifact_inputs, request.artifact_option_name)
166
    )
167
    return GenerateJvmLockfile(
×
168
        artifacts=artifacts,
169
        resolve_name=request.resolve_name,
170
        lockfile_dest=(
171
            request.lockfile if request.lockfile != DEFAULT_TOOL_LOCKFILE else DEFAULT_TOOL_LOCKFILE
172
        ),
173
        diff=False,
174
    )
175

176

UNCOV
177
async def _plan_generate_lockfile(
×
178
    resolve, resolve_to_artifacts, tools
179
) -> Coroutine[Any, Any, GenerateJvmLockfile]:
180
    """Generate a JVM lockfile request for each requested resolve.
181

182
    This step also allows other backends to validate the proposed set of artifact requirements for
183
    each resolve.
184
    """
185
    if resolve in resolve_to_artifacts:
×
186
        return validate_jvm_artifacts_for_resolve(
×
187
            _ValidateJvmArtifactsRequest(
188
                artifacts=ArtifactRequirements(resolve_to_artifacts[resolve]),
189
                resolve_name=resolve,
190
            ),
191
            **implicitly(),
192
        )
193
    elif resolve in tools:
×
194
        tool_cls: type[JvmToolBase] = tools[resolve]
×
195
        tool = await _construct_subsystem(tool_cls)
×
196

197
        return setup_lockfile_request_from_tool(
×
198
            GenerateJvmLockfileFromTool.create(tool),
199
        )
200

201
    else:
202
        return validate_jvm_artifacts_for_resolve(
×
203
            _ValidateJvmArtifactsRequest(
204
                artifacts=ArtifactRequirements(()),
205
                resolve_name=resolve,
206
            ),
207
            **implicitly(),
208
        )
209

210

UNCOV
211
@rule
×
UNCOV
212
async def setup_user_lockfile_requests(
×
213
    requested: RequestedJVMUserResolveNames,
214
    all_targets: AllTargets,
215
    jvm_subsystem: JvmSubsystem,
216
    union_membership: UnionMembership,
217
) -> UserGenerateLockfiles:
218
    resolve_to_artifacts: Mapping[str, OrderedSet[ArtifactRequirement]] = defaultdict(OrderedSet)
×
219
    for tgt in sorted(all_targets, key=lambda t: t.address):
×
220
        if not tgt.has_field(JvmArtifactResolveField):
×
221
            continue
×
222
        artifact = ArtifactRequirement.from_jvm_artifact_target(tgt)
×
223
        resolve = tgt[JvmResolveField].normalized_value(jvm_subsystem)
×
224
        resolve_to_artifacts[resolve].add(artifact)
×
225

226
    tools = ExportableTool.filter_for_subclasses(union_membership, JvmToolBase)
×
227

228
    rule_calls: list[Coroutine[Any, Any, GenerateJvmLockfile]] = []
×
229
    for resolve in requested:
×
230
        rule_calls.append(await _plan_generate_lockfile(resolve, resolve_to_artifacts, tools))
×
231

232
    jvm_lockfile_requests = await concurrently(rule_calls)
×
233

234
    return UserGenerateLockfiles(jvm_lockfile_requests)
×
235

236

UNCOV
237
def rules():
×
UNCOV
238
    return (
×
239
        *collect_rules(),
240
        *coursier_fetch.rules(),
241
        UnionRule(GenerateLockfile, GenerateJvmLockfile),
242
        UnionRule(KnownUserResolveNamesRequest, KnownJVMUserResolveNamesRequest),
243
        UnionRule(RequestedUserResolveNames, RequestedJVMUserResolveNames),
244
    )
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