diff --git a/CHANGES.txt b/CHANGES.txt index f2d528b23..b2d92e57f 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -6,6 +6,9 @@ * Fix an issue where pip did not properly unquote quoted URLs which contain characters like PEP 440's epoch separator (``!``). +* Fix an issue where distutils installed projects were not actually uninstalled + and deprecate attempting to uninstall them altogether. + **6.0.7 (2015-01-28)** diff --git a/pip/req/req_install.py b/pip/req/req_install.py index 24649e964..c4e74548f 100644 --- a/pip/req/req_install.py +++ b/pip/req/req_install.py @@ -6,6 +6,7 @@ import re import shutil import sys import tempfile +import warnings import zipfile from distutils.util import change_root @@ -32,6 +33,7 @@ from pip.utils import ( dist_in_usersite, dist_in_site_packages, egg_link_path, make_path_relative, call_subprocess, read_text_file, FakeFile, _make_build_dir, ) +from pip.utils.deprecation import RemovedInPip8Warning from pip.utils.logging import indent_log from pip.req.req_uninstall import UninstallPathSet from pip.vcs import vcs @@ -559,6 +561,8 @@ exec(compile( paths_to_remove = UninstallPathSet(dist) develop_egg_link = egg_link_path(dist) egg_info_exists = dist.egg_info and os.path.exists(dist.egg_info) + # Special case for distutils installed package + distutils_egg_info = getattr(dist._provider, 'path', None) if develop_egg_link: # develop egg with open(develop_egg_link, 'r') as fh: @@ -597,6 +601,16 @@ exec(compile( paths_to_remove.add(path + '.py') paths_to_remove.add(path + '.pyc') + elif distutils_egg_info: + 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), + RemovedInPip8Warning, + ) + paths_to_remove.add(distutils_egg_info) + elif dist.location.endswith('.egg'): # package installed by easy_install # We cannot match on dist.egg_name because it can slightly vary diff --git a/tests/functional/test_uninstall.py b/tests/functional/test_uninstall.py index 3fe70cc2c..eace07e7b 100644 --- a/tests/functional/test_uninstall.py +++ b/tests/functional/test_uninstall.py @@ -28,6 +28,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') + result2 = script.pip('list') + assert "distutils-install (0.1)" not in result2.stdout + + def test_uninstall_with_scripts(script): """ Uninstall an easy_installed package with scripts.