Skip to content
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

refactor(pip_install): make the API surface of deps parsing smaller #1657

Merged
merged 5 commits into from
Jan 9, 2024

Conversation

aignas
Copy link
Collaborator

@aignas aignas commented Dec 28, 2023

With this change we also fix a minor bug where the self edge dependencies
within the wheels are correctly handled as per unit tests.

Also refactor the code to use the fact that the selects are chosen
based on the specificity of the condition. This can make the addition
of deps incrementally correct without the need for extra processing in
the build method. This should hopefully make the implementation more
future-proof as it makes use of these generic concepts and is likely to
help to extend this code to work with selecting on multiple Python versions.

I have added a test to ensure coverage of the new code.

@aignas aignas force-pushed the fix/make-deps-api-surface-smaller branch from 57aeec2 to d1c7bc9 Compare December 28, 2023 23:32
@aignas
Copy link
Collaborator Author

aignas commented Jan 5, 2024

When you have time, please take a look @rickeylev. My end-goal would be to support parsing the metadata to support select statements with version aware python toolchain config settings, which should hopefully land in another PR.

Copy link
Contributor

@rickeylev rickeylev left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, ran out of time tonight to review in full; only got like 10 lines into it.

internal_deps.bzl Outdated Show resolved Hide resolved
Copy link
Contributor

@rickeylev rickeylev left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm guessing the loop I'm confused by (and looks like a bug?) is just me not understanding the flow. So I'll approve. But i would like to wrap my head around it a bit.

Rest of my comments are mostly nits/doc requests.

internal_deps.bzl Outdated Show resolved Hide resolved
python/pip_install/tools/wheel_installer/wheel.py Outdated Show resolved Hide resolved
python/pip_install/tools/wheel_installer/wheel.py Outdated Show resolved Hide resolved
python/pip_install/tools/wheel_installer/wheel.py Outdated Show resolved Hide resolved
key=lambda x: f"{x.name}:{sorted(x.extras)}",
)

# Resolve any extra extras due to self-edges, empty string means not extras
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I commented on the empty string thing in an earlier PR; this empty string thing is confusing.

Does the presence of the empty string mean no extras? i.e. are {"", "foo"} Or is it assumed that an empty string element is mutually exclusive with other elements? Why is "no extras" communicated using set-with-only-empty-string as opposed to empty-set ?

(I've authored and had to maintain code where None vs empty set vs non-empty set have 3 different meanings, and it was always a cognitive burden)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right now the case of {"", "foo"} and {"foo"} has the same meaning. I moved this detail into the method implementation to better isolate it from the rest of the code as it is an implementation detail. The return value of _resolve_extras should be always a set with at least one element in it and it just makes the matching with any(...) easier to write.

Comment on lines 271 to 287
# Add the platform-specific dep
self._select[platform].add(dep)

def add(self, *wheel_reqs: str) -> None:
reqs = [Requirement(wheel_req) for wheel_req in wheel_reqs]
# Add the dep to more specific constraints
for p in platform:
if p not in self._select:
continue

# Resolve any extra extras due to self-edges
self._want_extras = self._resolve_extras(reqs)
self._select[p].add(dep)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The if p not in self._select part of this block of code is confusing me.

The iteration will produce one of two list of values:

  1. Exactly one element: self (may or may not have arch set)
  2. Two or more elements: self (without an arch) and one or more with arch set.

In case one, L279 duplicates what L272 did: the loop is one element long, p is present, and L279 executes, and we're done.

In case two, the same thing happens: the loop is 1 + N long. The first element does L279 (duplicating L272), and then subsequent iterations do nothing (the arch-bound platform isn't present).

What am I missing? That some earlier add_req() call added an entry? But then wouldn't that mean some of these were ignored when they shouldn't have been...? or maybe the loop below has something to do with this? I think if I could see the requirements lines being processed it'd be easier for me to reason about.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a unit-test and more comments to hopefully make the code more self-explanatory.

With this change we also fix a minor bug where the self
edge dependencies within the wheels are correctly handled
as per unit tests.
Use the fact that the selects are chosen based on the specificity
of the condition and also make the manipulation of the deps correct
through iteration of each Requires-Dist so that we don't need to
do any post-processing in the build() function. This should hopefully
make the extension to supporting python version, interpreter implementation
and others easier as we are generalizing what the Platform and Deps
data structures can do.

I have added a test to ensure coverage of the new code.
It tries to cleanup the usage of generators and refactors the tests
a little bit more so that we have more isolated test cases.
@aignas aignas force-pushed the fix/make-deps-api-surface-smaller branch from d1c7bc9 to fef4ac5 Compare January 8, 2024 23:47
@aignas aignas enabled auto-merge January 9, 2024 00:19
@aignas aignas added this pull request to the merge queue Jan 9, 2024
Merged via the queue into bazelbuild:main with commit 6d0d514 Jan 9, 2024
4 checks passed
@aignas aignas deleted the fix/make-deps-api-surface-smaller branch May 13, 2024 06:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants