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

2020 resolver: list out helpful info on basic resolution failures #9405

Merged
merged 2 commits into from
Feb 28, 2021

Conversation

MrMino
Copy link
Contributor

@MrMino MrMino commented Dec 31, 2020

Fixes #9139

Adds the old diagnostic information ("from versions:") to the new resolver.


If there was a failure in resolution of a requirement that stemmed from
a simple fact of there being no candidate found that could possibly
satisfy it, make pip output diagnostic information about which versions
of the package are available to pip (outputs "(none)" if there weren't any).


Note: since finder.find_all_candidates() uses lru_cache, this avoids performing additional API calls to PyPI.

@MrMino MrMino force-pushed the diagnostic_aversion branch 2 times, most recently from 50f6fdc to 7a5ab7f Compare December 31, 2020 02:42
@MrMino

This comment has been minimized.

@pradyunsg
Copy link
Member

Thanks for the PR! Could you also show a sample of how this looks, so that we can discuss the design before we dive into the implementation?

@MrMino

This comment has been minimized.

@MrMino MrMino changed the title List out helpful info on basic resolution failures New resolver: list out helpful info on basic resolution failures Dec 31, 2020
@MrMino MrMino changed the title New resolver: list out helpful info on basic resolution failures 2020 resolver: list out helpful info on basic resolution failures Dec 31, 2020
f"Cache dir:\n"
f"{cache_dir or '(not used)'}"
)
logger.warning(diagnostic_hint)
Copy link
Member

@uranusjr uranusjr Dec 31, 2020

Choose a reason for hiding this comment

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

The approach lgtm, but the message formatting is much too complicated imo. I would simplify this to something like

Available versions: <list of versions joined by comma>
Sources:
  <list of source URLs joined by newline and indented>

Some points to note:

  • The project name is already shown in the message directly above and would be duplicated info here.
  • Available versions need to be sorted to be readable (they are not right now).
  • Showing the cache directory is not useful imo. Cache is only a factor during package build and install, not here.
  • comes_from is not necessarily an index page.

Copy link
Contributor Author

@MrMino MrMino Jan 1, 2021

Choose a reason for hiding this comment

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

Thanks.

The project name is already shown in the message directly above and would be duplicated info here.

Correct. Removed

Available versions need to be sorted to be readable (they are not right now).

Added sorting to versions using distutils.version.LooseVersion. Indexes are now sorted too, as to ensure that they don't jump around on different runs.

Showing the cache directory is not useful imo.

Yea, I guess even if it was, you might as well just do pip cache info. Having it in every one of these outputs is just too verbose anyway. I removed it.

comes_from is not necessarily an index page.

Huh? What else could it be at that point? Replaced Index(es): with Sources:.

This is how it looks right now:
after

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I've also removed the empty newlines, so now it looks like this:
after2

Copy link
Member

Choose a reason for hiding this comment

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

Instead of making this a separate logging.warning call, I think we should be adding this information to the original logging.critical call.

Copy link
Member

Choose a reason for hiding this comment

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

Added sorting to versions using distutils.version.LooseVersion

We should use the version type from packaging. I don't think we should add a dependency on distutils here, as Python core is planning on removing that at some point.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@pfmoore I didn't know about that. Will do.
@pradyunsg The point of doing that was to make it different from the error messages, as - technically - these aren't, and for readability. I can change that too, no problem there.

Copy link
Member

Choose a reason for hiding this comment

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

"Could not find a version, here are the versions" is OK as an error message. I don't think we need to make it look distinct or whatever.

Copy link
Member

Choose a reason for hiding this comment

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

Huh? What else could it be at that point? Replaced Index(es): with Sources:.

PackageFinder also looks at find-links pages, which are technically not package indexes.

This reminds me though, we should add a check and display this whole message only when the user did not specify any direct URL requirements on the package. It would be quite confusing IMO if the user specify foo @ git+https://github.com/... and pip displays this.

Copy link
Contributor Author

@MrMino MrMino Jan 2, 2021

Choose a reason for hiding this comment

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

@pfmoore Done.
@pradyunsg Done. This is a comparison of the before / after:
2021-01-02_15-34

Copy link
Contributor Author

@MrMino MrMino Jan 2, 2021

Choose a reason for hiding this comment

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

@uranusjr The sources section has been removed. Not sure how to go about the foo@git+... thing though. I was of the impression that it is not possible to get a ResolutionImpossible exception when doing that.

src/pip/_internal/resolution/resolvelib/factory.py Outdated Show resolved Hide resolved
f"Cache dir:\n"
f"{cache_dir or '(not used)'}"
)
logger.warning(diagnostic_hint)
Copy link
Member

Choose a reason for hiding this comment

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

"Could not find a version, here are the versions" is OK as an error message. I don't think we need to make it look distinct or whatever.

@pfmoore
Copy link
Member

pfmoore commented Jan 2, 2021

Also, can I go on record as saying that while reporting the available versions in case of an error is a reasonable thing to do, I am absolutely against making pip install foo== the supported way of asking "what versions of foo exist?"

If that functionality is useful (and I can see that it is) then it should be a command in its own right. And invalid requirement specifiers like foo== should be rejected. I feel that allowing an empty version is a bug in packaging.specifiers.SpecifierSet which should be fixed - I can see nothing in PEP 440 which suggests that it's valid, or why it should be valid.

@MrMino

This comment has been minimized.

@MrMino MrMino requested a review from pradyunsg January 2, 2021 15:45
@MrMino
Copy link
Contributor Author

MrMino commented Jan 2, 2021

@pradyunsg
I've brought back the original report format. Here's the comparison.
2021-01-02_17-06

@pfmoore
Copy link
Member

pfmoore commented Jan 2, 2021

@MrMino I'm not going to get into an extended debate on this. I've stated my opinion and I stick by it. Other pip maintainers may differ, and if so we'll come to a consensus at some point. None of which alters the fact that this is useful as diagnostic data after an error. (Which is how I'd prefer to frame this PR).

IMO there's no reasonable way to interpret PEP 440 as allowing foo== as a valid specifier, so I think that packaging should reject it (and as a consequence, pip would never try to resolve). If and when that happens¹, pip should have an alternative available (in the form of a "list available versions" subcommand), rather than complaining that packaging "has" to support it.

¹ Normally, I'd raise a bug report against packaging. I'm not doing so at the moment in this case as I feel that would be needlessly passive-aggressive given that pip users do value this loophole currently.

@MrMino
Copy link
Contributor Author

MrMino commented Jan 2, 2021

I'm not going to get into an extended debate on this.

@pfmoore I was asking to find a good mental model that would make me understand your position. Alright - I won't go into that here anymore.

@pfmoore
Copy link
Member

pfmoore commented Jan 2, 2021

I was asking to find a good mental model that would make me understand your position

I have no problem with clarifying my thinking if it helps, I just don't intend to try to persuade you if you believe differently 🙂

My model is simple. pip install takes a requirement (project name + specifier) and foo== isn't a valid requirement, because == isn't a valid specifier. In addition, pip install as a command is intended to install stuff, not as a way to trigger an error that provides informative information about a project.

If people want to find out what versions of foo are available, we should support that via a dedicated command (maybe pip list foo --versions, but we can bikeshed the name as much as anyone has energy for 🙂). The fact that pip install foo== has provided that information historically is an accident, and in fact is the accidental consequence of a bug (accepting foo== as a valid requirement). People could just as easily have used foo==999.76.34.post0 to get the information, which would have worked just as well, but might have made it a little clearer that it wasn't the "right" way to get that information.

Does that help you understand my logic?

@uranusjr
Copy link
Member

uranusjr commented Jan 2, 2021

I opened a thread in packaging to discuss the behaviour.

@MrMino
Copy link
Contributor Author

MrMino commented Jan 2, 2021

@pfmoore I understand the willingness to make it follow a spec. But I'd say that following the spec ≠ usability of a CLI. It's strange to me that you would prioritize former over the latter, but I guess it's a matter of opinion. Agree to disagree?

Anything else I should add to this PR?

@pradyunsg
Copy link
Member

pradyunsg commented Jan 2, 2021

I don't think there's more needed here.

And, also, I hate that we constantly hit Hyrum's Law. :)

@MrMino

This comment has been minimized.

@pradyunsg pradyunsg removed their request for review January 2, 2021 21:52
@pradyunsg pradyunsg dismissed their stale review January 2, 2021 21:52

Comments addressed.

@pradyunsg
Copy link
Member

pradyunsg commented Jan 2, 2021

Apologies, this is the first I'm hearing of Hyrum's Law being considered derogatory. If you would be willing to elaborate/share on why that is, I'd like to know more! :)

