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
Support Python requirement target addrs in tool requirements. #19014
Conversation
@@ -344,7 +352,7 @@ def to_pex_request( | |||
return PexRequest( | |||
output_filename=f"{self.options_scope.replace('-', '_')}.pex", | |||
internal_only=True, | |||
requirements=self.pex_requirements(extra_requirements=extra_requirements), | |||
requirements=requirements, |
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.
This call to self.pex_requirements() was redundant even before any of the other changes in this PR, so this is just an obvious cleanup.
@@ -333,13 +333,8 @@ class _PexRequirementsRequest: | |||
async def determine_requirement_strings_in_closure( | |||
request: _PexRequirementsRequest, global_requirement_constraints: GlobalRequirementConstraints | |||
) -> PexRequirements: | |||
transitive_targets = await Get(TransitiveTargets, TransitiveTargetsRequest(request.addresses)) |
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.
This computation is now pushed to later.
@classmethod | ||
def req_strings_from_requirement_fields( | ||
cls, fields: Iterable[PythonRequirementsField] | ||
) -> FrozenOrderedSet[str]: | ||
"""A convenience when you only need the raw requirement strings from fields and don't need | ||
to consider things like constraints or resolves.""" | ||
return cls.create_from_requirement_fields(fields, constraints_strings=()).req_strings | ||
return FrozenOrderedSet( |
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.
This should always have been implemented this way. It seems like a silly oversight that it was implemented using a transient object returned by create_from_requirement_fields
. Fixing this allows us to delete create_from_requirement_fields entirely.
Note for reviewers: I wanted to get feedback on the approach. Am working on adding some tests. |
addrs.append(req_str_or_addr) | ||
else: | ||
assert isinstance(req_str_or_addr, str) | ||
# A local or VCS requirement will have an ampersand in it, and any other |
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.
Reviewers, do you concur?
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 so. But you could also explicitly recommend prefixing an address with //
in case of ambiguity, and skip the @
check (note: not ampersand).
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.
Whoops, I meant asperand.
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.
We would have to require prefixing, we can't just recommend it. Otherwise we'll see vcs/local requirements as addresses with no escape hatch.
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.
And yeah, I think we should require the //
prefix, because apparently wheel paths can be treated as requirements.
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.
Looks good, thanks!
addrs.append(req_str_or_addr) | ||
else: | ||
assert isinstance(req_str_or_addr, str) | ||
# A local or VCS requirement will have an ampersand in it, and any other |
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 so. But you could also explicitly recommend prefixing an address with //
in case of ambiguity, and skip the @
check (note: not ampersand).
# TODO: Plumb the origin through in PexRequirements? | ||
description_of_origin="User-specified requirements", |
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.
That would probably be good, yea... maybe as an optional field (initially), at the very least? I would be less concerned about this, but particularly since heuristics are being used to distinguish addresses from requirements...
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.
BTW there may be a future cleanup (post removing tool lockfiles) where this only takes addresses, I'd have to dive more deeply to be sure.
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.
Switched to requiring the //
prefix, for extra security (really I just check for a single /
).
Also added descriptions of origin.
Also add documentation, and apply this in the Pants repo.
PTAL
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!
# Require a `//` prefix, to distinguish address specs from | ||
# local or VCS requirements. | ||
if req_str_or_addr.startswith(os.path.sep): |
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.
This should probably be double //
, otherwise it's ambiguous with what someone might try as an absolute file path.
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.
An absolute file path is definitely not any kind of valid requirement, but sure.
…uild#19014) Currently users can enumerate `requirements` for a Python tool, which will cause Pants to use that requirement subset from the tool's lockfile. This supports resolving a tool from a larger lockfile, when that makes sense. If no requirements are provided the entire lockfile is used. Two examples of when resolving a tool from a subset of a larger lockfile is useful: 1. Resolving `pytest` as a tool at the same version as its runtime library without specifying it in two places. 2. Having a single lockfile for all tools, and user code, to be consumed by VSCode. However, the value of this `requirements` option is typically redundant with the input requirements used to generate the lockfile. This change allows `requirements` to specify addresses (or address specs). This can be used to avoid the redundancy: You can point to some python_requirement targets that are a subset of all those used to generate the lockfile. The implementation turns out to be reasonably neat, as it just pushes some code that turns addresses into requirement strings to slightly later in the pex creation logic, and actually allowed us to reduce some redundancy and trim some code. This fixes pantsbuild#18816.
…-pick of #19014) (#19023) Currently users can enumerate `requirements` for a Python tool, which will cause Pants to use that requirement subset from the tool's lockfile. This supports resolving a tool from a larger lockfile, when that makes sense. If no requirements are provided the entire lockfile is used. Two examples of when resolving a tool from a subset of a larger lockfile is useful: 1. Resolving `pytest` as a tool at the same version as its runtime library without specifying it in two places. 2. Having a single lockfile for all tools, and user code, to be consumed by VSCode. However, the value of this `requirements` option is typically redundant with the input requirements used to generate the lockfile. This change allows `requirements` to specify addresses (or address specs). This can be used to avoid the redundancy: You can point to some python_requirement targets that are a subset of all those used to generate the lockfile. The implementation turns out to be reasonably neat, as it just pushes some code that turns addresses into requirement strings to slightly later in the pex creation logic, and actually allowed us to reduce some redundancy and trim some code. This addresses #18816.
Currently users can enumerate
requirements
for a Python tool, which will causePants to use that requirement subset from the tool's lockfile. This supports resolving
a tool from a larger lockfile, when that makes sense. If no requirements are provided
the entire lockfile is used.
Two examples of when resolving a tool from a subset of a larger lockfile is useful:
pytest
as a tool at the same version as its runtime library withoutspecifying it in two places.
However, the value of this
requirements
option is typically redundant with theinput requirements used to generate the lockfile.
This change allows
requirements
to specify addresses (or address specs).This can be used to avoid the redundancy: You can point to some
python_requirement targets that are a subset of all those used to generate
the lockfile.
The implementation turns out to be reasonably neat, as it just pushes
some code that turns addresses into requirement strings to slightly
later in the pex creation logic, and actually allowed us to reduce some
redundancy and trim some code.
This addresses #18816.