Restore ability to uninstall distutils packages

This is a partial revert of 6afc718307
to restore the ability to overwrite distutils installed packages.

It is not elegant, but some projects (such as OpenStack's devstack)
rely on overwriting packages installed via the system package manager.
These packages can't be removed because they are dependencies for
parts of the base system, but many of the things devstack needs to run
requires later dependencies.  For historical reasons it's not easy to
fix this into a virtualenv, etc, all at once.

If distributions move to setuptools based packages, this problem might
fix itself.
This commit is contained in:
Ian Wienand 2016-01-20 16:50:18 +11:00
parent 495c773662
commit 35a3e8b7f5
2 changed files with 32 additions and 5 deletions

View File

@ -7,6 +7,7 @@ import shutil
import sys import sys
import tempfile import tempfile
import traceback import traceback
import warnings
import zipfile import zipfile
from distutils.util import change_root from distutils.util import change_root
@ -34,7 +35,9 @@ from pip.utils import (
call_subprocess, read_text_file, FakeFile, _make_build_dir, ensure_dir, call_subprocess, read_text_file, FakeFile, _make_build_dir, ensure_dir,
get_installed_version, canonicalize_name get_installed_version, canonicalize_name
) )
from pip.utils.hashes import Hashes from pip.utils.hashes import Hashes
from pip.utils.deprecation import RemovedInPip10Warning
from pip.utils.logging import indent_log from pip.utils.logging import indent_log
from pip.utils.setuptools_build import SETUPTOOLS_SHIM from pip.utils.setuptools_build import SETUPTOOLS_SHIM
from pip.utils.ui import open_spinner from pip.utils.ui import open_spinner
@ -647,12 +650,14 @@ class InstallRequirement(object):
paths_to_remove.add(path + '.pyo') paths_to_remove.add(path + '.pyo')
elif distutils_egg_info: elif distutils_egg_info:
raise UninstallationError( warnings.warn(
"Detected a distutils installed project ({0!r}) which we " "Uninstalling a distutils installed project ({0}) has been "
"cannot uninstall. The metadata provided by distutils does " "deprecated and will be removed in a future version. This is "
"not contain a list of files which have been installed, so " "due to the fact that uninstalling a distutils project will "
"pip does not know which files to uninstall.".format(self.name) "only partially uninstall the project.".format(self.name),
RemovedInPip10Warning,
) )
paths_to_remove.add(distutils_egg_info)
elif dist.location.endswith('.egg'): elif dist.location.endswith('.egg'):
# package installed by easy_install # package installed by easy_install

View File

@ -30,6 +30,28 @@ def test_simple_uninstall(script):
assert_all_changes(result, result2, [script.venv / 'build', 'cache']) assert_all_changes(result, result2, [script.venv / 'build', 'cache'])
def test_simple_uninstall_distutils(script):
"""
Test simple install and uninstall.
"""
script.scratch_path.join("distutils_install").mkdir()
pkg_path = script.scratch_path / 'distutils_install'
pkg_path.join("setup.py").write(textwrap.dedent("""
from distutils.core import setup
setup(
name='distutils-install',
version='0.1',
)
"""))
result = script.run('python', pkg_path / 'setup.py', 'install')
result = script.pip('list')
assert "distutils-install (0.1)" in result.stdout
script.pip('uninstall', 'distutils_install', '-y', expect_stderr=True)
result2 = script.pip('list')
assert "distutils-install (0.1)" not in result2.stdout
@pytest.mark.network @pytest.mark.network
def test_uninstall_with_scripts(script): def test_uninstall_with_scripts(script):
""" """