-
-
Notifications
You must be signed in to change notification settings - Fork 651
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[internal] Add experimental ./pants lock
to generate a lockfile with pip-compile
#12300
Conversation
…h pip-compile # Rust tests and lints will be skipped. Delete if not intended. [ci skip-rust]
# TODO: What should the input to `./pants lock` be when generating user lockfiles? Currently, it's | ||
# the 3rd-party requirements that get used as input. Likely it should instead be all 3rd party | ||
# reqs used by the transitive closure? That would better mirror generate_lockfile.sh. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pretty sure the comment's proposed semantics are more correct
EDIT: we should probably defer this discussion for the dedicated PR. I'm thinking this PR should mostly be about simply using pip-compile
. That way, we can have a more robust discussion there where I can give the full context and design process.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I tend to agree.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1
This probably doesn't need to be exposed as a goal at all (in this PR)...?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's helpful for me to have a goal to run when iterating. But feature gated behind the experimental backend
# TODO: Figure out which interpreter constraints to use...Among other reasons, this is | ||
# tricky because python_requirement_library targets don't have interpreter constraints! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this will come from the transitive closure of the code using the 3rd party reqs, with a default to [python-setup].interpreter_constraints
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Correct. With one permutation (templated copy á la lock-%p-%i
) per platform (%s
) and interpreter constraint (%i
).
FYI @wilsonliam and @chrisjrn , who will likely work on some tickets related to lockfiles. Also FYI @jsirois |
# Rust tests and lints will be skipped. Delete if not intended. [ci skip-rust] # Building wheels and fs_util will be skipped. Delete if not intended. [ci skip-build-wheels]
# Rust tests and lints will be skipped. Delete if not intended. [ci skip-rust] # Building wheels and fs_util will be skipped. Delete if not intended. [ci skip-build-wheels]
# TODO: What should the input to `./pants lock` be when generating user lockfiles? Currently, it's | ||
# the 3rd-party requirements that get used as input. Likely it should instead be all 3rd party | ||
# reqs used by the transitive closure? That would better mirror generate_lockfile.sh. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I tend to agree.
# Rust tests and lints will be skipped. Delete if not intended. [ci skip-rust] # Building wheels and fs_util will be skipped. Delete if not intended. [ci skip-build-wheels]
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks!
# TODO: How should users indicate where to save the lockfile to when we have per-tool | ||
# lockfiles and mmultiple user lockfiles? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One approach would be to have a resolve(name=..)
target type, with optional parameters for overriding some default lockfile templates. To use it, you would declare one in some directory, and then when it was actually consumed by a *_binary
target, the lockfiles would be produced next to it at the templated paths (templated by platform * interpreter_constraint * etc).
A downside of that modeling though is that it means that whatever our "default" global resolve is would be a bit magical. We don't want folks to have to declare one of these just to get started with Pants. Not sure how to fix that mismatch... maybe with a setting instead...?: [resolves] resolve_mapping = "{'default': '3rdparty/python/lock%p-%i', 'custom_for_aws': '3rdparty/python/aws_lock%p-%i'}"
.
# TODO: What should the input to `./pants lock` be when generating user lockfiles? Currently, it's | ||
# the 3rd-party requirements that get used as input. Likely it should instead be all 3rd party | ||
# reqs used by the transitive closure? That would better mirror generate_lockfile.sh. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1
This probably doesn't need to be exposed as a goal at all (in this PR)...?
# TODO: Figure out which interpreter constraints to use...Among other reasons, this is | ||
# tricky because python_requirement_library targets don't have interpreter constraints! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Correct. With one permutation (templated copy á la lock-%p-%i
) per platform (%s
) and interpreter constraint (%i
).
argv=[ | ||
"requirements.in", | ||
"--generate-hashes", | ||
f"--output-file={dest}", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this output format something that PEX can consume...? Should PEX be delegating to pip_tools
in order to put the fetched stuff in its cache...?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, and speaking of caching: should this be configured to use a named_cache
(until PEX is invoking it)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Interesting on caching. The --output-file is a literal requirements.txt file.
I haven't investigated yet how pip-tools is doing the fetching and where it gets cached, but fwict it delegates to Pip. That makes sense to try to share that cache with Pex, and at a minimum to use a dedicated named_cache. I'll add a TODO in the next PR.
I think that the lock goal should not have any particular spec semantics: there will need to be some underlying reusable
The first two points are the hand-waviest. Figuring out how to do this without full runs of |
Internal changes omitted from the release notes: * [internal] `./pants lock` uses transitive closure as inputs ([pantsbuild#12312](pantsbuild#12312)) * [internal] Add experimental `./pants lock` to generate a lockfile with pip-compile ([pantsbuild#12300](pantsbuild#12300)) * upgrade tokio and futures crates ([pantsbuild#12308](pantsbuild#12308)) * upgrade tonic, tower, and hyper crates ([pantsbuild#12294](pantsbuild#12294)) * Set up pants to use the latest version of humbug ([pantsbuild#12302](pantsbuild#12302)) * Refactor BUILD file parsing. ([pantsbuild#12279](pantsbuild#12279)) * Use get_type_hints() to get typed type hints. ([pantsbuild#12287](pantsbuild#12287)) * [internal] Fix parameters of convert_source_to_sources_test ([pantsbuild#12274](pantsbuild#12274)) * Fix assert arguments in a test ([pantsbuild#12273](pantsbuild#12273)) * Introduce a native pants client. ([pantsbuild#11922](pantsbuild#11922)) * Don't run CI in forks ([pantsbuild#12267](pantsbuild#12267)) * Change how we embed docsite links in help text. ([pantsbuild#12261](pantsbuild#12261))
Internal changes omitted from the release notes: * [internal] `./pants lock` uses transitive closure as inputs ([pantsbuild#12312](pantsbuild#12312)) * [internal] Add experimental `./pants lock` to generate a lockfile with pip-compile ([pantsbuild#12300](pantsbuild#12300)) * upgrade tokio and futures crates ([pantsbuild#12308](pantsbuild#12308)) * upgrade tonic, tower, and hyper crates ([pantsbuild#12294](pantsbuild#12294)) * Set up pants to use the latest version of humbug ([pantsbuild#12302](pantsbuild#12302)) * Refactor BUILD file parsing. ([pantsbuild#12279](pantsbuild#12279)) * Use get_type_hints() to get typed type hints. ([pantsbuild#12287](pantsbuild#12287)) * [internal] Fix parameters of convert_source_to_sources_test ([pantsbuild#12274](pantsbuild#12274)) * Fix assert arguments in a test ([pantsbuild#12273](pantsbuild#12273)) * Introduce a native pants client. ([pantsbuild#11922](pantsbuild#11922)) * Don't run CI in forks ([pantsbuild#12267](pantsbuild#12267)) * Change how we embed docsite links in help text. ([pantsbuild#12261](pantsbuild#12261))
Internal changes omitted from the release notes: * [internal] `./pants lock` uses transitive closure as inputs ([pantsbuild#12312](pantsbuild#12312)) * [internal] Add experimental `./pants lock` to generate a lockfile with pip-compile ([pantsbuild#12300](pantsbuild#12300)) * upgrade tokio and futures crates ([pantsbuild#12308](pantsbuild#12308)) * upgrade tonic, tower, and hyper crates ([pantsbuild#12294](pantsbuild#12294)) * Set up pants to use the latest version of humbug ([pantsbuild#12302](pantsbuild#12302)) * Refactor BUILD file parsing. ([pantsbuild#12279](pantsbuild#12279)) * Use get_type_hints() to get typed type hints. ([pantsbuild#12287](pantsbuild#12287)) * [internal] Fix parameters of convert_source_to_sources_test ([pantsbuild#12274](pantsbuild#12274)) * Fix assert arguments in a test ([pantsbuild#12273](pantsbuild#12273)) * Introduce a native pants client. ([pantsbuild#11922](pantsbuild#11922)) * Don't run CI in forks ([pantsbuild#12267](pantsbuild#12267)) * Change how we embed docsite links in help text. ([pantsbuild#12261](pantsbuild#12261)) * Add JavacSubsystem and JavacBinary, allowing user-configurable JVM selection ([pantsbuild#12283](pantsbuild#12283)) * Revert "Deprecate unused `--process-execution-local-enable-nailgun` (pantsbuild#11600)" ([pantsbuild#12257](pantsbuild#12257))
Internal changes omitted from the release notes: * [internal] `./pants lock` uses transitive closure as inputs ([#12312](#12312)) * [internal] Add experimental `./pants lock` to generate a lockfile with pip-compile ([#12300](#12300)) * upgrade tokio and futures crates ([#12308](#12308)) * upgrade tonic, tower, and hyper crates ([#12294](#12294)) * Set up pants to use the latest version of humbug ([#12302](#12302)) * Refactor BUILD file parsing. ([#12279](#12279)) * Use get_type_hints() to get typed type hints. ([#12287](#12287)) * [internal] Fix parameters of convert_source_to_sources_test ([#12274](#12274)) * Fix assert arguments in a test ([#12273](#12273)) * Introduce a native pants client. ([#11922](#11922)) * Don't run CI in forks ([#12267](#12267)) * Change how we embed docsite links in help text. ([#12261](#12261)) * Add JavacSubsystem and JavacBinary, allowing user-configurable JVM selection ([#12283](#12283)) * Revert "Deprecate unused `--process-execution-local-enable-nailgun` (#11600)" ([#12257](#12257))
This allows you to use the new lockfile format, generated by pip-tools via `./pants --tag=-lockfile_ignore lock ::` and #12300. A lockfile cannot be used at the same time as a constraints file. This makes the code easier to implement and means that we don't break any prior APIs. We will likely deprecate constraints when the dust settles. There are several major deficiencies: - Only `pex_from_targets.py` consumes this lockfile. This means that tool lockfiles will now have no constraints and no lockfile, for now. - Does not handle requirements disjoint to the lockfile. - Does not support multiple user lockfiles, which, for example, is necessary to properly handle `platforms` with `pex_binary` and `python_awslambda`: we need one lockfile per platform, as demonstrated in https://github.com/Eric-Arellano/lockfile-platforms-problem/tree/main/multiple_pex__stu_proposal. ### Lockfile vs. constraints file (and `[python-setup].resolve_all_constraints`) We're currently using pip's `--constraints` file support, which allows you to specify constraints that may not actually be used. At the same time, we default to `[python-setup].resolve_all_constraints`, which _does_ first install the entire constraints file, and then uses Pex's repository PEX feature to extract the relevant subset. This is generally a performance optimization, but there are some times `--resolve-all-constraints` is not desirable: 1. It is not safe to first install the superset, and you can only install the proper subset. This especially can happen when `platforms` are used. See #12222. - We proactively disable `--resolve-all-constraints` when `platforms` are used. 2. User does not like the performance tradeoff, e.g. because they have a huge repository PEX so it's slow to access. -- In contrast, this PR stops using `--constraints` and roughly always does `[python-setup].resolve_all_constraints` (we now run `pex -r requirements.txt --no-transitive` and use repository PEXes). Multiple user lockfiles will allow us to solve the above issues: > 1. It is not safe to first install the superset, and you can only install the proper subset. We'll have a distinct lockfile for each `platform`, which avoids this situation. See https://github.com/Eric-Arellano/lockfile-platforms-problem/tree/main/multiple_pex__stu_proposal for an example. > 2. User does not like the performance tradeoff They can use multiple lockfiles to work around this. -- Always using `[python-setup].resolve_all_constraints` reduces complexity: less code to support, fewer concepts for users to learn. Likewise, if we did still want to use `--constraints`, we would also need to upgrade Pex to use Pip 21+, which gained support for URL constraints. We [hacked around URL constraints before](#11907), but that isn't robust. However, Pip 21+ drops Python 2 and 3.5 support: we'd need to release Pex 3 w/o Py2 support, and upgrade Pants to have workarounds that allow Py2 to still be used. To avoid project creep, it's better to punt on Pex 3. [ci skip-rust] [ci skip-build-wheels]
With this goal, you can run
./pants lock 3rdparty/python::
to create a lockfile using pip-compile. For example:This is still very experimental, and there are many unresolved questions. The intent with landing this is to have a foundation to start iterating on and answering design questions.
Why pip-compile
There are several known ways to generate a lockfile in Python:
pip freeze
.Pip-compile offers a robust out-of-the-box solution with several benefits:
pip freeze
, only downloads and does the minimum work necessary.Lockfiles vs. constraints files
Note that this generates a "lockfile", not a "constraints" file, which we have confusingly been calling the same thing. Among other differences, a lockfile can include extra like
requests[security]
, which choke with a constraints file.Next steps
./pants lock
so that the lockfile is based on what gets used by your code, rather than what reqs are defined in your universe.[ci skip-rust]