• 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/adhoc/target_types.py
1
# Copyright 2023 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 enum import Enum
×
UNCOV
7
from typing import ClassVar
×
8

UNCOV
9
from pants.base.glob_match_error_behavior import GlobMatchErrorBehavior
×
UNCOV
10
from pants.core.environments.target_types import EnvironmentField
×
UNCOV
11
from pants.core.util_rules.adhoc_process_support import PathEnvModifyMode
×
UNCOV
12
from pants.engine.env_vars import EXTRA_ENV_VARS_USAGE_HELP
×
UNCOV
13
from pants.engine.fs import GlobExpansionConjunction
×
UNCOV
14
from pants.engine.process import ProcessCacheScope
×
UNCOV
15
from pants.engine.target import (
×
16
    COMMON_TARGET_FIELDS,
17
    BoolField,
18
    Dependencies,
19
    DictStringToStringField,
20
    IntField,
21
    MultipleSourcesField,
22
    SpecialCasedDependencies,
23
    StringField,
24
    StringSequenceField,
25
    Target,
26
    ValidNumbers,
27
)
UNCOV
28
from pants.util.docutil import bin_name
×
UNCOV
29
from pants.util.strutil import help_text
×
30

31

UNCOV
32
class AdhocToolDependenciesField(Dependencies):
×
UNCOV
33
    pass
×
34

35

UNCOV
36
class AdhocToolRunnableField(StringField):
×
UNCOV
37
    alias: ClassVar[str] = "runnable"
×
UNCOV
38
    required = True
×
UNCOV
39
    help = help_text(
×
40
        lambda: f"""
41
        Address to a target that can be invoked by the `run` goal (and does not set
42
        `run_in_sandbox_behavior=NOT_SUPPORTED`). This will be executed along with any arguments
43
        specified by `{AdhocToolArgumentsField.alias}`, in a sandbox with that target's transitive
44
        dependencies, along with the transitive dependencies specified by
45
        `{AdhocToolExecutionDependenciesField.alias}`.
46
        """
47
    )
48

49

UNCOV
50
class AdhocToolOutputFilesField(StringSequenceField):
×
UNCOV
51
    alias: ClassVar[str] = "output_files"
×
UNCOV
52
    required = False
×
UNCOV
53
    default = ()
×
UNCOV
54
    help = help_text(
×
55
        lambda: f"""
56
        Specify the output files to capture, relative to the value of
57
        `{AdhocToolWorkdirField.alias}`.
58

59
        For directories, use `{AdhocToolOutputDirectoriesField.alias}`. At least one of
60
        `{AdhocToolOutputFilesField.alias}` and `{AdhocToolOutputDirectoriesField.alias}` must be
61
        specified.
62

63
        Relative paths (including `..`) may be used, as long as the path does not ascend further
64
        than the build root.
65
        """
66
    )
67

68

UNCOV
69
class AdhocToolOutputDirectoriesField(StringSequenceField):
×
UNCOV
70
    alias: ClassVar[str] = "output_directories"
×
UNCOV
71
    required = False
×
UNCOV
72
    default = ()
×
UNCOV
73
    help = help_text(
×
74
        lambda: f"""
75
        Specify full directories (including recursive descendants) of output to capture, relative
76
        to the value of `{AdhocToolWorkdirField.alias}`.
77

78
        For individual files, use `{AdhocToolOutputFilesField.alias}`. At least one of
79
        `{AdhocToolOutputFilesField.alias}` and `{AdhocToolOutputDirectoriesField.alias}` must be
80
        specified.
81

82
        Relative paths (including `..`) may be used, as long as the path does not ascend further
83
        than the build root.
84
        """
85
    )
86

87

UNCOV
88
class AdhocToolOutputDependenciesField(AdhocToolDependenciesField):
×
UNCOV
89
    supports_transitive_excludes = True
×
UNCOV
90
    alias: ClassVar[str] = "output_dependencies"
×
91

UNCOV
92
    help = help_text(
×
93
        lambda: f"""
94
        Any dependencies that need to be present (as transitive dependencies) whenever the outputs
95
        of this target are consumed (including as dependencies).
96

97
        See also `{AdhocToolExecutionDependenciesField.alias}` and
98
        `{AdhocToolRunnableDependenciesField.alias}`.
99
        """
100
    )
101

102

UNCOV
103
class AdhocToolExecutionDependenciesField(SpecialCasedDependencies):
×
UNCOV
104
    alias: ClassVar[str] = "execution_dependencies"
×
UNCOV
105
    required = False
×
UNCOV
106
    default = None
×
107

