2727from poetry .utils .env import InvalidCurrentPythonVersionError
2828from poetry .utils .env import MockEnv
2929from poetry .utils .env import NoCompatiblePythonVersionFound
30+ from poetry .utils .env import PythonVersionNotFound
3031from poetry .utils .env import SystemEnv
3132from poetry .utils .env import VirtualEnv
3233from poetry .utils .env import build_environment
@@ -197,10 +198,12 @@ def check_output(cmd: list[str], *args: Any, **kwargs: Any) -> str:
197198 elif "sys.version_info[:2]" in python_cmd :
198199 return f"{ version .major } .{ version .minor } "
199200 elif "import sys; print(sys.executable)" in python_cmd :
200- return f"/usr/bin/{ cmd [0 ]} "
201+ executable = cmd [0 ]
202+ basename = os .path .basename (executable )
203+ return f"/usr/bin/{ basename } "
201204 else :
202205 assert "import sys; print(sys.prefix)" in python_cmd
203- return str ( Path ( "/prefix" ))
206+ return "/prefix"
204207
205208 return check_output
206209
@@ -218,6 +221,7 @@ def test_activate_activates_non_existing_virtualenv_no_envs_file(
218221
219222 config .merge ({"virtualenvs" : {"path" : str (tmp_dir )}})
220223
224+ mocker .patch ("shutil.which" , side_effect = lambda py : f"/usr/bin/{ py } " )
221225 mocker .patch (
222226 "subprocess.check_output" ,
223227 side_effect = check_output_wrapper (),
@@ -252,6 +256,30 @@ def test_activate_activates_non_existing_virtualenv_no_envs_file(
252256 assert env .base == Path ("/prefix" )
253257
254258
259+ def test_activate_fails_when_python_cannot_be_found (
260+ tmp_dir : str ,
261+ manager : EnvManager ,
262+ poetry : Poetry ,
263+ config : Config ,
264+ mocker : MockerFixture ,
265+ venv_name : str ,
266+ ) -> None :
267+ if "VIRTUAL_ENV" in os .environ :
268+ del os .environ ["VIRTUAL_ENV" ]
269+
270+ os .mkdir (os .path .join (tmp_dir , f"{ venv_name } -py3.7" ))
271+
272+ config .merge ({"virtualenvs" : {"path" : str (tmp_dir )}})
273+
274+ mocker .patch ("shutil.which" , return_value = None )
275+
276+ with pytest .raises (PythonVersionNotFound ) as e :
277+ manager .activate ("python3.7" )
278+
279+ expected_message = "Could not find the python executable python3.7"
280+ assert str (e .value ) == expected_message
281+
282+
255283def test_activate_activates_existing_virtualenv_no_envs_file (
256284 tmp_dir : str ,
257285 manager : EnvManager ,
@@ -267,6 +295,7 @@ def test_activate_activates_existing_virtualenv_no_envs_file(
267295
268296 config .merge ({"virtualenvs" : {"path" : str (tmp_dir )}})
269297
298+ mocker .patch ("shutil.which" , side_effect = lambda py : f"/usr/bin/{ py } " )
270299 mocker .patch (
271300 "subprocess.check_output" ,
272301 side_effect = check_output_wrapper (),
@@ -311,6 +340,7 @@ def test_activate_activates_same_virtualenv_with_envs_file(
311340
312341 config .merge ({"virtualenvs" : {"path" : str (tmp_dir )}})
313342
343+ mocker .patch ("shutil.which" , side_effect = lambda py : f"/usr/bin/{ py } " )
314344 mocker .patch (
315345 "subprocess.check_output" ,
316346 side_effect = check_output_wrapper (),
@@ -354,6 +384,7 @@ def test_activate_activates_different_virtualenv_with_envs_file(
354384
355385 config .merge ({"virtualenvs" : {"path" : str (tmp_dir )}})
356386
387+ mocker .patch ("shutil.which" , side_effect = lambda py : f"/usr/bin/{ py } " )
357388 mocker .patch (
358389 "subprocess.check_output" ,
359390 side_effect = check_output_wrapper (Version .parse ("3.6.6" )),
@@ -407,6 +438,7 @@ def test_activate_activates_recreates_for_different_patch(
407438
408439 config .merge ({"virtualenvs" : {"path" : str (tmp_dir )}})
409440
441+ mocker .patch ("shutil.which" , side_effect = lambda py : f"/usr/bin/{ py } " )
410442 mocker .patch (
411443 "subprocess.check_output" ,
412444 side_effect = check_output_wrapper (),
@@ -474,6 +506,7 @@ def test_activate_does_not_recreate_when_switching_minor(
474506
475507 config .merge ({"virtualenvs" : {"path" : str (tmp_dir )}})
476508
509+ mocker .patch ("shutil.which" , side_effect = lambda py : f"/usr/bin/{ py } " )
477510 mocker .patch (
478511 "subprocess.check_output" ,
479512 side_effect = check_output_wrapper (Version .parse ("3.6.6" )),
@@ -1070,6 +1103,7 @@ def test_create_venv_tries_to_find_a_compatible_python_executable_using_generic_
10701103 poetry .package .python_versions = "^3.6"
10711104
10721105 mocker .patch ("sys.version_info" , (2 , 7 , 16 ))
1106+ mocker .patch ("shutil.which" , side_effect = lambda py : f"/usr/bin/{ py } " )
10731107 mocker .patch (
10741108 "subprocess.check_output" ,
10751109 side_effect = check_output_wrapper (Version .parse ("3.7.5" )),
@@ -1093,6 +1127,34 @@ def test_create_venv_tries_to_find_a_compatible_python_executable_using_generic_
10931127 )
10941128
10951129
1130+ def test_create_venv_finds_no_python_executable (
1131+ manager : EnvManager ,
1132+ poetry : Poetry ,
1133+ config : Config ,
1134+ mocker : MockerFixture ,
1135+ config_virtualenvs_path : Path ,
1136+ venv_name : str ,
1137+ ) -> None :
1138+ if "VIRTUAL_ENV" in os .environ :
1139+ del os .environ ["VIRTUAL_ENV" ]
1140+
1141+ poetry .package .python_versions = "^3.6"
1142+
1143+ mocker .patch ("sys.version_info" , (2 , 7 , 16 ))
1144+ mocker .patch ("shutil.which" , return_value = None )
1145+
1146+ with pytest .raises (NoCompatiblePythonVersionFound ) as e :
1147+ manager .create_venv ()
1148+
1149+ expected_message = (
1150+ "Poetry was unable to find a compatible version. "
1151+ "If you have one, you can explicitly use it "
1152+ 'via the "env use" command.'
1153+ )
1154+
1155+ assert str (e .value ) == expected_message
1156+
1157+
10961158def test_create_venv_tries_to_find_a_compatible_python_executable_using_specific_ones (
10971159 manager : EnvManager ,
10981160 poetry : Poetry ,
@@ -1107,8 +1169,10 @@ def test_create_venv_tries_to_find_a_compatible_python_executable_using_specific
11071169 poetry .package .python_versions = "^3.6"
11081170
11091171 mocker .patch ("sys.version_info" , (2 , 7 , 16 ))
1172+ mocker .patch ("shutil.which" , side_effect = lambda py : f"/usr/bin/{ py } " )
11101173 mocker .patch (
1111- "subprocess.check_output" , side_effect = ["3.5.3" , "3.9.0" , "/usr/bin/python3.9" ]
1174+ "subprocess.check_output" ,
1175+ side_effect = ["/usr/bin/python3" , "3.5.3" , "/usr/bin/python3.9" , "3.9.0" ],
11121176 )
11131177 m = mocker .patch (
11141178 "poetry.utils.env.EnvManager.build_venv" , side_effect = lambda * args , ** kwargs : ""
@@ -1309,6 +1373,7 @@ def test_activate_with_in_project_setting_does_not_fail_if_no_venvs_dir(
13091373 }
13101374 )
13111375
1376+ mocker .patch ("shutil.which" , side_effect = lambda py : f"/usr/bin/{ py } " )
13121377 mocker .patch (
13131378 "subprocess.check_output" ,
13141379 side_effect = check_output_wrapper (),
@@ -1546,13 +1611,15 @@ def test_create_venv_accepts_fallback_version_w_nonzero_patchlevel(
15461611
15471612 def mock_check_output (cmd : str , * args : Any , ** kwargs : Any ) -> str :
15481613 if GET_PYTHON_VERSION_ONELINER in cmd :
1549- if "python3.5" in cmd :
1614+ executable = cmd [0 ]
1615+ if "python3.5" in str (executable ):
15501616 return "3.5.12"
15511617 else :
15521618 return "3.7.1"
15531619 else :
15541620 return "/usr/bin/python3.5"
15551621
1622+ mocker .patch ("shutil.which" , side_effect = lambda py : f"/usr/bin/{ py } " )
15561623 check_output = mocker .patch (
15571624 "subprocess.check_output" ,
15581625 side_effect = mock_check_output ,
@@ -1662,6 +1729,7 @@ def test_create_venv_project_name_empty_sets_correct_prompt(
16621729 venv_name = manager .generate_env_name ("" , str (poetry .file .parent ))
16631730
16641731 mocker .patch ("sys.version_info" , (2 , 7 , 16 ))
1732+ mocker .patch ("shutil.which" , side_effect = lambda py : f"/usr/bin/{ py } " )
16651733 mocker .patch (
16661734 "subprocess.check_output" ,
16671735 side_effect = check_output_wrapper (Version .parse ("3.7.5" )),
0 commit comments