Skip to content

Commit 0223076

Browse files
authored
Merge branch 'main' into yarn-v2-immutable-install
2 parents 5177a9b + ef03520 commit 0223076

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+218
-91
lines changed

docs/docs/using-pants/project-introspection.mdx

+66
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,72 @@ To include the original target itself, use `--closed`:
127127
helloworld/main.py:lib
128128
```
129129

130+
## Export dependency graph
131+
132+
Both `dependencies` and `dependents` goals have the `--format` option allowing you to export data in multiple formats.
133+
Exporting information about the dependencies and dependents in JSON format will produce the
134+
[adjacency list](https://en.wikipedia.org/wiki/Adjacency_list) of your dependency graph:
135+
136+
```bash
137+
$ pants dependencies --format=json \
138+
helloworld/greet/greeting.py \
139+
helloworld/translator/translator_test.py
140+
141+
{
142+
"helloworld/greet/greeting.py:lib": [
143+
"//:reqs#setuptools",
144+
"//:reqs#types-setuptools",
145+
"helloworld/greet:translations",
146+
"helloworld/translator/translator.py:lib"
147+
],
148+
"helloworld/translator/translator_test.py:tests": [
149+
"//:reqs#pytest",
150+
"helloworld/translator/translator.py:lib"
151+
]
152+
}
153+
```
154+
155+
This has various applications, and you could analyze, visualize, and process the data further. Sometimes, a fairly
156+
straightforward `jq` query would suffice, but for anything more complex, it may make sense to write a small program
157+
to process the exported graph. For instance, you could:
158+
159+
* find tests with most transitive dependencies
160+
161+
```bash
162+
$ pants dependencies --filter-target-type=python_test --format=json :: \
163+
| jq -r 'to_entries[] | "\(.key)\t\(.value | length)"' \
164+
| sort -k2 -n
165+
```
166+
167+
* find resources that only a few other targets depend on
168+
169+
```bash
170+
$ pants dependents --filter-target-type=resource --format=json :: \
171+
| jq -r 'to_entries[] | select(.value | length < 2)'
172+
```
173+
174+
* find files within the `src/` directory that transitively lead to the most tests
175+
176+
```python
177+
# depgraph.py
178+
import json
179+
180+
with open("data.json") as fh:
181+
data = json.load(fh)
182+
183+
for source, dependents in data.items():
184+
print(source, len([d for d in dependents if d.startswith("tests/")]))
185+
```
186+
187+
```bash
188+
$ pants dependents --transitive --format=json src:: > data.json
189+
$ python3 depgraph.py | sort -k2 -n
190+
```
191+
192+
For more sophisticated graph querying, you may want to look into graph libraries such as [`networkx`](https://networkx.org/).
193+
In a larger repository, it may make sense to track the health of the dependency graph and use the output
194+
of the graph export to identify parts of your codebase that would benefit from refactoring.
195+
130196
## `filedeps` - find which files a target owns
131197

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

src/python/pants/backend/awslambda/python/target_types.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,7 @@ class PythonAWSLambda(_AWSLambdaBaseTarget):
191191
f"""
192192
A self-contained Python function suitable for uploading to AWS Lambda.
193193
194-
See {doc_url('awslambda-python')}.
194+
See {doc_url('docs/python/integrations/aws-lambda')}.
195195
"""
196196
)
197197

@@ -207,7 +207,7 @@ class PythonAWSLambdaLayer(_AWSLambdaBaseTarget):
207207
f"""
208208
A Python layer suitable for uploading to AWS Lambda.
209209
210-
See {doc_url('awslambda-python')}.
210+
See {doc_url('docs/python/integrations/aws-lambda')}.
211211
"""
212212
)
213213

src/python/pants/backend/codegen/protobuf/python/python_protobuf_subsystem.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ class PythonProtobufSubsystem(Subsystem):
3535
f"""
3636
Options related to the Protobuf Python backend.
3737
38-
See {doc_url('protobuf-python')}.
38+
See {doc_url('docs/python/integrations/protobuf-and-grpc')}.
3939
"""
4040
)
4141

src/python/pants/backend/codegen/protobuf/target_types.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,8 @@ class ProtobufSourceTarget(Target):
6666
A single Protobuf file used to generate various languages.
6767
6868
See language-specific docs:
69-
Python: {doc_url('protobuf-python')}
70-
Go: {doc_url('protobuf-go')}
69+
Python: {doc_url('docs/python/integrations/protobuf-and-grpc')}
70+
Go: {doc_url('docs/go/integrations/protobuf')}
7171
"""
7272
)
7373

src/python/pants/backend/codegen/thrift/target_types.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ class ThriftSourceTarget(Target):
7272
A single Thrift file used to generate various languages.
7373
7474
See language-specific docs:
75-
Python: {doc_url('thrift-python')}
75+
Python: {doc_url('docs/python/integrations/thrift')}
7676
"""
7777
)
7878

src/python/pants/backend/codegen/utils.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ def find_python_runtime_library_or_raise_error(
5454
No `python_requirement` target was found with the module `{runtime_library_module}`
5555
in your project{for_resolve_str}, so the Python code generated from the target
5656
{codegen_address} will not work properly. See
57-
{doc_url('python-third-party-dependencies')} for how to add a requirement, such as
57+
{doc_url('docs/python/overview/third-party-dependencies')} for how to add a requirement, such as
5858
adding to requirements.txt. Usually you will want to use the
5959
`{recommended_requirement_name}` project at {recommended_requirement_url}.
6060

src/python/pants/backend/docker/target_types.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ class DockerImageTagsField(StringSequenceField):
149149
150150
{_interpolation_help.format(kind="tag")}
151151
152-
See {doc_url('tagging-docker-images')}.
152+
See {doc_url('docs/docker/tagging-docker-images')}.
153153
"""
154154
)
155155

src/python/pants/backend/google_cloud_function/python/target_types.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ class PythonGoogleCloudFunction(Target):
125125
f"""
126126
A self-contained Python function suitable for uploading to Google Cloud Function.
127127
128-
See {doc_url('google-cloud-function-python')}.
128+
See {doc_url('docs/python/integrations/google-cloud-functions')}.
129129
"""
130130
)
131131

src/python/pants/backend/python/dependency_inference/rules.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -346,7 +346,7 @@ async def _handle_unowned_imports(
346346
347347
If you do not expect an import to be inferrable, add `# pants: no-infer-dep` to the
348348
import line. Otherwise, see
349-
{doc_url('troubleshooting#import-errors-and-missing-dependencies')} for common problems.
349+
{doc_url('docs/using-pants/troubleshooting-common-issues#import-errors-and-missing-dependencies')} for common problems.
350350
"""
351351
)
352352
if unowned_dependency_behavior is UnownedDependencyUsage.LogWarning:

src/python/pants/backend/python/goals/pytest_runner.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,7 @@ async def validate_pytest_cov_included(_pytest: PyTest):
243243
`{_pytest.install_from_resolve}` used to install pytest is missing
244244
`pytest-cov`, which is needed to collect coverage data.
245245
246-
See {doc_url("python-test-goal#pytest-version-and-plugins")} for details
246+
See {doc_url("docs/python/goals/test#pytest-version-and-plugins")} for details
247247
on how to set up a custom resolve for use by pytest.
248248
"""
249249
)

