Default to --user install in certain conditions

This commit is contained in:
Thomas Kluyver 2019-09-09 15:22:08 +01:00
parent 90aeec97f1
commit 042d4844e8
2 changed files with 58 additions and 2 deletions

View File

@ -13,6 +13,7 @@ import logging
import operator
import os
import shutil
import site
from optparse import SUPPRESS_HELP
from pip._vendor import pkg_resources
@ -28,11 +29,11 @@ from pip._internal.exceptions import (
InstallationError,
PreviousBuildDirError,
)
from pip._internal.locations import distutils_scheme
from pip._internal.locations import distutils_scheme, site_packages
from pip._internal.operations.check import check_install_conflicts
from pip._internal.req import RequirementSet, install_given_reqs
from pip._internal.req.req_tracker import RequirementTracker
from pip._internal.utils.filesystem import check_path_owner
from pip._internal.utils.filesystem import check_path_owner, test_writable_dir
from pip._internal.utils.misc import (
ensure_dir,
get_installed_version,
@ -305,6 +306,17 @@ class InstallCommand(RequirementCommand):
install_options.append('--user')
install_options.append('--prefix=')
elif options.use_user_site is None:
if options.prefix_path or options.target_dir:
options.use_user_site = False
elif site_packages_writable(
root=options.root_path,
isolated=options.isolated_mode
):
options.use_user_site = False
elif site.ENABLE_USER_SITE:
options.use_user_site = True
target_temp_dir = None # type: Optional[TempDirectory]
target_temp_dir_path = None # type: Optional[str]
if options.target_dir:
@ -594,6 +606,10 @@ def get_lib_location_guesses(*args, **kwargs):
return [scheme['purelib'], scheme['platlib']]
def site_packages_writable(**kwargs):
return all(test_writable_dir(d) for d in get_lib_location_guesses(**kwargs))
def create_env_error_message(error, show_traceback, using_user_site):
"""Format an error message for an EnvironmentError

View File

@ -1,5 +1,6 @@
import os
import os.path
import random
import shutil
import stat
from contextlib import contextmanager
@ -113,3 +114,42 @@ if PY2:
else:
replace = _replace_retry(os.replace)
# test_writable_dir and _test_writable_dir_win are copied from Flit,
# with the author's agreement to also place them under pip's license.
def test_writable_dir(path):
"""Check if a directory is writable.
Uses os.access() on POSIX, tries creating files on Windows.
"""
if os.name == 'posix':
return os.access(path, os.W_OK)
return _test_writable_dir_win(path)
def _test_writable_dir_win(path):
# os.access doesn't work on Windows: http://bugs.python.org/issue2528
# and we can't use tempfile: http://bugs.python.org/issue22107
basename = 'accesstest_deleteme_fishfingers_custard_'
alphabet = 'abcdefghijklmnopqrstuvwxyz0123456789'
for i in range(10):
name = basename + ''.join(random.choice(alphabet) for _ in range(6))
file = os.path.join(path, name)
try:
with open(file, mode='xb'):
pass
except FileExistsError:
continue
except PermissionError:
# This could be because there's a directory with the same name.
# But it's highly unlikely there's a directory called that,
# so we'll assume it's because the parent directory is not writable.
return False
else:
os.unlink(file)
return True
# This should never be reached
raise EnvironmentError('Unexpected condition testing for writable directory')