From 257c576d97ab6d30bf873695c88f924df73c002d Mon Sep 17 00:00:00 2001 From: lyijian86-source Date: Sat, 6 Jun 2026 20:36:58 +0800 Subject: [PATCH] fix(env): fail on incompatible Python without venv creation --- src/poetry/utils/env/env_manager.py | 12 ++++++ src/poetry/utils/env/python/exceptions.py | 4 +- tests/utils/env/test_env_manager.py | 46 +++++++++++++++++++++++ 3 files changed, 61 insertions(+), 1 deletion(-) diff --git a/src/poetry/utils/env/env_manager.py b/src/poetry/utils/env/env_manager.py index 2087b1b3f6e..47ed5661826 100644 --- a/src/poetry/utils/env/env_manager.py +++ b/src/poetry/utils/env/env_manager.py @@ -408,6 +408,18 @@ def create_venv( name = self._poetry.package.name supported_python = self._poetry.package.python_constraint + if create_venv is False: + current_python = Version.parse( + ".".join(str(c) for c in env.version_info[:3]) + ) + if not supported_python.allows(current_python): + raise InvalidCurrentPythonVersionError( + self._poetry.package.python_versions, + str(current_python), + "Poetry cannot switch to a compatible Python version because " + "virtualenv creation is disabled.", + ) + if not supported_python.allows(python.patch_version): # The currently activated or chosen Python version # is not compatible with the Python constraint specified diff --git a/src/poetry/utils/env/python/exceptions.py b/src/poetry/utils/env/python/exceptions.py index 1663df16b50..fa7aa6eb29e 100644 --- a/src/poetry/utils/env/python/exceptions.py +++ b/src/poetry/utils/env/python/exceptions.py @@ -31,11 +31,13 @@ def __init__(self, expected: str, given: str | None = None) -> None: class InvalidCurrentPythonVersionError(PythonVersionError): - def __init__(self, expected: str, given: str) -> None: + def __init__(self, expected: str, given: str, note: str | None = None) -> None: message = ( f"Current Python version ({given}) " f"is not allowed by the project ({expected}).\n" 'Please change python executable via the "env use" command.' ) + if note is not None: + message = f"{message}\n{note}" super().__init__(message) diff --git a/tests/utils/env/test_env_manager.py b/tests/utils/env/test_env_manager.py index 3e990e81872..31b5d894b07 100644 --- a/tests/utils/env/test_env_manager.py +++ b/tests/utils/env/test_env_manager.py @@ -21,6 +21,7 @@ from poetry.utils.env import EnvManager from poetry.utils.env import IncorrectEnvError from poetry.utils.env.env_manager import EnvsFile +from poetry.utils.env.mock_env import MockEnv from poetry.utils.env.python.exceptions import InvalidCurrentPythonVersionError from poetry.utils.env.python.exceptions import NoCompatiblePythonVersionFoundError from poetry.utils.env.python.exceptions import PythonVersionNotFoundError @@ -32,6 +33,7 @@ from collections.abc import Iterator from unittest.mock import MagicMock + from _pytest.monkeypatch import MonkeyPatch from cleo.io.buffered_io import BufferedIO from pytest import LogCaptureFixture from pytest_mock import MockerFixture @@ -1069,6 +1071,50 @@ def test_create_venv_fails_if_no_compatible_python_version_could_be_found( assert m.call_count == 0 +@pytest.mark.parametrize("use_poetry_python", [True, False]) +def test_create_venv_fails_if_current_python_is_not_supported_without_creating_venv( + manager: EnvManager, + poetry: Poetry, + config: Config, + mocker: MockerFixture, + mocked_python_register: MockedPythonRegister, + monkeypatch: MonkeyPatch, + use_poetry_python: bool, +) -> None: + config.config["virtualenvs"]["create"] = False + config.config["virtualenvs"]["use-poetry-python"] = use_poetry_python + monkeypatch.delenv("VIRTUAL_ENV", raising=False) + + poetry.package.python_versions = "^3.10" + + current_python = mocked_python_register("3.9.0") + compatible_python = mocked_python_register("3.10.0") + mocker.patch.object(manager, "get", return_value=MockEnv(version_info=(3, 9, 0))) + mocker.patch( + "poetry.utils.env.env_manager.Python.get_preferred_python", + return_value=current_python if use_poetry_python else compatible_python, + ) + get_compatible_python = mocker.patch( + "poetry.utils.env.env_manager.Python.get_compatible_python", + return_value=compatible_python, + ) + build_venv = mocker.patch("poetry.utils.env.EnvManager.build_venv") + + with pytest.raises(InvalidCurrentPythonVersionError) as e: + manager.create_venv() + + expected_message = ( + "Current Python version (3.9.0) is not allowed by the project (^3.10).\n" + 'Please change python executable via the "env use" command.\n' + "Poetry cannot switch to a compatible Python version because virtualenv " + "creation is disabled." + ) + + assert str(e.value) == expected_message + get_compatible_python.assert_not_called() + build_venv.assert_not_called() + + @pytest.mark.parametrize("use_poetry_python", [True, False]) def test_create_venv_does_not_try_to_find_compatible_versions_with_executable( manager: EnvManager,