UNCOV
108
    help = help_text(
×
109
        lambda: f"""
110
        The execution dependencies for this command.
111

112
        Dependencies specified here are those required to make the command complete successfully
113
        (e.g. file inputs, packages compiled from other targets, etc), but NOT required to make
114
        the outputs of the command useful. Dependencies that are required to use the outputs
115
        produced by this command should be specified using the
116
        `{AdhocToolOutputDependenciesField.alias}` field.
117

118
        If this field is specified, dependencies from `{AdhocToolOutputDependenciesField.alias}`
119
        will not be added to the execution sandbox.
120

121
        See also `{AdhocToolOutputDependenciesField.alias}` and
122
        `{AdhocToolRunnableDependenciesField.alias}`.
123
        """
124
    )
125

126

UNCOV
127
class AdhocToolRunnableDependenciesField(SpecialCasedDependencies):
×
UNCOV
128
    alias: ClassVar[str] = "runnable_dependencies"
×
UNCOV
129
    required = False
×
UNCOV
130
    default = None
×
131

UNCOV
132
    help = help_text(
×
133
        lambda: f"""
134
        The runnable dependencies for this command.
135

136
        Dependencies specified here are those required to exist on the `PATH` to make the command
137
        complete successfully (interpreters specified in a `#!` command, etc). Note that these
138
        dependencies will be made available on the `PATH` with the name of the target.
139

140
        See also `{AdhocToolOutputDependenciesField.alias}` and
141
        `{AdhocToolExecutionDependenciesField.alias}`.
142
        """
143
    )
144

145

UNCOV
146
class AdhocToolSourcesField(MultipleSourcesField):
×
147
    # We solely register this field for codegen to work.
UNCOV
148
    alias: ClassVar[str] = "_sources"
×
UNCOV
149
    uses_source_roots = False
×
UNCOV
150
    expected_num_files = 0
×
151

152

UNCOV
153
class AdhocToolArgumentsField(StringSequenceField):
×
UNCOV
154
    alias: ClassVar[str] = "args"
×
UNCOV
155
    default = ()
×
UNCOV
156
    help = help_text(
×
157
        lambda: f"Extra arguments to pass into the `{AdhocToolRunnableField.alias}` field."
158
    )
159

160

UNCOV
161
class AdhocToolStdoutFilenameField(StringField):
×
UNCOV
162
    alias: ClassVar[str] = "stdout"
×
UNCOV
163
    default = None
×
UNCOV
164
    help = help_text(
×
165
        lambda: f"""
166
        A filename to capture the contents of `stdout` to. Relative paths are
167
        relative to the value of `{AdhocToolWorkdirField.alias}`, absolute paths
168
        start at the build root.
169
        """
170
    )
171

172

UNCOV
173
class AdhocToolStderrFilenameField(StringField):
×
UNCOV
174
    alias: ClassVar[str] = "stderr"
×
UNCOV
175
    default = None
×
UNCOV
176
    help = help_text(
×
177
        lambda: f"""
178
        A filename to capture the contents of `stderr` to. Relative paths are
179
        relative to the value of `{AdhocToolWorkdirField.alias}`, absolute paths
180
        start at the build root.
181
        """
182
    )
183

184

UNCOV
185
class AdhocToolTimeoutField(IntField):
×
UNCOV
186
    alias: ClassVar[str] = "timeout"
×
UNCOV
187
    default = 30
×
UNCOV
188
    help = "Command execution timeout (in seconds)."
×
UNCOV
189
    valid_numbers = ValidNumbers.positive_only
×
190

191

UNCOV
192
class AdhocToolExtraEnvVarsField(StringSequenceField):
×
UNCOV
193
    alias: ClassVar[str] = "extra_env_vars"
×
UNCOV
194
    help = help_text(
×
195
        f"""
196
        Additional environment variables to provide to the process.
197

198
        {EXTRA_ENV_VARS_USAGE_HELP}
199
        """
200
    )
201

202

UNCOV
203
class AdhocToolLogOutputField(BoolField):
×
UNCOV
204
    alias: ClassVar[str] = "log_output"
×
UNCOV
205
    default = False
×
UNCOV
206
    help = "Set to true if you want the output logged to the console."
×
207

208

UNCOV
209
class AdhocToolWorkdirField(StringField):
×
UNCOV
210
    alias: ClassVar[str] = "workdir"
×
UNCOV
211
    default = "."
×
UNCOV
212
    help = help_text(
×
213
        """
214
        Sets the working directory for the process.
215

216
        Values are relative to the build root, except in the following cases:
217

218
        * `.` specifies the location of the `BUILD` file.
219
        * Values beginning with `./` are relative to the location of the `BUILD` file.
220
        * `/` or the empty string specifies the build root.
221
        * Values beginning with `/` are also relative to the build root.
222
        """
223
    )
