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