src/python/pants/backend/python/goals/repl.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ def maybe_get_resolve(t: Target) -> str | None:
5454
raise NoCompatibleResolveException.bad_input_roots(
5555
root_targets,
5656
maybe_get_resolve=maybe_get_resolve,
57-
doc_url_slug="python-third-party-dependencies#multiple-lockfiles",
57+
doc_url_slug="docs/python/overview/lockfiles#multiple-lockfiles",
5858
workaround=softwrap(
5959
f"""
6060
To work around this, choose which resolve you want to use from above. Then, run

src/python/pants/backend/python/lint/flake8/subsystem.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ class Flake8(PythonToolBase):
108108
example, if your plugin is at `build-support/flake8/custom_plugin.py`, add
109109
`'build-support/flake8'` to `[source].root_patterns` in `pants.toml`. This is
110110
necessary for Pants to know how to tell Flake8 to discover your plugin. See
111-
{doc_url('source-roots')}
111+
{doc_url('docs/using-pants/key-concepts/source-roots')}
112112
113113
You must also set `[flake8:local-plugins]` in your Flake8 config file.
114114
@@ -123,7 +123,7 @@ class Flake8(PythonToolBase):
123123
directory or a subdirectory.
124124
125125
To instead load third-party plugins, add them to a custom resolve alongside
126-
flake8 itself, as described in {doc_url("python-lockfiles#lockfiles-for-tools")}.
126+
flake8 itself, as described in {doc_url("docs/python/overview/lockfiles#lockfiles-for-tools")}.
127127
"""
128128
),
129129
)