224

225

UNCOV
226
class AdhocToolNamedCachesField(DictStringToStringField):
×
UNCOV
227
    alias = "experimental_named_caches"
×
UNCOV
228
    help = help_text(
×
229
        """
230
        Named caches to construct for the execution.
231
        See https://www.pantsbuild.org/docs/reference-global#named_caches_dir.
232

233
        The keys of the mapping are the directory name to be created in the named caches dir.
234
        The values are the name of the symlink (relative to the sandbox root) in the sandbox which
235
        points to the subdirectory in the named caches dir
236

237
        NOTE: The named caches MUST be handled with great care. Processes accessing the named caches
238
        can be run in parallel, and can be cancelled at any point in their execution (and
239
        potentially restarted). That means that _every_ operation modifying the contents of the cache
240
        MUST be concurrency and cancellation safe.
241
        """
242
    )
243

244

UNCOV
245
class AdhocToolOutputRootDirField(StringField):
×
UNCOV
246
    alias: ClassVar[str] = "root_output_directory"
×
UNCOV
247
    default = "/"
×
UNCOV
248
    help = help_text(
×
249
        """
250
        Adjusts the location of files output by this target, when consumed as a dependency.
251

252
        Values are relative to the build root, except in the following cases:
253

254
          * `.` specifies the location of the `BUILD` file.
255
          * Values beginning with `./` are relative to the location of the `BUILD` file.
256
          * `/` or the empty string specifies the build root.
257
          * Values beginning with `/` are also relative to the build root.
258
        """
259
    )
260

261

UNCOV
262
class AdhocToolWorkspaceInvalidationSourcesField(StringSequenceField):
×
UNCOV
263
    alias: ClassVar[str] = "workspace_invalidation_sources"
×
UNCOV
264
    help = help_text(
×
265
        """
266
        Path globs for source files on which this target depends and for which any changes should cause
267
        this target's process to be re-executed. Unlike ordinary dependencies, the files referenced by
268
        `workspace_invalidation_sources` globs are not materialized into any execution sandbox
269
        and are referenced solely for cache invalidation purposes.
270

271
        Note: This field is intended to work with the in-workspace execution environment configured by
272
        the `workspace_environment` target type. It should only be used when the configured
273
        environment for a target is a `workspace_environment`.
274

275
        Implementation: Pants computes a digest of all of the files referenced by the provided globs
276
        and injects that digest into the process as an environment variable. Since environment variables
277
        are part of the cache key for a process's execution, any changes to the referenced files will
278
        change the digest and thus force re-exection of the process.
279
        """
280
    )
281

282

UNCOV
283
class AdhocToolPathEnvModifyModeField(StringField):
×
UNCOV
284
    alias = "path_env_modify"
×
UNCOV
285
    default = PathEnvModifyMode.PREPEND.value
×
UNCOV
286
    help = help_text(
×
287
        """
288
        When executing the command of an `adhoc_tool`, `shell_command`, or `test_shell_command` target,
289
        Pants may augment the `PATH` environment variable with the location of any binary shims created for
290
        `tools` and any runnable dependencies.
291

292
        Modification of the `PATH` environment variable can be configured as follows:
293

294
        - `prepend`: Prepend the extra path components to any existing `PATH` value.
295

296
        - `append`: Append the extra path componenets to any existing `PATH` value.
297

298
        - `off`: Do not modify the existing `PATH` value.
299
        """
300
    )
UNCOV
301
    valid_choices = PathEnvModifyMode
×
302

UNCOV
303
    @property
×
UNCOV
304
    def enum_value(self) -> PathEnvModifyMode:
×
305
        return PathEnvModifyMode(self.value)
×
306

307

UNCOV
308
class OutputsMatchMode(Enum):
×
309
    """The different types of output checks for adhoc_tool / shell_command targets."""
310

UNCOV
311
    ALL = "all"
×
UNCOV
312
    ALL_WARN = "all_warn"
×
UNCOV
313
    AT_LEAST_ONE = "at_least_one"
×
UNCOV
314
    AT_LEAST_ONE_WARN = "at_least_one_warn"
×
UNCOV
315
    ALLOW_EMPTY = "allow_empty"
×
316

UNCOV
317
    @property
×
UNCOV
318
    def glob_match_error_behavior(self) -> GlobMatchErrorBehavior:
×
319
        if self in (OutputsMatchMode.ALL, OutputsMatchMode.AT_LEAST_ONE):