I thought it applied here because we made a change to an undocumented only-an-implementation-detail behaviour of pip, which broke users (which is what this PR is fixing).


On a completely different note, thanks a lot @MrMino for being so receptive on feedback and being, overall, a pleasure to collaborate with so far in this PR! Much appreciated! ^.^

@MrMino
Copy link
Contributor Author

MrMino commented Jan 2, 2021

@pradyunsg The way I see it, you wouldn't like to tell your son that he's a result of a Murphy's law, it wouldn't be a good PR to tell your contractor that his refactor shows signs of Tesler's law, it wouldn't look good if I told you that your website is a failure in application of Jakob's Law.
On their own and in general these are true observations, but applying most of these witty epigrams to the work of others is just a veiled way of saying "your work is gawky as hell" - that's how I and many others (speaking from experience) hear them.

IMO applications of Hyrum's law as a label should be limited to the places where there's a clear API contract. UX / GUIs / CLIs (for the most part) don't have that.


thanks a lot @MrMino for being so receptive on feedback and being, overall, a pleasure to collaborate with so far in this PR! Much appreciated! ^.^

I'm always surprised to hear this, as to myself I sound like a huge pain in the butt most of the time 😉. Thanks though, appreciated.

@MrMino
Copy link
Contributor Author

MrMino commented Jan 2, 2021

Commits squashed, news entry reworded (I'm bad at sticking to my word choices). Should there be anything else to change / add - I'm all ears.

Thanks for the reviews, it was a pleasure to work with you guys :).

@benjaoming
Copy link

Great work @MrMino !

We're hitting a pytest-xdist bug.

@pradyunsg could you clarify what this bug is about? Is it something that the PR Author should fix or a known bug that is unrelated to the changes?

@BrownTruck
Copy link
Contributor

Hello!

I am an automated bot and I have noticed that this pull request is not currently able to be merged. If you are able to either merge the master branch into this pull request or rebase this pull request against master then it will be eligible for code review and hopefully merging!

@BrownTruck BrownTruck added the needs rebase or merge PR has conflicts with current master label Feb 21, 2021
@pypa-bot pypa-bot removed the needs rebase or merge PR has conflicts with current master label Feb 21, 2021
@ddelange
Copy link
Contributor

It's worth noting that packaging will be dropping LegacyVersion sometime soon, at which point a specifier of == will no longer be valid. At that point pip install foo== will stop working as a way to list all available versions anyway (as will other variants using non-compliant versions, such as pip install foo=versions).

In this case, what will become the new approach to trigger this output?

@pfmoore
Copy link
Member

pfmoore commented Feb 22, 2021

In this case, what will become the new approach to trigger this output?

There isn't one yet, because no-one has proposed an approach or written a PR.

@uranusjr
Copy link
Member

If you just want a “reasonable hack”, something like foo==9999999999999999 would work most of the time.

@BrownTruck
Copy link
Contributor

Hello!

I am an automated bot and I have noticed that this pull request is not currently able to be merged. If you are able to either merge the master branch into this pull request or rebase this pull request against master then it will be eligible for code review and hopefully merging!

@BrownTruck BrownTruck added the needs rebase or merge PR has conflicts with current master label Feb 25, 2021
In the new resolver the "(from versions ...)" message, shown on
failure to resolve a package, has been removed. This commit brings it
back.
@pypa-bot pypa-bot removed the needs rebase or merge PR has conflicts with current master label Feb 27, 2021
@MrMino MrMino requested a review from uranusjr February 27, 2021 19:41
@MrMino
Copy link
Contributor Author

MrMino commented Feb 27, 2021

@uranusjr could you please look at it once more, just to make sure that after your changes in 917ecad everything is still in order?

@uranusjr
Copy link
Member

uranusjr commented Feb 27, 2021

One nitpick, the rebase looks good to me.

Co-authored-by: Tzu-ping Chung <uranusjr@gmail.com>
@MrMino
Copy link
Contributor Author

MrMino commented Feb 27, 2021

Good to know, thank you.

@pradyunsg pradyunsg merged commit 8223d29 into pypa:master Feb 28, 2021
@MrMino MrMino deleted the diagnostic_aversion branch March 2, 2021 21:05
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Oct 1, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[2020-resolver] No longer can get list of available versions.
9 participants