Advanced target selection
Alternative techniques to tell Pants which files/targets to run on.
See Goal arguments for the normal techniques for telling Pants what to run on.
See Project introspection for queries that you can run and then pipe into another Pants run, such as finding the dependencies of a target or file.
Running over changed files with --changed-since
Because Pants understands Git, it can find which files have changed since a certain commit through the --changed-since option.
For example, to lint all uncommitted files, run:
pants --changed-since=HEAD lint
To run against another branch, run:
pants --changed-since=origin/main lint
By default, --changed-since will only run over files directly changed. Often, though, you will want to run over any dependents of those changed files, meaning any targets that depend on the changed files. Use --changed-dependents=direct or --changed-dependents=transitive for this:
❯ pants \
--changed-since=origin/main \
--changed-dependents=transitive \
test
Changes to third-party dependencies (particularly, dependencies of dependencies) may not be
surfaced as you expect via --changed-*. In particular, any change to a single dependency
within a lockfile or a target generator (such as python_requirements) will consider all
users of any dependency changed, transitively.
filter options
Use filters to operate on only targets that match the predicate, e.g. only running Python tests.
Specify a predicate by using one of the below filter options, like --filter-target-type.
The predicates support logical OR, AND, and NOT as follows:
-
OR: Use a comma
,within the same filter value to OR multiple values together, meaning that at least one member must be matched for the filter to match. For example,--filter-target-type=python_source,python_testwill match targets with either thepython_sourceorpython_testtarget types; no other targets will be included. -
AND: Repeat the option multiple times to AND each filter together. For example,
--filter-tag-regex=^foo --filter-tag-regex=bar$will match targets with both at least one tag starting withfooand at least one tag ending inbar; no other targets will be included even if the target has a tag matching one of the filters. -
NOT: Use a
-prefix to negate a filter, meaning that the filter will exclude a target if the filter matches. For example,--filter-target-type=-python_testwill exclude any target with thepython_testtarget type.
Some more examples:
# Only `python_source` targets.
pants --filter-target-type=python_source list ::
# `python_source` or `python_test` targets.
pants --filter-target-type='python_source,python_test' list ::
# Any target except for `python_source` targets
pants --filter-target-type='-python_source' list ::
You can combine multiple filter options in the same run, e.g.:
pants --filter-target-type='python_test' --filter-address-regex=^integration_tests test ::
--filter-target-type
Each value should be the name of a target type, e.g.
pants --filter-target-type=python_test test ::.
Run pants help targets to see what targets are registered.
--filter-address-regex
Regex strings for the address, such as
pants --filter-address-regex='^integration_tests$' test ::.
--filter-tag-regex
Regex strings to match against the tags field, such as
pants --filter-tag-regex='^skip_lint$' lint ::.
If you don't need the power of regex, use the simpler --tag global option explained below.
Tags: annotating targets
Every target type has a field called tags, which allows you to add a sequence of strings. The
strings can be whatever you'd like, such as "integration_test".
python_tests(
name="integration",
sources=["*_integration_test.py"],
tags=["skip_lint", "integration_test"],
)
You can then filter by tags with the global --tag option, like this:
pants --tag=integration_test list ::
To exclude certain tags, prefix with a -:
pants --tag='-integration_test' list ::
You can even combine multiple includes and excludes:
pants --tag='+type_checked,skip_lint' --tag='-integration_test' list ::
Use --filter-tag-regex instead for more complex queries.
--spec-files
The global option --spec-files allows you to pass a file containing target addresses and/or file names/globs to Pants.
Each entry must be separated by a new line.
For example:
- Shell
- targets.txt
$ pants --spec-files=targets.txt list
helloworld/lang/*.py
helloworld/util
helloworld/util:tests
Whereas tags are useful for decentralized allow/block lists, --spec-files is useful when you want to define one single list of targets or files.
Piping to other Pants runs
To pipe a Pants run, use your shell's | pipe operator and xargs:
pants dependents helloworld/util | xargs pants list
You can, of course, pipe multiple times:
# Run over the second-degree dependents of `utils.py`.
❯ pants dependents helloworld/utils.py | \
xargs pants dependents | \
xargs pants lint
--spec-filesSometimes, you may want to reuse the output of a Pants run for multiple subsequent Pants runs. Rather than repeating xargs multiple times, you can generate a file through stdout redirection and --spec-files.
For example:
$ pants dependencies helloworld/util > util_dependencies.txt
$ pants --spec-files=util_dependencies.txt lint
Using spec files is also more robust because when piping output of a Pants goal to xargs, the specified command
may be invoked by xargs as many times as necessary to use up the list of input items.
This may break the structured data output, for instance, when you want to peek the targets as JSON:
$ pants list --filter-target-type=resource :: | xargs pants peek
If you don't want to save the output to an actual file—such as to not pollute version control—you can use a variable and a named pipe:
$ TARGETS=$(pants dependencies helloworld/util)
$ pants --spec-files=<(echo $TARGETS) lint
Sharding the input targets
The test goal natively supports sharding input targets into multiple shards. Use the option --test-shard=k/N, where k is a non-negative integer less than N. For example, you can split up your CI into three shards with --shard=0/3, --shard=1/3, and --shard=2/3.
For other goals, you can leverage shell piping to partition the input targets into multiple shards. For example, to split your package run into 5 shards, and select shard 0:
pants list :: | awk 'NR % 5 == 0' | xargs pants package
Using CLI aliases
If setting tags on individual targets is not feasible, there are a few other options available to refer to multiple targets.
If you have an operation that you perform often on a certain group of targets, you can use the
cli subsystem options to create shortcuts. For instance, this alias
would let you run pants publish-libraries to publish all Python distributions declared in the src/libA and src/libB
directories.
[cli.alias]
publish-libraries = "--filter-target-type=python_distribution --filter-address-regex=\"['^src/libA/,^src/libB/']\" publish src::"
You can use any argument or goal, and the alias doesn't need to be a "full" invocation of Pants.
For instance, you could combine filtering arguments along with --changed-since flag and a tag to refer to long-running
integration tests that have been recently modified:
[cli.alias]
--integration-long = "--changed-since --filter-target-type=python_test --tag=long"
You can now invoke pants --integration-long test tests:: to run the relevant tests.