×
320
            return GlobMatchErrorBehavior.error
×
321
        else:
322
            return GlobMatchErrorBehavior.warn
×
323

UNCOV
324
    @property
×
UNCOV
325
    def glob_expansion_conjunction(self) -> GlobExpansionConjunction | None:
×
326
        if self in (OutputsMatchMode.ALL, OutputsMatchMode.ALL_WARN):
×
327
            return GlobExpansionConjunction.all_match
×
328
        elif self in (OutputsMatchMode.AT_LEAST_ONE, OutputsMatchMode.AT_LEAST_ONE_WARN):
×
329
            return GlobExpansionConjunction.any_match
×
330
        else:
331
            return None
×
332

333

UNCOV
334
class AdhocToolOutputsMatchMode(StringField):
×
UNCOV
335
    alias = "outputs_match_mode"
×
UNCOV
336
    default = OutputsMatchMode.ALL_WARN.value
×
UNCOV
337
    help = help_text(
×
338
        """
339
        Configure whether all, or some, of the values in the `output_files` and `output_directories` fields must actually match
340
        the outputs generated by the invoked process. These values are called "globs". Outputs may be matched by more than one
341
        glob.
342

343
        Valid values are:
344

345
        - `all_warn`: Log a warning if any glob fails to match an output. (In other words, all globs must match to avoid a
346
        warning.) This is the default value.
347

348
        - `all`: Ensure all globs match an output or else raise an error.
349

350
        - `at_least_one_warn`: Log a warning if none of the globs match an output.
351

352
        - `at_least_one`: Ensure at least one glob matches an output or else raise an error.
353

354
        - `allow_empty`: Allow empty digests (which means nothing was captured). This disables checking that globs match outputs.
355
        """
356
    )
UNCOV
357
    valid_choices = OutputsMatchMode
×
358

UNCOV
359
    @property
×
UNCOV
360
    def enum_value(self) -> OutputsMatchMode:
×
361
        return OutputsMatchMode(self.value)
×
362

363

UNCOV
364
class AdhocToolCacheScopeField(StringField):
×
UNCOV
365
    alias = "cache_scope"
×
UNCOV
366
    default = "from_environment"
×
UNCOV
367
    help = help_text(
×
368
        f"""
369
        Set the "cache scope" of the executed process to provided value. The cache scope determines for how long
370
        Pants will cache the result of the process execution (assuming no changes to files or dependencies
371
        invalidate the result in the meantime).
372

373
        The valid values are:
374

375
        - `from_environment`: Use the default cache scope for the applicable environment in which the process will execute.
376
        This is `success` for all environments except for `experimental_workspace_environment`, in which case `session`
377
        cache scope will be used.
378

379
        - `success`: Cache successful executions of the process.
380

381
        - `success_per_pantsd_restart`: Cache successful executions of the process for the life of the
382
         applicable pantsd process.
383

384
        - `session`: Only cache the result for a single Pants session. This will usually be a single invocation of the
385
        `{bin_name()}` tool.
386
        """
387
    )
UNCOV
388
    valid_choices = ("from_environment", "success", "success_per_pantsd_restart", "session")
×
389

UNCOV
390
    @property
×
UNCOV
391
    def enum_value(self) -> ProcessCacheScope | None:
×
392
        value = self.value
×
393
        if value == "success":
×
394
            return ProcessCacheScope.SUCCESSFUL
×
395
        elif value == "success_per_pantsd_restart":
×
396
            return ProcessCacheScope.PER_RESTART_SUCCESSFUL
×
397
        elif value == "session":
×
398
            return ProcessCacheScope.PER_SESSION
×
399
        else:
400
            # Default case `from_environment`
401
            return None
×
402

403

UNCOV
404
class AdhocToolTarget(Target):
×
UNCOV
405
    alias: ClassVar[str] = "adhoc_tool"
×
UNCOV
406
    core_fields = (
×
407
        *COMMON_TARGET_FIELDS,
408
        AdhocToolRunnableField,
409
        AdhocToolArgumentsField,
410
        AdhocToolExecutionDependenciesField,
411
        AdhocToolOutputDependenciesField,
412
        AdhocToolRunnableDependenciesField,
413
        AdhocToolLogOutputField,
414
        AdhocToolOutputFilesField,
415
        AdhocToolOutputDirectoriesField,
416
        AdhocToolSourcesField,
417
        AdhocToolTimeoutField,
418
        AdhocToolExtraEnvVarsField,
419
        AdhocToolWorkdirField,
420
        AdhocToolOutputRootDirField,
421
        AdhocToolStdoutFilenameField,
422
        AdhocToolStderrFilenameField,
423
        AdhocToolWorkspaceInvalidationSourcesField,
424
        AdhocToolPathEnvModifyModeField,
425
        AdhocToolOutputsMatchMode,
426
        AdhocToolCacheScopeField,
427
        EnvironmentField,
428
    )
