-
-
Notifications
You must be signed in to change notification settings - Fork 146
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Resolve to interpreter 'python' in PATH if '--version' fits #224
Changes from 1 commit
0dcd1d9
1ce4c7b
a2b37a4
f1e93c6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -23,6 +23,7 @@ | |||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
IS_WINDOWS = nox.virtualenv._SYSTEM == "Windows" | ||||||||||||||||||||||||||||||||||||||||||||
RAISE_ERROR = "RAISE_ERROR" | ||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Very srs bznz! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes. I'm exceptionally proud of this line. :) Well, I at least hope it's more explicit than some fake path string like |
||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
@pytest.fixture | ||||||||||||||||||||||||||||||||||||||||||||
|
@@ -35,6 +36,47 @@ def factory(*args, **kwargs): | |||||||||||||||||||||||||||||||||||||||||||
return factory | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
@pytest.fixture | ||||||||||||||||||||||||||||||||||||||||||||
def make_mocked_interpreter_path(): | ||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Suggestion 1/2 as discussed in #224 (comment)
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||
def factory(path, sysexec_result): | ||||||||||||||||||||||||||||||||||||||||||||
def mock_sysexec(*_): | ||||||||||||||||||||||||||||||||||||||||||||
if sysexec_result == RAISE_ERROR: | ||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. First of all, thank you for re-factoring these tests at my request. I know that can be a bit annoying after you've written some useful unit tests. The core of my re-factoring request was that I was hoping we could ditch There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not annoying at all! It's an interesting challenge, and, yes, there were absolutely too many But thanks to your review, the number of I am aware that each fixture creates a new potential source for bugs, but for me, the EDIT: To mitigate, I added some documentation to the fixtures, see my two suggestions below. WDYT? |
||||||||||||||||||||||||||||||||||||||||||||
raise py.process.cmdexec.Error(1, 1, "", "", "") | ||||||||||||||||||||||||||||||||||||||||||||
else: | ||||||||||||||||||||||||||||||||||||||||||||
return sysexec_result | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
attrs = { | ||||||||||||||||||||||||||||||||||||||||||||
"sysexec.side_effect": mock_sysexec, | ||||||||||||||||||||||||||||||||||||||||||||
"__str__": mock.Mock(return_value=path), | ||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||
mock_python = mock.Mock() | ||||||||||||||||||||||||||||||||||||||||||||
mock_python.configure_mock(**attrs) | ||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ditto here, is there some reason we can't use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I understood that a plain |
||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
return mock_python | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
return factory | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
@pytest.fixture | ||||||||||||||||||||||||||||||||||||||||||||
def patch_sysfind(make_mocked_interpreter_path): | ||||||||||||||||||||||||||||||||||||||||||||
def patcher(sysfind, only_find, sysfind_result, sysexec_result): | ||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Suggestion 2/2 as discussed in #224 (comment)
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||
mock_python = make_mocked_interpreter_path(sysfind_result, sysexec_result) | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
def mock_sysfind(arg): | ||||||||||||||||||||||||||||||||||||||||||||
if sysfind_result is None: | ||||||||||||||||||||||||||||||||||||||||||||
return None | ||||||||||||||||||||||||||||||||||||||||||||
elif arg.lower() in only_find: | ||||||||||||||||||||||||||||||||||||||||||||
return mock_python | ||||||||||||||||||||||||||||||||||||||||||||
else: | ||||||||||||||||||||||||||||||||||||||||||||
return None | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
sysfind.side_effect = mock_sysfind | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
return sysfind | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
return patcher | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
def test_process_env_constructor(): | ||||||||||||||||||||||||||||||||||||||||||||
penv = nox.virtualenv.ProcessEnv() | ||||||||||||||||||||||||||||||||||||||||||||
assert not penv.bin | ||||||||||||||||||||||||||||||||||||||||||||
|
@@ -279,64 +321,53 @@ def test__resolved_interpreter_windows_pyexe_fails(sysfind, make_one): | |||||||||||||||||||||||||||||||||||||||||||
sysfind.assert_any_call("py") | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
@pytest.mark.parametrize( | ||||||||||||||||||||||||||||||||||||||||||||
["input_", "path_result", "expected"], | ||||||||||||||||||||||||||||||||||||||||||||
[ | ||||||||||||||||||||||||||||||||||||||||||||
("3.7", r"c:\python37-x64\python.exe", r"c:\python37-x64\python.exe"), | ||||||||||||||||||||||||||||||||||||||||||||
("3.7", r"c:\fails\python.exe", None), | ||||||||||||||||||||||||||||||||||||||||||||
("python3.7", r"c:\python37-x64\python.exe", None), | ||||||||||||||||||||||||||||||||||||||||||||
("2.7", r"c:\python37-x64\python.exe", None), | ||||||||||||||||||||||||||||||||||||||||||||
("goofy", r"c:\python37-x64\python.exe", None), | ||||||||||||||||||||||||||||||||||||||||||||
("3.7", None, None), | ||||||||||||||||||||||||||||||||||||||||||||
("python3.7", None, None), | ||||||||||||||||||||||||||||||||||||||||||||
("2.7", None, None), | ||||||||||||||||||||||||||||||||||||||||||||
("goofy", None, None), | ||||||||||||||||||||||||||||||||||||||||||||
], | ||||||||||||||||||||||||||||||||||||||||||||
) | ||||||||||||||||||||||||||||||||||||||||||||
@mock.patch("nox.virtualenv._SYSTEM", new="Windows") | ||||||||||||||||||||||||||||||||||||||||||||
@mock.patch.object(py.path.local, "sysfind") | ||||||||||||||||||||||||||||||||||||||||||||
def test__resolved_interpreter_windows_path_and_version( | ||||||||||||||||||||||||||||||||||||||||||||
sysfind, make_one, input_, path_result, expected | ||||||||||||||||||||||||||||||||||||||||||||
sysfind, make_one, patch_sysfind | ||||||||||||||||||||||||||||||||||||||||||||
): | ||||||||||||||||||||||||||||||||||||||||||||
# Establish that if we get a standard pythonX.Y path, we look it | ||||||||||||||||||||||||||||||||||||||||||||
# up via the path on Windows. | ||||||||||||||||||||||||||||||||||||||||||||
venv, _ = make_one(interpreter=input_) | ||||||||||||||||||||||||||||||||||||||||||||
venv, _ = make_one(interpreter="3.7") | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
# Trick the system into thinking that it cannot find python3.6 | ||||||||||||||||||||||||||||||||||||||||||||
# (it likely will on Unix). Also, we don't give it a dummy | ||||||||||||||||||||||||||||||||||||||||||||
# py launcher. But we give it a dummy python interpreter to find | ||||||||||||||||||||||||||||||||||||||||||||
# Trick the system into thinking that it cannot find | ||||||||||||||||||||||||||||||||||||||||||||
# pythonX.Y up until the python-in-path check at the end. | ||||||||||||||||||||||||||||||||||||||||||||
# Also, we don't give it a mock py launcher. | ||||||||||||||||||||||||||||||||||||||||||||
# But we give it a mock python interpreter to find | ||||||||||||||||||||||||||||||||||||||||||||
# in the system path. | ||||||||||||||||||||||||||||||||||||||||||||
if path_result: | ||||||||||||||||||||||||||||||||||||||||||||
correct_path = r"c:\python37-x64\python.exe" | ||||||||||||||||||||||||||||||||||||||||||||
patch_sysfind( | ||||||||||||||||||||||||||||||||||||||||||||
sysfind, | ||||||||||||||||||||||||||||||||||||||||||||
only_find=("python", "python.exe"), | ||||||||||||||||||||||||||||||||||||||||||||
sysfind_result=correct_path, | ||||||||||||||||||||||||||||||||||||||||||||
sysexec_result="3.7.3\\n", | ||||||||||||||||||||||||||||||||||||||||||||
) | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
def mock_sysexec(_): | ||||||||||||||||||||||||||||||||||||||||||||
if path_result == r"c:\fails\python.exe": | ||||||||||||||||||||||||||||||||||||||||||||
raise py.process.cmdexec.Error(1, 1, "", "", "") | ||||||||||||||||||||||||||||||||||||||||||||
else: | ||||||||||||||||||||||||||||||||||||||||||||
return "Python 3.7.3 | Anaconda\\n" | ||||||||||||||||||||||||||||||||||||||||||||
# Okay, now run the test. | ||||||||||||||||||||||||||||||||||||||||||||
assert str(venv._resolved_interpreter) == correct_path | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
attrs = { | ||||||||||||||||||||||||||||||||||||||||||||
"sysexec.side_effect": mock_sysexec, | ||||||||||||||||||||||||||||||||||||||||||||
"__str__.return_value": path_result, | ||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||
mock_python = mock.MagicMock() | ||||||||||||||||||||||||||||||||||||||||||||
mock_python.configure_mock(**attrs) | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
def mock_sysfind(arg): | ||||||||||||||||||||||||||||||||||||||||||||
if arg.lower() == "python" or arg.lower() == "python.exe": | ||||||||||||||||||||||||||||||||||||||||||||
return mock_python | ||||||||||||||||||||||||||||||||||||||||||||
else: | ||||||||||||||||||||||||||||||||||||||||||||
return None | ||||||||||||||||||||||||||||||||||||||||||||
@pytest.mark.parametrize("input_", ["2.7", "python3.7", "goofy"]) | ||||||||||||||||||||||||||||||||||||||||||||
@pytest.mark.parametrize("sysfind_result", [r"c:\python37-x64\python.exe", None]) | ||||||||||||||||||||||||||||||||||||||||||||
@pytest.mark.parametrize("sysexec_result", ["3.7.3\\n", RAISE_ERROR]) | ||||||||||||||||||||||||||||||||||||||||||||
@mock.patch("nox.virtualenv._SYSTEM", new="Windows") | ||||||||||||||||||||||||||||||||||||||||||||
@mock.patch.object(py.path.local, "sysfind") | ||||||||||||||||||||||||||||||||||||||||||||
def test__resolved_interpreter_windows_path_and_version_fails( | ||||||||||||||||||||||||||||||||||||||||||||
sysfind, input_, sysfind_result, sysexec_result, make_one, patch_sysfind | ||||||||||||||||||||||||||||||||||||||||||||
): | ||||||||||||||||||||||||||||||||||||||||||||
# Establish that if we get a standard pythonX.Y path, we look it | ||||||||||||||||||||||||||||||||||||||||||||
# up via the path on Windows. | ||||||||||||||||||||||||||||||||||||||||||||
venv, _ = make_one(interpreter=input_) | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
sysfind.side_effect = mock_sysfind | ||||||||||||||||||||||||||||||||||||||||||||
else: | ||||||||||||||||||||||||||||||||||||||||||||
sysfind.return_value = None | ||||||||||||||||||||||||||||||||||||||||||||
# Trick the system into thinking that it cannot find | ||||||||||||||||||||||||||||||||||||||||||||
# pythonX.Y up until the python-in-path check at the end. | ||||||||||||||||||||||||||||||||||||||||||||
# Also, we don't give it a mock py launcher. | ||||||||||||||||||||||||||||||||||||||||||||
# But we give it a mock python interpreter to find | ||||||||||||||||||||||||||||||||||||||||||||
# in the system path. | ||||||||||||||||||||||||||||||||||||||||||||
patch_sysfind(sysfind, ("python", "python.exe"), sysfind_result, sysexec_result) | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
# Okay now run the test. | ||||||||||||||||||||||||||||||||||||||||||||
if expected: | ||||||||||||||||||||||||||||||||||||||||||||
assert str(venv._resolved_interpreter) == expected | ||||||||||||||||||||||||||||||||||||||||||||
else: | ||||||||||||||||||||||||||||||||||||||||||||
with pytest.raises(nox.virtualenv.InterpreterNotFound): | ||||||||||||||||||||||||||||||||||||||||||||
venv._resolved_interpreter | ||||||||||||||||||||||||||||||||||||||||||||
with pytest.raises(nox.virtualenv.InterpreterNotFound): | ||||||||||||||||||||||||||||||||||||||||||||
venv._resolved_interpreter | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
@mock.patch("nox.virtualenv._SYSTEM", new="Windows") | ||||||||||||||||||||||||||||||||||||||||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why lift this out of the
if
statement but not out of the function as a module global?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was aiming for style consistency with
locate_via_py
. I can put it inside theif
block if it helps (would prefer not to make it module global, as it is the only time this string is used). Should I?