Project introspection

Finding insights in your project.

Pants provides several goals to provide insights into your project's structure.

📘

Tip: Use xargs to pipe these goals into other Pants commands

For example:

$ ./pants dependees project/util.py | xargs ./pants test

See Advanced target selection for more info and other techniques to use the results.

list - find your project's targets

list will find all targets that match the arguments.

For example, to show all targets in your project:

❯ ./pants list ::
//:ansicolors
//:setuptools
helloworld:lib
helloworld:pex_binary
helloworld/__init__.py:lib
helloworld/main.py:lib
...

You can specify a file, which will find the target(s) owning that file:

❯ ./pants list helloworld/greet/greeting_test.py
helloworld/greet/greeting_test.py:tests

filter - find targets that match a predicate

filter is like list, but will only include targets that match the predicate(s).

Specify a predicate by using one of the below filter options, like --target-type. You can use a comma to OR multiple values, meaning that at least one member must be matched. You can repeat the option multiple times to AND each filter. You can prefix the filter with - to negate the filter, meaning that the target must not be true for the filter.

Some examples:

# Only `python_source` targets.
./pants filter --target-type=python_source ::

# `python_source` or `python_test` targets.
./pants filter --target-type='python_source,python_test' ::

# Any target except for `python_source` targets
./pants filter --target-type='-python_source' ::

filter --target-type

Each value should be the name of a target type, e.g. python_source or resource. Run ./pants help targets to see what targets are registered.

filter --address-regex

Regex strings for the address, such as ^dir or :util$.

filter --tag-regex

Regex strings for the tags field. Alternatively, you can use the global --tags option, which uses exact string matches instead of regex. See Advanced target selection.

dependencies - find a target's dependencies

Use dependencies to list all targets used directly by a target.

❯ ./pants dependencies helloworld:pex_binary
helloworld/main.py:lib

You can specify a file, which will run on the target(s) owning that file:

❯ ./pants dependencies helloworld/main.py:lib
//:ansicolors
helloworld/greet/greeting.py:lib
helloworld/main.py:lib

To include transitive dependencies—meaning the dependencies of the direct dependencies—use --transitive:

❯ ./pants dependencies --transitive helloworld/main.py:lib
//:ansicolors
//:setuptools
//:types-setuptools
helloworld/greet/greeting.py:lib
helloworld/greet:translations
helloworld/main.py:lib
helloworld/translator/translator.py:lib

dependees - find which targets depend on a target

The dependees goal finds all targets that directly depend on the target you specify.

❯ ./pants dependees //:ansicolors
helloworld/main.py:lib

You can specify a file, which will run on the target(s) owning that file:

❯ ./pants dependees helloworld/translator/translator.py
helloworld/greet/greeting.py:lib
helloworld/translator:lib
helloworld/translator/translator_test.py:tests

To include transitive dependees—meaning targets that don't directly depend on your target, but which depend on a target that does directly use your target—use --transitive:

❯ ./pants dependees --transitive helloworld/translator/translator.py
helloworld:lib
helloworld:pex_binary
helloworld/main.py:lib
helloworld/greet:lib
...

To include the original target itself, use --closed:

❯ ./pants dependees --closed //:ansicolors
//:ansicolors
helloworld/main.py:lib

filedeps - find which files a target owns

filedeps outputs all of the files belonging to a target, based on its sources field.

❯ ./pants filedeps helloworld/greet:lib
helloworld/greet/BUILD
helloworld/greet/__init__.py
helloworld/greet/greeting.py

To output absolute paths, use the option --absolute:

$ ./pants filedeps --absolute helloworld/util:util
/Users/pantsbuild/example-python/helloworld/greet/BUILD
/Users/pantsbuild/example-python/helloworld/greet/__init__.py
/Users/pantsbuild/example-python/helloworld/greet/greeting.py

To include the files used by dependencies (including transitive dependencies), use --transitive:

$ ./pants filedeps --transitive helloworld/util:util
BUILD
helloworld/greet/BUILD
helloworld/greet/__init__.py
helloworld/greet/greeting.py
helloworld/greet/translations.json
...

peek - programmatically inspect a target

peek outputs JSON for each target specified.

