-
Notifications
You must be signed in to change notification settings - Fork 3k
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
Fix pip show displaying the incorrect result for "Required-by" #6957
Fix pip show displaying the incorrect result for "Required-by" #6957
Conversation
Add test to check if a capitalized name is being shown properly Add new stub package to support the test
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 for the PR! I think you did everything fine, it looks like all the checks are happy.
I have one minor comment that I have made on the code itself.
In addition, can we also add a test to check that a package (A, for example) that requires Requires_Capitalized
as requires_Capitalized
causes Required-by: A
to appear in the output of pip show
for Requires-Capitalized
?
Just a note: In general we prefer to use unit tests where possible since those are usually faster (and we're trying to speed up our tests). In this case it would require some refactoring in commands/show.py
so in my opinion these tests are OK and we can probably worry about it later.
in pip show Remove useless import in stubs for named tests
@@ -0,0 +1,6 @@ | |||
from setuptools import setup | |||
|
|||
setup(name='requires_Capitalized', |
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.
Sorry, in hindsight my previous suggestion was not very clear.
I think that this package should be named "A" (or anything else, it doesn't matter), and then it should have requires_Capitalized
in its install_requires
list. Then we should check that the Requires_Capitalized
package correctly puts "A" in its "Required-By" list. That would ensure that the names of things in install_requires
that we're comparing against are also normalized.
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 see.
As you can see by the following commits, I messed it up a bit.
Anyway, do you prefer having both the existing test and the new one? Just the new one?
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.
No worries! I would keep test_show_required_by_packages_capitalized
, remove test_show_required_by_with_mixed_capitalization
, and add the new one (maybe called test_show_required_by_packages_requiring_capitalized
).
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 tried to do that earlier, but it didn't install the package because of:
ERROR: No matching distribution found for requires_Capitalized==1.0 (from simple-1==1.0)
(obviously)
So I figured I should Create a new tar.gz called Requires_Capitalized for this test.
I wanted to make sure with you first that this is in fact what you meant before I do so.
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 it would be OK to explicitly install Requires_Capitalized
before installing A
, then we should not need another .tar.gz.
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.
Are you sure that installing it explicitly would work?
I've done the following:
(Don't mind the name, WIP and stuff)
- Added a file
setup(name='Req_Cap_Todo',
version='1.0',
)
- Installing this file:
editable_path = os.path.join(data.src, 'Req_Cap_Todo')
script.pip(
'install', '--no-index', '-f', data.find_links, editable_path
)
- Installed the package
setup(name='simpleone',
version='1.0',
install_requires=['Req_Cap_Todo==1.0']
)
And I get the result of
['Name: Req-Cap-Todo', 'Version: 1.0', ... , 'Requires: ', 'Required-by: ']
To make sure, I tried to installed Click first and black afterwards, but it did show the correct message (with my fix, of course)
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.
Installing explicitly was meant to avoid making another .tar.gz, and that looks like it worked. 👍 The other item is a bug.
@@ -0,0 +1,6 @@ | |||
from setuptools import setup | |||
|
|||
setup(name='requires_Capitalized', |
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.
Installing explicitly was meant to avoid making another .tar.gz, and that looks like it worked. 👍 The other item is a bug.
src/pip/_internal/commands/show.py
Outdated
required_by = [ | ||
pkg.project_name for pkg in pkg_resources.working_set | ||
if name in [required.name for required in pkg.requires()] | ||
if canonical_name in [required.name for required in pkg.requires()] |
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 we should probably be doing canonicalize_name(required.name)
here, that may fix the issue you mentioned with the "Required-by" of "Req-Cap-Todo" missing "simpleone" in our new test.
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.
You are indeed correct, I really need to setup up my pycharm debugger with tox.
Everything passes now.
I also think we should extract this list comprehension to a method, under the rule of "a function should do one thing and one thing only".
I would've done so in a personal project (without thinking too much about it) but since I'm new here I'm checking with you.
Or better yet, should I put it in search_packages_info
? (this methodneeds a refactor imo but that's a different story)
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 agree this could be improved, and moving it into search_packages_info
seems like it would work and make more sense.
If you make the change in a separate commit then it should be OK here. It may take a little longer for someone else to review and merge, or maybe not - everyone is a volunteer so it can vary wildly. A few things that could help:
- If you squash/rewrite your commits into meaningful "chunks" of changes that have clear diffs (maybe one commit for the primary change here and then one for moving the
requires_by
calculation intosearch_packages_info
) that would make it easier to evaluate this PR - Give each of those commits a clear message (reduces noise compared to having a handful of commits)
These aren't required by any means, but can reduce the work required to review and can be useful to know how to do.
Just FYI, not applicable here - in general if the primary change being made is larger or more complex I would probably do refactoring in separate PRs before the "main" one if I think they are required to make the "main" changes clear. If the refactoring is more like a nice-to-have but doesn't really improve understanding the "main" change then I would probably do it in a followup PR after the "main" one. You don't have to figure this out ahead of time on your own - if some refactoring is needed then it's OK to put the "main" PR on hold, do refactoring in a separate PR, and then rebase and continue with the "main" one when the refactoring is merged. Similarly it's OK to say in a PR comment or issue that some refactoring followup is needed.
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.
Thank you very much for all the feedback, I appreciate it greatly.
I've been working in a python team for about 3 years but open source feedback adds much more.
Just one more question before I push:
I have an option to add a private:
def _get_requiring_packages(package_name):
return [
pkg.project_name for pkg in pkg_resources.working_set
if canonicalize_name(package_name) in
[canonicalize_name(required.name) for required in pkg.requires()]
]
or to do it directly in search_packages_info
:
package = {
'name': dist.project_name,
'version': dist.version,
'location': dist.location,
'requires': [dep.project_name for dep in dist.requires()],
'required_by': [
pkg.project_name for pkg in pkg_resources.working_set
if canonicalize_name(dist.project_name) in
[canonicalize_name(required.name) for required in pkg.requires()]
]
}
I feel like the first option is better (and passes the 79 char per line limit!) but again, wanted to make sure before I push.
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.
1 seems better to me, but I would make it a free function in search_packages_info
and drop the leading underscore (because its scope will already prevent it from being used outside, marking it private would be redundant IMO).
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! Just a few minor comments.
src/pip/_internal/commands/show.py
Outdated
def get_requiring_packages(package_name): | ||
return [ | ||
pkg.project_name for pkg in pkg_resources.working_set | ||
if canonicalize_name(package_name) in |
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 would assign canonicalize_name(package_name)
outside the list comprehension and then use the variable inside, which looks a little simpler (also avoids recomputing every time).
@@ -0,0 +1 @@ | |||
# |
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 should be able to get rid of this file.
@@ -0,0 +1 @@ | |||
# |
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 one too.
@@ -0,0 +1 @@ | |||
# |
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 this one.
|
||
setup(name='simple', | ||
version='1.0', | ||
install_requires=['required_by_Capitalized==1.0'] |
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 would call this package requires_requires_capitalized
(impacting the name
argument here and the directory name) and have it contain 'requires_Capitalized'
in its install_requires
, then we can remove required_by_Capitalized
. There will be a few corresponding changes in test_show_required_by_packages_requiring_capitalized
.
Rename stub package required_by_mixed_cap to requires_requires_cap Move the canonicalize_name calculation outside of a loop
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.
LGTM. Thanks!
@pradyunsg Indeed I do. |
Fixes #6947
Hello, this is my first PR here so I hope I did everything properly.
I chose to have a separate test and stub because:
I hope this is good as is, but if not, please say so and I'll change it to your liking.