Skip to content

Commit 0f50737

Browse files
committed
Add unit tests for user install decision
Functional tests for conflict install locations are removed in favor of the unittest which handle more cases.
1 parent b5f4a91 commit 0f50737

File tree

3 files changed

+98
-76
lines changed

3 files changed

+98
-76
lines changed

src/pip/_internal/commands/install.py

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -536,7 +536,7 @@ def site_packages_writable(**kwargs):
536536

537537

538538
def decide_user_install(
539-
use_user_site, # type: Optional[bool]
539+
use_user_site=None, # type: Optional[bool]
540540
prefix_path=None, # type: Optional[str]
541541
target_dir=None, # type: Optional[str]
542542
root_path=None, # type: Optional[str]
@@ -577,12 +577,19 @@ def decide_user_install(
577577
return False
578578

579579
if use_user_site is not None:
580+
use_user_site = bool(use_user_site)
580581
logger.debug("{} install by explicit request".format(
581582
"User" if use_user_site else "Non-user"))
582-
use_user_site = bool(use_user_site)
583-
elif site.ENABLE_USER_SITE is False: # This never seems to be reached.
584-
logger.debug("Non-user install due to disabled user site-packages by "
585-
"user request (with 'python -s' or PYTHONNOUSERSITE)")
583+
if use_user_site is True and site.ENABLE_USER_SITE is None:
584+
raise InstallationError("User site-packages are disabled for "
585+
"security reasons or by an administrator.")
586+
elif site.ENABLE_USER_SITE is None:
587+
logger.debug("Non-user install since user site-packages are disabled "
588+
"for security reasons or by an administrator.")
589+
use_user_site = False
590+
elif site.ENABLE_USER_SITE is False:
591+
logger.debug("Non-user install since user site-packages are disabled "
592+
"by user request (with 'python -s' or PYTHONNOUSERSITE)")
586593
use_user_site = False
587594
elif root_path:
588595
logger.debug(
@@ -596,14 +603,13 @@ def decide_user_install(
596603
"normal site-packages is not writeable")
597604
use_user_site = True
598605

599-
if use_user_site:
600-
if site.ENABLE_USER_SITE is None:
601-
raise InstallationError("User site-packages are disabled for "
602-
"security reasons or by an administrator.")
606+
if use_user_site is True:
603607
if virtualenv_no_global():
604-
raise InstallationError("User site-packages are not visible "
605-
"in this virtualenv.")
608+
raise InstallationError(
609+
"Can not perform a '--user' install. "
610+
"User site-packages are not visible in this virtualenv.")
606611
else:
612+
assert use_user_site is False
607613
if not site_packages_writable(root=root_path, isolated=isolated_mode):
608614
raise InstallationError("Cannot write to global site-packages.")
609615
return use_user_site

tests/functional/test_install.py

Lines changed: 0 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -847,27 +847,6 @@ def test_install_package_with_target(script):
847847
assert singlemodule_py in result.files_updated, str(result)
848848

849849

850-
def test_install_package_to_usersite_with_target_must_fail(script):
851-
"""
852-
Test that installing package to usersite with target
853-
must raise error
854-
"""
855-
target_dir = script.scratch_path / 'target'
856-
result = script.pip_install_local(
857-
'--user', '-t', target_dir, "simple==1.0", expect_error=True
858-
)
859-
assert "Can not combine '--user' and '--target'" in result.stderr, (
860-
str(result)
861-
)
862-
863-
result = script.pip_install_local(
864-
'--user', '--target', target_dir, "simple==1.0", expect_error=True
865-
)
866-
assert "Can not combine '--user' and '--target'" in result.stderr, (
867-
str(result)
868-
)
869-
870-
871850
def test_install_nonlocal_compatible_wheel(script, data):
872851
target_dir = script.scratch_path / 'target'
873852

@@ -1031,21 +1010,6 @@ def test_install_editable_with_prefix(script):
10311010
assert install_path in result.files_created, str(result)
10321011

10331012

1034-
def test_install_package_conflict_prefix_and_user(script, data):
1035-
"""
1036-
Test installing a package using pip install --prefix --user errors out
1037-
"""
1038-
prefix_path = script.scratch_path / 'prefix'
1039-
result = script.pip(
1040-
'install', '-f', data.find_links, '--no-index', '--user',
1041-
'--prefix', prefix_path, 'simple==1.0',
1042-
expect_error=True, quiet=True,
1043-
)
1044-
assert (
1045-
"Can not combine '--user' and '--prefix'" in result.stderr
1046-
)
1047-
1048-
10491013
def test_install_package_that_emits_unicode(script, data):
10501014
"""
10511015
Install a package with a setup.py that emits UTF-8 output and then fails.

tests/unit/test_command_install.py

Lines changed: 81 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import errno
2+
from itertools import product
23

34
import pytest
45
from mock import patch
@@ -9,39 +10,90 @@
910
decide_user_install,
1011
warn_deprecated_install_options,
1112
)
13+
from pip._internal.exceptions import CommandError, InstallationError
1214
from pip._internal.req.req_install import InstallRequirement
1315

16+
ENABLE_USER_SITE = 'site.ENABLE_USER_SITE'
17+
WRITABLE = 'pip._internal.commands.install.test_writable_dir'
18+
ISDIR = 'pip._internal.commands.install.os.path.isdir'
19+
EXISTS = 'pip._internal.commands.install.os.path.exists'
1420

21+
22+
def false(*args, **kwargs):
23+
"""Return False."""
24+
return False
25+
26+
27+
def true(*args, **kwargs):
28+
"""Return True."""
29+
return True
30+
31+
32+
# virtualenv_no_global is tested by functional test
33+
@patch('pip._internal.commands.install.virtualenv_no_global', false)
1534
class TestDecideUserInstall:
16-
@patch('site.ENABLE_USER_SITE', True)
17-
@patch('pip._internal.commands.install.site_packages_writable')
18-
def test_prefix_and_target(self, sp_writable):
19-
sp_writable.return_value = False
20-
21-
assert decide_user_install(
22-
use_user_site=None, prefix_path='foo'
23-
) is False
24-
25-
assert decide_user_install(
26-
use_user_site=None, target_dir='bar'
27-
) is False
28-
29-
@pytest.mark.parametrize(
30-
"enable_user_site,site_packages_writable,result", [
31-
(True, True, False),
32-
(True, False, True),
33-
(False, True, False),
34-
(False, False, False),
35-
])
36-
def test_most_cases(
37-
self, enable_user_site, site_packages_writable, result, monkeypatch,
38-
):
39-
monkeypatch.setattr('site.ENABLE_USER_SITE', enable_user_site)
40-
monkeypatch.setattr(
41-
'pip._internal.commands.install.site_packages_writable',
42-
lambda **kw: site_packages_writable
43-
)
44-
assert decide_user_install(use_user_site=None) is result
35+
@pytest.mark.parametrize('use_user_site,prefix_path,target_dir,root_path',
36+
filter(lambda args: sum(map(bool, args)) > 1,
37+
product((False, True), (None, 'foo'),
38+
(None, 'bar'), (None, 'baz'))))
39+
def test_conflicts(self, use_user_site,
40+
prefix_path, target_dir, root_path):
41+
with pytest.raises(CommandError):
42+
decide_user_install(
43+
use_user_site=use_user_site, prefix_path=prefix_path,
44+
target_dir=target_dir, root_path=root_path)
45+
46+
def test_target_dir(self):
47+
with patch(WRITABLE, true):
48+
with patch(EXISTS, true), patch(ISDIR, false):
49+
with pytest.raises(InstallationError):
50+
decide_user_install(target_dir='bar')
51+
for exists, isdir in (false, false), (false, true), (true, true):
52+
with patch(EXISTS, exists), patch(ISDIR, isdir):
53+
assert decide_user_install(target_dir='bar') is False
54+
55+
def test_target_writable(self):
56+
with patch(EXISTS, false):
57+
with patch(WRITABLE, false), pytest.raises(InstallationError):
58+
decide_user_install(target_dir='bar')
59+
with patch(WRITABLE, true):
60+
assert decide_user_install(target_dir='bar') is False
61+
62+
def test_prefix_writable(self):
63+
with patch(WRITABLE, false), pytest.raises(InstallationError):
64+
decide_user_install(prefix_path='foo')
65+
with patch(WRITABLE, true):
66+
assert decide_user_install(prefix_path='foo') is False
67+
68+
def test_global_site_writable(self):
69+
with patch(ENABLE_USER_SITE, True):
70+
with patch(WRITABLE, false):
71+
with pytest.raises(InstallationError):
72+
decide_user_install(use_user_site=False)
73+
with pytest.raises(InstallationError):
74+
decide_user_install(root_path='baz')
75+
assert decide_user_install() is True
76+
with patch(WRITABLE, true):
77+
assert decide_user_install(use_user_site=True) is True
78+
assert decide_user_install(root_path='baz') is False
79+
assert decide_user_install() is False
80+
81+
def test_enable_user_site(self):
82+
with patch(WRITABLE, true):
83+
with patch(ENABLE_USER_SITE, None):
84+
assert decide_user_install() is False
85+
assert decide_user_install(use_user_site=False) is False
86+
with pytest.raises(InstallationError):
87+
decide_user_install(use_user_site=True)
88+
with patch(ENABLE_USER_SITE, False):
89+
assert decide_user_install() is False
90+
assert decide_user_install(use_user_site=False) is False
91+
assert decide_user_install(use_user_site=True) is True
92+
with patch(ENABLE_USER_SITE, True):
93+
assert decide_user_install(use_user_site=False) is False
94+
assert decide_user_install(use_user_site=True) is True
95+
with patch(WRITABLE, false), patch(ENABLE_USER_SITE, True):
96+
assert decide_user_install() is True
4597

4698

4799
def test_deprecation_notice_for_pip_install_options(recwarn):

0 commit comments

Comments
 (0)