src/python/pants/backend/python/lint/pylint/subsystem.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ class Pylint(PythonToolBase):
106106
example, if your plugin is at `build-support/pylint/custom_plugin.py`, add
107107
`'build-support/pylint'` to `[source].root_patterns` in `pants.toml`. This is
108108
necessary for Pants to know how to tell Pylint to discover your plugin. See
109-
{doc_url('source-roots')}
109+
{doc_url('docs/using-pants/key-concepts/source-roots')}
110110
111111
You must also set `load-plugins=$module_name` in your Pylint config file.
112112
@@ -115,7 +115,7 @@ class Pylint(PythonToolBase):
115115
directory or a subdirectory.
116116
117117
To instead load third-party plugins, add them to a custom resolve alongside
118-
pylint itself, as described in {doc_url("python-lockfiles#lockfiles-for-tools")}.
118+
pylint itself, as described in {doc_url("docs/python/overview/lockfiles#lockfiles-for-tools")}.
119119
"""
120120
),
121121
)

src/python/pants/backend/python/packaging/pyoxidizer/rules.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ async def package_pyoxidizer_binary(
133133
The `{PyOxidizerTarget.alias}` target {field_set.address} must include
134134
in its `dependencies` field at least one `python_distribution` target that produces a
135135
`.whl` file. For example, if using `{GenerateSetupField.alias}=True`, then make sure
136-
`{WheelField.alias}=True`. See {doc_url('python-distributions')}.
136+
`{WheelField.alias}=True`. See {doc_url('docs/python/overview/building-distributions')}.
137137
"""
138138
)
139139
)

src/python/pants/backend/python/packaging/pyoxidizer/target_types.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -78,14 +78,14 @@ class PyOxidizerDependenciesField(Dependencies):
7878
7979
The distribution(s) must generate at least one wheel file. For example, if using
8080
`{GenerateSetupField.alias}=True`, then make sure `{WheelField.alias}=True`. See
81-
{doc_url('python-distributions')}.
81+
{doc_url('docs/python/overview/building-distributions')}.
8282
8383
Usually, you only need to specify a single `python_distribution`. However, if
8484
that distribution depends on another first-party distribution in your repository, you
8585
must specify that dependency too, otherwise PyOxidizer would try installing the
8686
distribution from PyPI. Note that a `python_distribution` target might depend on
8787
another `python_distribution` target even if it is not included in its own `dependencies`
88-
field, as explained at {doc_url('python-distributions')}; if code from one distribution
88+
field, as explained at {doc_url('docs/python/overview/building-distributions')}; if code from one distribution
8989
imports code from another distribution, then there is a dependency and you must
9090
include both `python_distribution` targets in the `dependencies` field of this
9191
`pyoxidizer_binary` target.
@@ -146,7 +146,7 @@ class PyOxidizerTarget(Target):
146146
A single-file Python executable with a Python interpreter embedded, built via PyOxidizer.
147147
148148
To use this target, first create a `python_distribution` target with the code you want
149-
included in your binary, per {doc_url('python-distributions')}. Then add this
149+
included in your binary, per {doc_url('docs/python/overview/building-distributions')}. Then add this
150150
`python_distribution` target to the `dependencies` field. See the `help` for
151151
`dependencies` for more information.
152152

src/python/pants/backend/python/subsystems/python_tool_base.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ class PythonToolRequirementsBase(Subsystem):
5858
If specified, install the tool using the lockfile for this named resolve.
5959
6060
This resolve must be defined in `[python].resolves`, as described in
61-
{doc_url("python-third-party-dependencies#user-lockfiles")}.
61+
{doc_url("docs/python/overview/third-party-dependencies#user-lockfiles")}.
6262
6363
The resolve's entire lockfile will be installed, unless specific requirements are
6464
listed via the `requirements` option, in which case only those requirements

