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

list often works well when paired with the --filter options from
Advanced Target Selection, e.g.
./pants --filter-target-type=python_test list :: to find all your python_test targets.

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
───────────────────────────────────────────────────────────────────────────────

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?