UNCOV
429
    help = help_text(
×
430
        lambda: f"""
431
        Execute any runnable target for its side effects.
432

433
        Example BUILD file:
434

435
            {AdhocToolTarget.alias}(
436
                {AdhocToolRunnableField.alias}=":python_source",
437
                {AdhocToolArgumentsField.alias}=[""],
438
                {AdhocToolExecutionDependenciesField.alias}=[":scripts"],
439
                {AdhocToolOutputDirectoriesField.alias}=["results/"],
440
                {AdhocToolOutputFilesField.alias}=["logs/my-script.log"],
441
            )
442

443
            shell_sources(name="scripts")
444
        """
445
    )
446

447

448
# ---
449
# `system_binary` target
450
# ---
451

452

UNCOV
453
class SystemBinaryNameField(StringField):
×
UNCOV
454
    alias: ClassVar[str] = "binary_name"
×
UNCOV
455
    required = True
×
UNCOV
456
    help = "The name of the binary to find."
×
457

458

UNCOV
459
class SystemBinaryExtraSearchPathsField(StringSequenceField):
×
UNCOV
460
    alias: ClassVar[str] = "extra_search_paths"
×
UNCOV
461
    default = ()
×
UNCOV
462
    help = help_text(
×
463
        """
464
        Extra search paths to look for the binary. These take priority over Pants' default
465
        search paths.
466
        """
467
    )
468

469

UNCOV
470
class SystemBinaryFingerprintPattern(StringField):
×
UNCOV
471
    alias: ClassVar[str] = "fingerprint"
×
UNCOV
472
    required = False
×
UNCOV
473
    default = None
×
UNCOV
474
    help = help_text(
×
475
        """
476
        A regular expression which will be used to match the fingerprint outputs from
477
        candidate binaries found during the search process.
478
        """
479
    )
480

481

UNCOV
482
class SystemBinaryFingerprintArgsField(StringSequenceField):
×
UNCOV
483
    alias: ClassVar[str] = "fingerprint_args"
×
UNCOV
484
    default = ()
×
UNCOV
485
    help = help_text(
×
486
        "Specifies arguments that will be used to run the binary during the search process."
487
    )
488

489

UNCOV
490
class SystemBinaryFingerprintDependenciesField(AdhocToolRunnableDependenciesField):
×
UNCOV
491
    alias: ClassVar[str] = "fingerprint_dependencies"
×
UNCOV
492
    help = help_text(
×
493
        """
494
        Specifies any runnable dependencies that need to be available on the `PATH` when the binary
495
        is run, so that the search process may complete successfully. The name of the target must
496
        be the name of the runnable dependency that is called by this binary.
497
        """
498
    )
499

500

UNCOV
501
class SystemBinaryLogFingerprintingErrorsField(BoolField):
×
UNCOV
502
    alias = "log_fingerprinting_errors"
×
UNCOV
503
    default = True
×
UNCOV
504
    help = help_text(
×
505
        """
506
        If True, then any errors encountered while fingerprinting candidate binaries will be logged as a warning.
507
        """
508
    )
509

510

UNCOV
511
class SystemBinaryTarget(Target):
×
UNCOV
512
    alias: ClassVar[str] = "system_binary"
×
UNCOV
513
    core_fields = (
×
514
        *COMMON_TARGET_FIELDS,
515
        SystemBinaryNameField,
516
        SystemBinaryExtraSearchPathsField,
517
        SystemBinaryFingerprintPattern,
518
        SystemBinaryFingerprintArgsField,
519
        SystemBinaryFingerprintDependenciesField,
520
        SystemBinaryLogFingerprintingErrorsField,
521
    )
UNCOV
522
    help = help_text(
×
523
        lambda: f"""
524
        A system binary that can be run with `pants run` or consumed by `{AdhocToolTarget.alias}`.
525

526
        Pants will search for binaries with name `{SystemBinaryNameField.alias}` in the search
527
        paths provided, as well as default search paths. If
528
        `{SystemBinaryFingerprintPattern.alias}` is specified, each binary that is located will be
529
        executed with the arguments from `{SystemBinaryFingerprintArgsField.alias}`. Any binaries
530
        whose output does not match the pattern will be excluded.
531

532
        The first non-excluded binary will be the one that is resolved.
533
        """
534
    )
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