src/python/pants/backend/python/subsystems/repos.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -78,19 +78,19 @@ class PythonRepos(Subsystem):
7878
7979
This feature is intended to be used with `[python-repos].find_links`, rather than PEP
8080
440 direct reference requirements (see
81-
{doc_url("python-third-party-dependencies#local-requirements")}.
81+
{doc_url("docs/python/overview/third-party-dependencies#local-requirements")}.
8282
`[python-repos].find_links` must be configured to a valid absolute path for the
8383
current machine.
8484
8585
Tip: you can avoid each user needing to manually configure this option and
8686
`[python-repos].find_links` by using a common file location, along with Pants's
87-
interpolation support ({doc_url('options#config-file-interpolation')}. For example,
87+
interpolation support ({doc_url('docs/using-pants/key-concepts/options#config-file-interpolation')}. For example,
8888
in `pants.toml`, you could set both options to `%(buildroot)s/python_wheels`
8989
to point to the directory `python_wheels` in the root of
9090
your repository; or, use the path `%(env.HOME)s/pants_wheels` for the path
9191
`~/pants_wheels`. If you are not able to use a common path like this, then we
9292
recommend setting that each user set these options via a `.pants.rc` file
93-
({doc_url('options#pantsrc-file')}.
93+
({doc_url('docs/using-pants/key-concepts/options#pantsrc-file')}.
9494
9595
Note: Only takes effect if using Pex lockfiles, i.e. using the
9696
`generate-lockfiles` goal.

src/python/pants/backend/python/subsystems/setup.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ def interpreter_constraints(self) -> tuple[str, ...]:
106106
if different parts of your codebase run against different python interpreter
107107
versions in a single repo.
108108
109-
See {doc_url("python-interpreter-compatibility")} for details.
109+
See {doc_url("docs/python/overview/interpreter-compatibility")} for details.
110110
"""
111111
),
112112
)
@@ -126,7 +126,7 @@ def interpreter_constraints(self) -> tuple[str, ...]:
126126
interpreter constraints, update `[python].interpreter_constraints`, the
127127
`interpreter_constraints` field, and relevant tool options like
128128
`[isort].interpreter_constraints` to tell Pants which interpreters your code
129-
actually uses. See {doc_url('python-interpreter-compatibility')}.
129+
actually uses. See {doc_url('docs/python/overview/interpreter-compatibility')}.
130130
131131
All elements must be the minor and major Python version, e.g. `'2.7'` or `'3.10'`. Do
132132
not include the patch version.
@@ -187,7 +187,7 @@ def interpreter_constraints(self) -> tuple[str, ...]:
187187
resolve with the `resolve` field.
188188
189189
If a target can work with multiple resolves, you can either use the `parametrize`
190-
mechanism or manually create a distinct target per resolve. See {doc_url("targets")}
190+
mechanism or manually create a distinct target per resolve. See {doc_url("docs/using-pants/key-concepts/targets-and-build-files")}
191191
for information about `parametrize`.
192192
193193
For example:
@@ -231,7 +231,7 @@ def interpreter_constraints(self) -> tuple[str, ...]:
231231
Use this version of Pip for resolving requirements and generating lockfiles.
232232
233233
The value used here must be one of the Pip versions supported by the underlying PEX
234-
version. See {doc_url("pex")} for details.
234+
version. See {doc_url("docs/python/overview/pex")} for details.
235235
236236
N.B.: The `latest` value selects the latest of the choices listed by PEX which is not
237237
necessarily the latest Pip version released on PyPI.

src/python/pants/backend/python/subsystems/twine.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ class TwineSubsystem(PythonToolBase):
7878
7979
This option cannot be overridden via environment targets, so if you need a different
8080
value than what the rest of your organization is using, override the value via an
81-
environment variable, CLI argument, or `.pants.rc` file. See {doc_url('options')}.
81+
environment variable, CLI argument, or `.pants.rc` file. See {doc_url('docs/using-pants/key-concepts/options')}.
8282
"""
8383
),
8484
)

0 commit comments

Comments
 (0)