$ ./pants peek helloworld/util:tests
[
  {
    "address": "helloworld/util:tests",
    "target_type": "python_tests",
    "dependencies": null,
    "description": null,
    "interpreter_constraints": null,
    "skip_black": false,
    "skip_docformatter": false,
    "skip_flake8": true,
    "skip_isort": false,
    "skip_mypy": false,
    "sources": [
      "*.py",
      "*.pyi",
      "!test_*.py",
      "!*_test.py",
      "!tests.py",
      "!conftest.py",
      "!test_*.pyi",
      "!*_test.pyi",
      "!tests.pyi"
    ],
    "tags": null
  }
]

You can use --exclude-defaults for less verbose output:

$ ./pants peek --exclude-defaults helloworld/util:tests
[
  {
    "address": "helloworld/util:tests",
    "target_type": "python_tests",
    "skip_flake8": true,
  }
]

📘

Piping peek output into jq

peek can be particularly useful when paired with JQ to query the JSON. For example, you can combine ./pants peek with JQ to find all targets where you set the field skip_flake8=True:

$ ./pants peek :: | jq -r '.[] | select(.skip_flake8 == true) | .["address"]'
helloworld/greet:lib
helloworld/greet:tests
helloworld/util:lib

📘

Piping other introspection commands into ./pants peek

Some introspection goals, such as filter, dependencies and dependees emit a flat list of target addresses. It's often useful to expand each of those into a full JSON structure with detailed properties of each target, by piping to ./pants peek:

./pants dependees  helloworld/main.py:lib | xargs ./pants peek --exclude-defaults
[
  {
    "address": "helloworld:lib",
    "target_type": "python_sources",
    "dependencies": [
      "helloworld/__init__.py:lib",
      "helloworld/main.py:lib"
    ],
    "sources": [
      "helloworld/__init__.py",
      "helloworld/main.py"
    ]
  },
  {
    "address": "helloworld:pex_binary",
    "target_type": "pex_binary",
    "dependencies": [
      "helloworld/main.py:lib"
    ],
    "entry_point": {
      "module": "main.py",
      "function": null
    }
  }
]

paths - find dependency paths

paths emits a list of all dependency paths between two targets:

$ ./pants paths --from=helloworld/main.py --to=helloworld/translator/translator.py
[
  [
    "helloworld/main.py:lib",
    "helloworld/greet/greeting.py:lib",
    "helloworld/translator/translator.py:lib"
  ]
]

count-loc - count lines of code

count-loc counts the lines of code of the specified files by running the Succinct Code Counter tool.

$ ./pants count-loc ::
───────────────────────────────────────────────────────────────────────────────
Language                 Files     Lines   Blanks  Comments     Code Complexity
───────────────────────────────────────────────────────────────────────────────
Python                    1690    618679    23906      7270   587503      18700
HTML                        61      6522      694        67     5761          0
JSON                        36     18755        6         0    18749          0
YAML                        30      2451        4        19     2428          0
JavaScript                   6       671       89         8      574         32
CSV                          1         2        0         0        2          0
JSONL                        1         4        0         0        4          0
Jinja                        1        11        0         0       11          2
Shell                        1        13        2         2        9          4
TOML                         1       146        5         0      141          0
───────────────────────────────────────────────────────────────────────────────
Total                     1828    647254    24706      7366   615182      18738
───────────────────────────────────────────────────────────────────────────────
Estimated Cost to Develop $22,911,268
Estimated Schedule Effort 50.432378 months
Estimated People Required 53.813884
───────────────────────────────────────────────────────────────────────────────
$ ./pants count-loc '**/*.py' '**/*.proto'
───────────────────────────────────────────────────────────────────────────────
Language                 Files     Lines   Blanks  Comments     Code Complexity
───────────────────────────────────────────────────────────────────────────────
Python                      13       155       50        22       83          5
Protocol Buffers             1        11        3         2        6          0
───────────────────────────────────────────────────────────────────────────────
Total                       14       166       53        24       89          5
───────────────────────────────────────────────────────────────────────────────

SCC has dozens of options. You can pass through options by either setting --scc-args or using -- at the end of your command, like this:

./pants count-loc '**' -- --no-cocomo

🚧

See unexpected results? Set pants_ignore.

By default, Pants will ignore all globs specified in your .gitignore, along with dist/ and any hidden files.

To ignore additional files, add to the global option pants_ignore in your pants.toml, using the same syntax as .gitignore files.

For example:

[GLOBAL]
pants_ignore.add = ["/ignore_this_dir/"]

Did this page help you?