diff --git a/docs/configuration.md b/docs/configuration.md index 3887446006c..b81edd26513 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -48,7 +48,7 @@ virtualenvs.in-project = null virtualenvs.options.always-copy = true virtualenvs.options.system-site-packages = false virtualenvs.path = "{cache-dir}/virtualenvs" # /path/to/cache/directory/virtualenvs -virtualenvs.prefer-shell-python = false +virtualenvs.prefer-active-python = false ``` ## Displaying a single configuration setting @@ -189,7 +189,7 @@ Give the virtual environment access to the system site-packages directory. Applies on virtualenv creation. Defaults to `false`. -### `virtualenvs.prefer-shell-python` +### `virtualenvs.prefer-active-python` (experimental) **Type**: boolean diff --git a/docs/managing-environments.md b/docs/managing-environments.md index 0c7a63fecf6..605ef9940cc 100644 --- a/docs/managing-environments.md +++ b/docs/managing-environments.md @@ -27,8 +27,9 @@ to find one that is and use it. If it's unable to do so then you will be prompte to activate one explicitly, see [Switching environments](#switching-between-environments). {{% note %}} -To easily switch between Python versions, it is recommended to -use [pyenv](https://github.com/pyenv/pyenv) or similar tools. +If you use a tool like [pyenv](https://github.com/pyenv/pyenv) to manage different Python versions, +you can set the experimental `virtualenvs.prefer-active-python` option to `true`. Poetry +than will try to find the current `python` of your shell. For instance, if your project requires a newer Python than is available with your system, a standard workflow would be: @@ -38,7 +39,6 @@ pyenv install 3.9.8 pyenv local 3.9.8 # Activate Python 3.9 for the current project poetry install ``` -This requires setting the `virtualenvs.prefer-shell-python` option to `true`. {{% /note %}} ## Switching between environments diff --git a/src/poetry/config/config.py b/src/poetry/config/config.py index 86a863b0e7a..bf4898bfdd5 100644 --- a/src/poetry/config/config.py +++ b/src/poetry/config/config.py @@ -38,7 +38,7 @@ class Config: "in-project": None, "path": os.path.join("{cache-dir}", "virtualenvs"), "options": {"always-copy": False, "system-site-packages": False}, - "prefer-shell-python": False, + "prefer-active-python": False, }, "experimental": {"new-installer": True}, "installer": {"parallel": True, "max-workers": None}, @@ -139,7 +139,7 @@ def _get_normalizer(name: str) -> Callable: "virtualenvs.in-project", "virtualenvs.options.always-copy", "virtualenvs.options.system-site-packages", - "virtualenvs.options.prefer-shell-python", + "virtualenvs.options.prefer-active-python", "experimental.new-installer", "installer.parallel", }: diff --git a/src/poetry/console/application.py b/src/poetry/console/application.py index 20a80979d78..a74a68b0ff1 100644 --- a/src/poetry/console/application.py +++ b/src/poetry/console/application.py @@ -1,10 +1,8 @@ import logging import re -import subprocess from contextlib import suppress from importlib import import_module -from subprocess import CalledProcessError from typing import TYPE_CHECKING from typing import Any from typing import Callable @@ -18,14 +16,11 @@ from cleo.exceptions import CleoException from cleo.formatters.style import Style from cleo.io.inputs.argv_input import ArgvInput -from cleo.io.outputs.output import Verbosity from poetry.core.utils._compat import PY37 from poetry.__version__ import __version__ from poetry.console.command_loader import CommandLoader from poetry.console.commands.command import Command -from poetry.utils._compat import decode -from poetry.utils._compat import list_to_shell_command if TYPE_CHECKING: @@ -229,30 +224,6 @@ def _configure_io(self, io: "IO") -> None: return super()._configure_io(io) - def _detect_active_python(self, io: "IO") -> str: - executable = None - - try: - io.write_line( - "Trying to detect current active python executable as specified in the config.", - verbosity=Verbosity.VERBOSE, - ) - executable = decode( - subprocess.check_output( - list_to_shell_command( - ["python", "-c", '"import sys; print(sys.executable)"'] - ), - shell=True, - ).strip() - ) - io.write_line(f"Found: {executable}", verbosity=Verbosity.VERBOSE) - except CalledProcessError: - io.write_line( - "Unable to detect the current active python executable. Falling back to default.", - verbosity=Verbosity.VERBOSE, - ) - return executable - def register_command_loggers( self, event: "ConsoleCommandEvent", event_name: str, _: Any ) -> None: @@ -311,18 +282,8 @@ def configure_env( io = event.io poetry = command.poetry - executable = ( - self._detect_active_python(io) - if poetry.config.get("virtualenvs.prefer-shell-python") - else None - ) - env_manager = EnvManager(poetry) - env = env_manager.create_venv( - io, - executable=executable, - find_compatible=True if executable else None, - ) + env = env_manager.create_venv(io) if env.is_venv() and io.is_verbose(): io.write_line(f"Using virtualenv: {env.path}") diff --git a/src/poetry/console/commands/config.py b/src/poetry/console/commands/config.py index a8f78867757..785abe361fe 100644 --- a/src/poetry/console/commands/config.py +++ b/src/poetry/console/commands/config.py @@ -78,7 +78,7 @@ def unique_config_values(self) -> Dict[str, Tuple[Any, Any, Any]]: lambda val: str(Path(val)), str(Path(CACHE_DIR) / "virtualenvs"), ), - "virtualenvs.prefer-shell-python": ( + "virtualenvs.prefer-active-python": ( boolean_validator, boolean_normalizer, False, diff --git a/src/poetry/utils/env.py b/src/poetry/utils/env.py index efdc6bf8d00..b0cbc604516 100644 --- a/src/poetry/utils/env.py +++ b/src/poetry/utils/env.py @@ -30,6 +30,7 @@ import tomlkit import virtualenv +from cleo.io.outputs.output import Verbosity from packaging.tags import Tag from packaging.tags import interpreter_name from packaging.tags import interpreter_version @@ -464,6 +465,30 @@ class EnvManager: def __init__(self, poetry: "Poetry") -> None: self._poetry = poetry + def _detect_active_python(self, io: "IO") -> str: + executable = None + + try: + io.write_line( + "Trying to detect current active python executable as specified in the config.", + verbosity=Verbosity.VERBOSE, + ) + executable = decode( + subprocess.check_output( + list_to_shell_command( + ["python", "-c", '"import sys; print(sys.executable)"'] + ), + shell=True, + ).strip() + ) + io.write_line(f"Found: {executable}", verbosity=Verbosity.VERBOSE) + except CalledProcessError: + io.write_line( + "Unable to detect the current active python executable. Falling back to default.", + verbosity=Verbosity.VERBOSE, + ) + return executable + def activate(self, python: str, io: "IO") -> "Env": venv_path = self._poetry.config.get("virtualenvs.path") if venv_path is None: @@ -763,7 +788,6 @@ def create_venv( name: Optional[str] = None, executable: Optional[str] = None, force: bool = False, - find_compatible: Optional[bool] = None, ) -> Union["SystemEnv", "VirtualEnv"]: if self._env is not None and not force: return self._env @@ -781,6 +805,12 @@ def create_venv( create_venv = self._poetry.config.get("virtualenvs.create") root_venv = self._poetry.config.get("virtualenvs.in-project") venv_path = self._poetry.config.get("virtualenvs.path") + prefer_active_python = self._poetry.config.get( + "virtualenvs.prefer-active-python" + ) + + if not executable and prefer_active_python: + executable = self._detect_active_python(io) if root_venv: venv_path = cwd / ".venv" @@ -813,7 +843,7 @@ def create_venv( # If an executable has been specified, we stop there # and notify the user of the incompatibility. # Otherwise, we try to find a compatible Python version. - if executable and not find_compatible: + if executable and not prefer_active_python: raise NoCompatiblePythonVersionFound( self._poetry.package.python_versions, python_patch ) diff --git a/tests/console/commands/test_config.py b/tests/console/commands/test_config.py index 9aca2b3d78a..f515eb4fc67 100644 --- a/tests/console/commands/test_config.py +++ b/tests/console/commands/test_config.py @@ -56,7 +56,7 @@ def test_list_displays_default_value_if_not_set( virtualenvs.options.always-copy = false virtualenvs.options.system-site-packages = false virtualenvs.path = {venv_path} # {config_cache_dir / 'virtualenvs'} -virtualenvs.prefer-shell-python = false +virtualenvs.prefer-active-python = false """ assert expected == tester.io.fetch_output() @@ -80,7 +80,7 @@ def test_list_displays_set_get_setting( virtualenvs.options.always-copy = false virtualenvs.options.system-site-packages = false virtualenvs.path = {venv_path} # {config_cache_dir / 'virtualenvs'} -virtualenvs.prefer-shell-python = false +virtualenvs.prefer-active-python = false """ assert config.set_config_source.call_count == 0 @@ -128,7 +128,7 @@ def test_list_displays_set_get_local_setting( virtualenvs.options.always-copy = false virtualenvs.options.system-site-packages = false virtualenvs.path = {venv_path} # {config_cache_dir / 'virtualenvs'} -virtualenvs.prefer-shell-python = false +virtualenvs.prefer-active-python = false """ assert config.set_config_source.call_count == 1