-
Notifications
You must be signed in to change notification settings - Fork 3.2k
Improve the presentation style of the pip upgrade prompt #10959
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
Changes from all commits
c4470ba
ea0d976
4f35572
4a3c4c9
59db67c
e247195
ca84a83
ee72f55
26d8441
4e53eaf
85ccf51
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,7 +1,23 @@ | ||
| import itertools | ||
| import os | ||
| import shutil | ||
| import sys | ||
| from typing import List, Optional | ||
|
|
||
| from pip._internal.cli.main import main | ||
| from pip._internal.utils.compat import WINDOWS | ||
|
|
||
| _EXECUTABLE_NAMES = [ | ||
| "pip", | ||
| f"pip{sys.version_info.major}", | ||
| f"pip{sys.version_info.major}.{sys.version_info.minor}", | ||
| ] | ||
| if WINDOWS: | ||
| _allowed_extensions = {"", ".exe"} | ||
| _EXECUTABLE_NAMES = [ | ||
| "".join(parts) | ||
| for parts in itertools.product(_EXECUTABLE_NAMES, _allowed_extensions) | ||
| ] | ||
|
|
||
|
|
||
| def _wrapper(args: Optional[List[str]] = None) -> int: | ||
|
|
@@ -25,3 +41,39 @@ def _wrapper(args: Optional[List[str]] = None) -> int: | |
| "running pip directly.\n" | ||
| ) | ||
| return main(args) | ||
|
|
||
|
|
||
| def get_best_invocation_for_this_pip() -> str: | ||
| """Try to figure out the best way to invoke pip in the current environment.""" | ||
| binary_directory = "Scripts" if WINDOWS else "bin" | ||
| binary_prefix = os.path.join(sys.prefix, binary_directory) | ||
|
|
||
| # Try to use pip[X[.Y]] names, if those executables for this environment are | ||
| # the first on PATH with that name. | ||
pradyunsg marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| path_parts = os.path.normcase(os.environ.get("PATH", "")).split(os.pathsep) | ||
| exe_are_in_PATH = os.path.normcase(binary_prefix) in path_parts | ||
| if exe_are_in_PATH: | ||
| for exe_name in _EXECUTABLE_NAMES: | ||
| found_executable = shutil.which(exe_name) | ||
| if found_executable and os.path.samefile( | ||
| found_executable, | ||
| os.path.join(binary_prefix, exe_name), | ||
| ): | ||
| return exe_name | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I assume here that we don't care about cases where the user might, for example, have a shell alias of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Pretty much. There's no way to detect or account for these things. |
||
|
|
||
| # Use the `-m` invocation, if there's no "nice" invocation. | ||
| return f"{get_best_invocation_for_this_python()} -m pip" | ||
|
|
||
|
|
||
| def get_best_invocation_for_this_python() -> str: | ||
| """Try to figure out the best way to invoke the current Python.""" | ||
| exe = sys.executable | ||
| exe_name = os.path.basename(exe) | ||
|
|
||
| # Try to use the basename, if it's the first executable. | ||
| found_executable = shutil.which(exe_name) | ||
| if found_executable and os.path.samefile(found_executable, exe): | ||
| return exe_name | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This approach seems much more robust than the pip one, but still could be messed up by the shell alias problem. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yea, there's nothing we can do for shell aliases anyway. If things break, I think it's fair to say "you have an alias" as a cause for the issue. |
||
|
|
||
| # Use the full executable name, because we couldn't find something simpler. | ||
| return exe | ||
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 can't remember for certain - do we not support environments on Windows that use "bin" rather than "Scripts" (for example, MSYS2)? I note that
pip._internal.locations.get_bin_prefix()allows both on Windows...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 don't think we explicitly support them. None the less, if this fails, the thing that'd happen is a less-perfect prompt will be presented. :)
I've copied this over inspired by what
venvdoes on 3.7 -- https://github.com/python/cpython/blob/3.7/Lib/venv/__init__.py#L114