Repository: pypa/pip

Issue:
upgrade of things distutils-installed in system-site-packages fails in pip 8
From #3384 - a virtualenv with system-site-packages enabled will error when installing a newer requests, if requests is present on the system with only distutils metadata.



Discussion:

Resolving patch:
diff --git a/pip/req/req_install.py b/pip/req/req_install.py
--- a/pip/req/req_install.py
+++ b/pip/req/req_install.py
@@ -752,7 +752,7 @@ def rollback_uninstall(self):
             self.uninstalled.rollback()
         else:
             logger.error(
-                "Can't rollback %s, nothing uninstalled.", self.project_name,
+                "Can't rollback %s, nothing uninstalled.", self.name,
             )
 
     def commit_uninstall(self):
diff --git a/pip/req/req_uninstall.py b/pip/req/req_uninstall.py
--- a/pip/req/req_uninstall.py
+++ b/pip/req/req_uninstall.py
@@ -2,13 +2,11 @@
 
 import logging
 import os
-import sys
 import tempfile
 
 from pip.compat import uses_pycache, WINDOWS, cache_from_source
 from pip.exceptions import UninstallationError
-from pip.utils import (rmtree, ask, is_local, dist_is_local, renames,
-                       normalize_path)
+from pip.utils import rmtree, ask, is_local, renames, normalize_path
 from pip.utils.logging import indent_log
 
 
@@ -34,17 +32,6 @@ def _permitted(self, path):
         """
         return is_local(path)
 
-    def _can_uninstall(self):
-        if not dist_is_local(self.dist):
-            logger.info(
-                "Not uninstalling %s at %s, outside environment %s",
-                self.dist.project_name,
-                normalize_path(self.dist.location),
-                sys.prefix,
-            )
-            return False
-        return True
-
     def add(self, path):
         head, tail = os.path.split(path)
 
@@ -94,8 +81,6 @@ def _stash(self, path):
     def remove(self, auto_confirm=False):
         """Remove paths in ``self.paths`` with confirmation (unless
         ``auto_confirm`` is True)."""
-        if not self._can_uninstall():
-            return
         if not self.paths:
             logger.info(
                 "Can't uninstall '%s'. No files were found to uninstall.",


Test patch:
diff --git a/tests/functional/test_uninstall.py b/tests/functional/test_uninstall.py
--- a/tests/functional/test_uninstall.py
+++ b/tests/functional/test_uninstall.py
@@ -4,12 +4,14 @@
 import os
 import sys
 import pytest
+import pretend
+
 from os.path import join, normpath
 from tempfile import mkdtemp
-from mock import patch
 from tests.lib import assert_all_changes, pyversion
 from tests.lib.local_repos import local_repo, local_checkout
 
+from pip.req import InstallRequirement
 from pip.utils import rmtree
 
 
@@ -317,11 +319,8 @@ def test_uninstallpathset_no_paths(caplog):
     from pip.req.req_uninstall import UninstallPathSet
     from pkg_resources import get_distribution
     test_dist = get_distribution('pip')
-    # ensure that the distribution is "local"
-    with patch("pip.req.req_uninstall.dist_is_local") as mock_dist_is_local:
-        mock_dist_is_local.return_value = True
-        uninstall_set = UninstallPathSet(test_dist)
-        uninstall_set.remove()  # with no files added to set
+    uninstall_set = UninstallPathSet(test_dist)
+    uninstall_set.remove()  # with no files added to set
 
     assert (
         "Can't uninstall 'pip'. No files were found to uninstall."
@@ -329,31 +328,25 @@ def test_uninstallpathset_no_paths(caplog):
     )
 
 
-def test_uninstallpathset_non_local(caplog):
-    """
-    Test UninstallPathSet logs notification and returns (with no exception)
-    when dist is non-local
-    """
-    nonlocal_path = os.path.abspath("/nonlocal")
-    from pip.req.req_uninstall import UninstallPathSet
-    from pkg_resources import get_distribution
-    test_dist = get_distribution('pip')
-    test_dist.location = nonlocal_path
-    # ensure that the distribution is "non-local"
-    # setting location isn't enough, due to egg-link file checking for
-    # develop-installs
-    with patch("pip.req.req_uninstall.dist_is_local") as mock_dist_is_local:
-        mock_dist_is_local.return_value = False
-        uninstall_set = UninstallPathSet(test_dist)
-        # with no files added to set; which is the case when trying to remove
-        # non-local dists
-        uninstall_set.remove()
+def test_uninstall_non_local_distutils(caplog, monkeypatch, tmpdir):
+    einfo = tmpdir.join("thing-1.0.egg-info")
+    with open(einfo, "wb"):
+        pass
 
-    assert (
-        "Not uninstalling pip at %s, outside environment %s"
-        % (nonlocal_path, sys.prefix)
-        in caplog.text()
+    dist = pretend.stub(
+        key="thing",
+        project_name="thing",
+        egg_info=einfo,
+        location=einfo,
+        _provider=pretend.stub(),
     )
+    get_dist = pretend.call_recorder(lambda x: dist)
+    monkeypatch.setattr("pip._vendor.pkg_resources.get_distribution", get_dist)
+
+    req = InstallRequirement.from_line("thing")
+    req.uninstall()
+
+    assert os.path.exists(einfo)
 
 
 def test_uninstall_wheel(script, data):