Skip to content

Move Windows protection check to specific commands #5312

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

Merged
merged 4 commits into from
May 30, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions news/5311.bugfix
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fix "pip wheel pip" being blocked by the "don't use pip to modify itself" check
1 change: 1 addition & 0 deletions news/5312.bugfix
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fix "pip wheel pip" being blocked by the "don't use pip to modify itself" check
18 changes: 0 additions & 18 deletions src/pip/_internal/basecommand.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
from pip._internal.baseparser import (
ConfigOptionParser, UpdatingDefaultsHelpFormatter,
)
from pip._internal.compat import WINDOWS
from pip._internal.download import PipSession
from pip._internal.exceptions import (
BadCommand, CommandError, InstallationError, PreviousBuildDirError,
Expand Down Expand Up @@ -321,23 +320,6 @@ def populate_requirement_set(requirement_set, args, options, finder,
'You must give at least one requirement to %(name)s '
'(see "pip help %(name)s")' % opts)

# On Windows, any operation modifying pip should be run as:
# python -m pip ...
# See https://github.com/pypa/pip/issues/1299 for more discussion
should_show_use_python_msg = (
WINDOWS and
requirement_set.has_requirement("pip") and
os.path.basename(sys.argv[0]).startswith("pip")
)
if should_show_use_python_msg:
new_command = [
sys.executable, "-m", "pip"
] + sys.argv[1:]
raise CommandError(
'To modify pip, please run the following command:\n{}'
.format(" ".join(new_command))
)

def _build_package_finder(self, options, session,
platform=None, python_versions=None,
abi=None, implementation=None):
Expand Down
9 changes: 8 additions & 1 deletion src/pip/_internal/commands/install.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,10 @@
from pip._internal.resolve import Resolver
from pip._internal.status_codes import ERROR
from pip._internal.utils.filesystem import check_path_owner
from pip._internal.utils.misc import ensure_dir, get_installed_version
from pip._internal.utils.misc import (
ensure_dir, get_installed_version,
protect_pip_from_modification_on_windows,
)
from pip._internal.utils.temp_dir import TempDirectory
from pip._internal.wheel import WheelBuilder

Expand Down Expand Up @@ -291,6 +294,10 @@ def run(self, options, args):
)
resolver.resolve(requirement_set)

protect_pip_from_modification_on_windows(
modifying_pip=requirement_set.has_requirement("pip")
)

# If caching is disabled or wheel is not installed don't
# try to build wheels.
if wheel and options.cache_dir:
Expand Down
6 changes: 6 additions & 0 deletions src/pip/_internal/commands/uninstall.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from pip._internal.basecommand import Command
from pip._internal.exceptions import InstallationError
from pip._internal.req import InstallRequirement, parse_requirements
from pip._internal.utils.misc import protect_pip_from_modification_on_windows


class UninstallCommand(Command):
Expand Down Expand Up @@ -63,6 +64,11 @@ def run(self, options, args):
'You must give at least one requirement to %(name)s (see '
'"pip help %(name)s")' % dict(name=self.name)
)

protect_pip_from_modification_on_windows(
modifying_pip="pip" in reqs_to_uninstall
)

for req in reqs_to_uninstall.values():
uninstall_pathset = req.uninstall(
auto_confirm=options.yes, verbose=self.verbosity > 0,
Expand Down
35 changes: 33 additions & 2 deletions src/pip/_internal/utils/misc.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,10 @@
from pip._vendor.six.moves import input
from pip._vendor.six.moves.urllib import parse as urllib_parse

from pip._internal.compat import console_to_str, expanduser, stdlib_pkgs
from pip._internal.exceptions import InstallationError
from pip._internal.compat import (
WINDOWS, console_to_str, expanduser, stdlib_pkgs,
)
from pip._internal.exceptions import CommandError, InstallationError
from pip._internal.locations import (
running_under_virtualenv, site_packages, user_site, virtualenv_no_global,
write_delete_marker_file,
Expand Down Expand Up @@ -868,3 +870,32 @@ def remove_auth_from_url(url):
)
surl = urllib_parse.urlunsplit(url_pieces)
return surl


def protect_pip_from_modification_on_windows(modifying_pip):
"""Protection of pip.exe from modification on Windows

On Windows, any operation modifying pip should be run as:
python -m pip ...
"""
pip_names = [
"pip.exe",
"pip{}.exe".format(sys.version_info[0]),
"pip{}.{}.exe".format(*sys.version_info[:2])
]

# See https://github.com/pypa/pip/issues/1299 for more discussion
should_show_use_python_msg = (
modifying_pip and
WINDOWS and
os.path.basename(sys.argv[0]) in pip_names
)

if should_show_use_python_msg:
new_command = [
sys.executable, "-m", "pip"
] + sys.argv[1:]
raise CommandError(
'To modify pip, please run the following command:\n{}'
.format(" ".join(new_command))
)
5 changes: 2 additions & 3 deletions tests/functional/test_install.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,8 @@ def test_pep518_uses_build_env(script, data, common_wheels, command, variant):
def test_pep518_with_user_pip(script, virtualenv, pip_src,
data, common_wheels):
virtualenv.system_site_packages = True
script.pip_install_local("--ignore-installed",
"-f", common_wheels,
"--user", pip_src)
script.pip("install", "--ignore-installed", "--user", pip_src,
use_module=True)
system_pip_dir = script.site_packages_path / 'pip'
system_pip_dir.rmtree()
system_pip_dir.mkdir()
Expand Down