-
Notifications
You must be signed in to change notification settings - Fork 3.2k
Description
Environment
- pip version: >=19.3 (i.e. post PEP 592 implementation)
- Python version: All
- OS: All
Description
Currently PackageFinder issues a warning immediately when it decides a yanked link is the chosen as “best”:
pip/src/pip/_internal/index/package_finder.py
Lines 548 to 576 in daff811
| def sort_best_candidate( | |
| self, | |
| candidates, # type: List[InstallationCandidate] | |
| ): | |
| # type: (...) -> Optional[InstallationCandidate] | |
| """ | |
| Return the best candidate per the instance's sort order, or None if | |
| no candidate is acceptable. | |
| """ | |
| if not candidates: | |
| return None | |
| best_candidate = max(candidates, key=self._sort_key) | |
| # Log a warning per PEP 592 if necessary before returning. | |
| link = best_candidate.link | |
| if link.is_yanked: | |
| reason = link.yanked_reason or '<none given>' | |
| msg = ( | |
| # Mark this as a unicode string to prevent | |
| # "UnicodeEncodeError: 'ascii' codec can't encode character" | |
| # in Python 2 when the reason contains non-ascii characters. | |
| u'The candidate selected for download or install is a ' | |
| 'yanked version: {candidate}\n' | |
| 'Reason for being yanked: {reason}' | |
| ).format(candidate=best_candidate, reason=reason) | |
| logger.warning(msg) | |
| return best_candidate |
There are fouer code paths in pip that can reach it. One of them (self_outdated_check.pip_self_version_check) never triggers the warning since the finder is constructed to exclude all yanked versions. Two are in the legacy resolver. The legacy resolver always selects the best available candidate. So the warning is valid because user should be warned if that candidate is yanked.
The other path is from the new resolver, which presents a problem. The candidate it chooses may be “unchosen” later (i.e. backtracking). The result is PackageFinder may show yanked warnings for candidates that are chosen during resolution but eventually discarded.
I worked on this briefly in #7796 but abandoned the work because there’s no easy way to refactor it, and the issue was only theoratical at the time anyway. But now we have the new resolver out for testing, and that PyPI actually starts supporting yanking, we’ll need to look into this soon.
Expected behavior
I think the warning needs to be moved into the resolver. This is not too difficult for the legacy resolver; just move it to the call site. It will be more difficult for the new resolver. We can issue a warning only when we know for sure the candidate is chosen (i.e. after the resolution completes), but before the link is resolved to the wheel cache (otherwise be loose the yank information). But OTOH the cache resolution must be done during the resolution (to fetch package metadata). So some additional refactoring is likely needed to make this work.