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

Simplify InstallRequirement.uninstall #7422

Merged
merged 26 commits into from
Dec 3, 2019

Conversation

chrahunt
Copy link
Member

@chrahunt chrahunt commented Dec 3, 2019

Previously InstallRequirement.uninstall was using InstallRequirement.check_if_exists, which is a very overloaded function with several callers that operate at different phases in pip processing, not to mention that it mutates InstallRequirement itself.

Now we don't use that function for InstallRequirement.uninstall.

This opens the door to allow scheme-based pip uninstall without too much trouble (e.g. #5595). Scheme-based pip install pre-upgrade uninstallation will need to come later, but should be simpler because of this refactoring.

There should be no behavior change here. I went in very small steps (which should each pass our tests) to hopefully make that easier to verify. This also makes it possible to break off several chunks at a time to validate in individual PRs, if needed.

Please let me know if anything is unclear!

@chrahunt chrahunt added the skip news Does not need a NEWS file entry (eg: trivial changes) label Dec 3, 2019
@chrahunt chrahunt changed the title Refactor/simpler uninstall check 2 Simplify InstallRequirement.uninstall Dec 3, 2019
@chrahunt chrahunt added the type: refactor Refactoring code label Dec 3, 2019
@chrahunt chrahunt marked this pull request as ready for review December 3, 2019 03:44
This is not passed by either `UninstallCommand` or `install_given_reqs`
(the only two callers), so we can remove it.
`InstallRequirement.check_if_exists` is called in several places for
dependency resolution and uninstall. We make a copy of the existing
function and only change the name so it's possible to simplify
it while only considering the uninstall use case.
Since the condition is now obviously False we can drop this code.
There are two callers to `uninstall`:

1. `pip uninstall` - as indicated, only named requirements are ever
   used
2. `pip install` via `req.install_given_reqs` - which since uninstall is
   only called when `conflicts_with` is set, must already be named

In case we're worried about this being relevant for the `pip uninstall
.` case (as requested in the issue tracker), we can worry about it later -
all this code will look very different by the time we get around to
implementing that.
In the next step we can inline this to simplify
`check_if_exists_uninstall`.
We map `False` to `None` and `True` to
`self.satisfied_by or self.conflicts_with`. This simplifies the
uninstall function and will let us do some cancellation in
check_with_exists_uninstall without too much hassle.
This is the default value which is only ever set in
InstallRequirement.check_if_exists, which isn't called before this
point in `pip uninstall`.
`satisfied_by` is only set to a non-`None` value by `check_if_exists`.

In the error case where `satisfied_by` is not set, `check_if_exists`
may set `conflicts_with`. The only other time `conflicts_with` is set is
if we have taken its value from `satisfied_by` and then immediately set
`satisfied_by = None`. So `satisfied_by` must be `None` here.
Since all (both) callers have this assertion, we can assert the same in
the called functions.
At least not after uninstall, based on inspection of `UninstallCommand`
and `InstallCommand`/`install_given_reqs`.
Since we previously enforced that `satisfied_by` and `conflicts_with`
aren't used after install, we can simplify without worrying about
preserving the member assignment side-effect.
pkg_resources.get_distribution either returns a Distribution or raises
an exception, so this will always be true.
To make it easier to review how we simplify the rest of this function.
Since `self.satisfied_by` will always be set, as mentioned before,
`self.conflicts_with` will never be returned here.
Also remove now-unnecessary assertions.
Because we aren't setting these values anymore, these "assertions"
aren't doing anything useful.
Instead of trying name + (optional) version and falling back to just
name, we just use name outright which can't fail with a version
exception.
The single assert in `InstallRequirement.uninstall` covers these cases.
@chrahunt chrahunt force-pushed the refactor/simpler-uninstall-check-2 branch from 1bd684b to e5d4b1c Compare December 3, 2019 06:02
@chrahunt
Copy link
Member Author

chrahunt commented Dec 3, 2019

Updated to remove some extraneous style changes.

Copy link
Member

@xavfernandez xavfernandez left a comment

Choose a reason for hiding this comment

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

Quite a lot of commits but it makes the logic behind the change slightly easier to review 👍

@chrahunt
Copy link
Member Author

chrahunt commented Dec 3, 2019

Thanks for reviewing! I figured any other way would end up being pretty wordy with a lot of justification or push the burden of checking their equivalence on whoever reviewed. I will squash these since they're only useful for review.

@chrahunt chrahunt merged commit d3419a4 into pypa:master Dec 3, 2019
@chrahunt chrahunt deleted the refactor/simpler-uninstall-check-2 branch December 3, 2019 23:20
@pradyunsg
Copy link
Member

This is a great PR! Thanks for taking the time to make such a detailed PR! :)

@lock lock bot added the auto-locked Outdated issues that have been locked by automation label Jan 3, 2020
@lock lock bot locked as resolved and limited conversation to collaborators Jan 3, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
auto-locked Outdated issues that have been locked by automation skip news Does not need a NEWS file entry (eg: trivial changes) type: refactor Refactoring code
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants