don't --user install in --system-site-packages virtualenvs with conflict

This commit is contained in:
Marcus Smith 2012-06-23 08:30:59 -07:00
parent 4c96de642d
commit 0708447bba
3 changed files with 48 additions and 13 deletions

View File

@ -16,7 +16,7 @@ from pip.log import logger
from pip.util import display_path, rmtree from pip.util import display_path, rmtree
from pip.util import ask, ask_path_exists, backup_dir from pip.util import ask, ask_path_exists, backup_dir
from pip.util import is_installable_dir, is_local, dist_is_local, dist_in_usersite from pip.util import is_installable_dir, is_local, dist_is_local, dist_in_usersite
from pip.util import renames, normalize_path, egg_link_path from pip.util import renames, normalize_path, egg_link_path, dist_in_site_packages
from pip.util import make_path_relative from pip.util import make_path_relative
from pip.util import call_subprocess from pip.util import call_subprocess
from pip.backwardcompat import (urlparse, urllib, from pip.backwardcompat import (urlparse, urllib,
@ -685,6 +685,9 @@ exec(compile(open(__file__).read().replace('\\r\\n', '\\n'), __file__, 'exec'))
if self.use_user_site: if self.use_user_site:
if dist_in_usersite(existing_dist): if dist_in_usersite(existing_dist):
self.conflicts_with = existing_dist self.conflicts_with = existing_dist
elif running_under_virtualenv() and dist_in_site_packages(existing_dist):
raise InstallationError("Will not install to the user site because it will lack sys.path precedence to %s in %s"
%(existing_dist.project_name, existing_dist.location))
else: else:
self.conflicts_with = existing_dist self.conflicts_with = existing_dist
return True return True

View File

@ -303,6 +303,12 @@ def dist_in_usersite(dist):
else: else:
return False return False
def dist_in_site_packages(dist):
"""
Return True if given Distribution is installed in distutils.sysconfig.get_python_lib().
"""
return normalize_path(dist_location(dist)).startswith(normalize_path(site_packages))
def get_installed_distributions(local_only=True, skip=('setuptools', 'pip', 'python')): def get_installed_distributions(local_only=True, skip=('setuptools', 'pip', 'python')):
""" """

View File

@ -9,6 +9,14 @@ from tests.local_repos import local_checkout
from tests.test_pip import here, reset_env, run_pip, pyversion from tests.test_pip import here, reset_env, run_pip, pyversion
patch_dist_in_site_packages = """
def dist_in_site_packages(dist):
return False
import pip
pip.util.dist_in_site_packages=dist_in_site_packages
"""
def test_install_curdir_usersite_fails_in_old_python(): def test_install_curdir_usersite_fails_in_old_python():
""" """
Test --user option on older Python versions (pre 2.6) fails intelligibly Test --user option on older Python versions (pre 2.6) fails intelligibly
@ -111,15 +119,21 @@ class Tests_UserSite:
assert not isfile(initools_v3_file), initools_v3_file assert not isfile(initools_v3_file), initools_v3_file
def test_install_user_conflict_in_site(self): def test_install_user_conflict_in_globalsite(self):
""" """
Test user install with conflict in site ignores site and installs to usersite Test user install with conflict in global site ignores site and installs to usersite
""" """
#the test framework only supports testing using virtualenvs # the test framework only supports testing using virtualenvs
#this test will use a --system_site_packages virtualenv to achieve the conflict scenario. # the sys.path ordering for virtualenvs with --system-site-packages is this: virtualenv-site, user-site, global-site
# this test will use 2 modifications to simulate the user-site/global-site relationship
# 1) a monkey patch which will make it appear INITools==0.2 is not in in the virtualenv site
# if we don't patch this, pip will return an installation error: "Will not install to the usersite because it will lack sys.path precedence..."
# 2) adding usersite to PYTHONPATH, so usersite as sys.path precedence over the virtualenv site
env = reset_env(system_site_packages=True, sitecustomize=patch_dist_in_site_packages)
env.environ["PYTHONPATH"] = env.root_path / env.user_site
env = reset_env(system_site_packages=True)
result1 = run_pip('install', 'INITools==0.2') result1 = run_pip('install', 'INITools==0.2')
result2 = run_pip('install', '--user', 'INITools==0.1') result2 = run_pip('install', '--user', 'INITools==0.1')
@ -141,14 +155,14 @@ class Tests_UserSite:
Test user install with conflict in globalsite and usersite ignores global site and updates usersite. Test user install with conflict in globalsite and usersite ignores global site and updates usersite.
""" """
#the test framework only supports testing using virtualenvs # the test framework only supports testing using virtualenvs.
#this test will use a --system_site_packages virtualenv to achieve the conflict scenario. # the sys.path ordering for virtualenvs with --system-site-packages is this: virtualenv-site, user-site, global-site.
# this test will use 2 modifications to simulate the user-site/global-site relationship
# 1) a monkey patch which will make it appear INITools==0.2 is not in in the virtualenv site
# if we don't patch this, pip will return an installation error: "Will not install to the usersite because it will lack sys.path precedence..."
# 2) adding usersite to PYTHONPATH, so usersite as sys.path precedence over the virtualenv site
env = reset_env(system_site_packages=True) env = reset_env(system_site_packages=True, sitecustomize=patch_dist_in_site_packages)
# the sys.path ordering for virtualenvs with --system-site-packages is this: virtualenv site, usersite, global site
# given this ordering you *can't* use it to simulate the scenario for this test.
# this test will add the usersite to PYTHONPATH to simulate the desired ordering
env.environ["PYTHONPATH"] = env.root_path / env.user_site env.environ["PYTHONPATH"] = env.root_path / env.user_site
result1 = run_pip('install', 'INITools==0.2') result1 = run_pip('install', 'INITools==0.2')
@ -166,3 +180,15 @@ class Tests_UserSite:
initools_folder = env.root_path / env.site_packages / 'initools' initools_folder = env.root_path / env.site_packages / 'initools'
assert isdir(egg_info_folder) assert isdir(egg_info_folder)
assert isdir(initools_folder) assert isdir(initools_folder)
def test_install_user_in_global_virtualenv_with_conflict_fails(self):
"""
Test user install in --system-site-packages virtualenv with conflict in site fails.
"""
env = reset_env(system_site_packages=True)
result1 = run_pip('install', 'INITools==0.2')
result2 = run_pip('install', '--user', 'INITools==0.1', expect_error=True)
assert result2.stdout.startswith("Will not install to the user site because it will lack sys.path precedence to %s in %s"
%('INITools',env.root_path / env.site_packages)), result2.stdout