Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 16 additions & 1 deletion poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ dependencies = [
"trove-classifiers (>=2022.5.19)",
"virtualenv (>=20.26.6,<21.0.0)",
"xattr (>=1.0.0,<2.0.0) ; sys_platform == 'darwin'",
"findpython (>=0.6.2,<0.7.0)",
]
authors = [
{ name = "Sébastien Eustace", email = "[email protected]" }
Expand Down Expand Up @@ -182,6 +183,7 @@ warn_unused_ignores = false
module = [
'deepdiff.*',
'fastjsonschema.*',
'findpython.*',
'httpretty.*',
'requests_toolbelt.*',
'shellingham.*',
Expand Down
2 changes: 1 addition & 1 deletion src/poetry/console/commands/init.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
from poetry.console.commands.command import Command
from poetry.console.commands.env_command import EnvCommand
from poetry.utils.dependency_specification import RequirementsParser
from poetry.utils.env.python_manager import Python
from poetry.utils.env.python import Python


if TYPE_CHECKING:
Expand Down
6 changes: 0 additions & 6 deletions src/poetry/utils/env/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,6 @@
from poetry.utils.env.exceptions import EnvCommandError
from poetry.utils.env.exceptions import EnvError
from poetry.utils.env.exceptions import IncorrectEnvError
from poetry.utils.env.exceptions import InvalidCurrentPythonVersionError
from poetry.utils.env.exceptions import NoCompatiblePythonVersionFoundError
from poetry.utils.env.exceptions import PythonVersionNotFoundError
from poetry.utils.env.generic_env import GenericEnv
from poetry.utils.env.mock_env import MockEnv
from poetry.utils.env.null_env import NullEnv
Expand Down Expand Up @@ -102,11 +99,8 @@ def build_environment(
"EnvManager",
"GenericEnv",
"IncorrectEnvError",
"InvalidCurrentPythonVersionError",
"MockEnv",
"NoCompatiblePythonVersionFoundError",
"NullEnv",
"PythonVersionNotFoundError",
"SitePackages",
"SystemEnv",
"VirtualEnv",
Expand Down
67 changes: 33 additions & 34 deletions src/poetry/utils/env/env_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,11 @@
from poetry.utils._compat import encode
from poetry.utils.env.exceptions import EnvCommandError
from poetry.utils.env.exceptions import IncorrectEnvError
from poetry.utils.env.exceptions import InvalidCurrentPythonVersionError
from poetry.utils.env.exceptions import NoCompatiblePythonVersionFoundError
from poetry.utils.env.exceptions import PythonVersionNotFoundError
from poetry.utils.env.generic_env import GenericEnv
from poetry.utils.env.python_manager import Python
from poetry.utils.env.python import Python
from poetry.utils.env.python.exceptions import InvalidCurrentPythonVersionError
from poetry.utils.env.python.exceptions import NoCompatiblePythonVersionFoundError
from poetry.utils.env.python.exceptions import PythonVersionNotFoundError
from poetry.utils.env.script_strings import GET_ENV_PATH_ONELINER
from poetry.utils.env.script_strings import GET_PYTHON_VERSION_ONELINER
from poetry.utils.env.system_env import SystemEnv
Expand Down Expand Up @@ -114,17 +114,8 @@ def base_env_name(self) -> str:
def activate(self, python: str) -> Env:
venv_path = self._poetry.config.virtualenvs_path

try:
python_version = Version.parse(python)
python = f"python{python_version.major}"
if python_version.precision > 1:
python += f".{python_version.minor}"
except ValueError:
# Executable in PATH or full executable path
pass

python_ = Python.get_by_name(python)
if python_ is None:
python_instance = Python.get_by_name(python)
if python_instance is None:
raise PythonVersionNotFoundError(python)

create = False
Expand All @@ -138,10 +129,10 @@ def activate(self, python: str) -> Env:
_venv = VirtualEnv(venv)
current_patch = ".".join(str(v) for v in _venv.version_info[:3])

if python_.patch_version.to_string() != current_patch:
if python_instance.patch_version.to_string() != current_patch:
create = True

self.create_venv(executable=python_.executable, force=create)
self.create_venv(python=python_instance, force=create)

return self.get(reload=True)

Expand All @@ -154,14 +145,16 @@ def activate(self, python: str) -> Env:
current_patch = current_env["patch"]

if (
current_minor == python_.minor_version.to_string()
and current_patch != python_.patch_version.to_string()
current_minor == python_instance.minor_version.to_string()
and current_patch != python_instance.patch_version.to_string()
):
# We need to recreate
create = True

name = f"{self.base_env_name}-py{python_.minor_version.to_string()}"
venv = venv_path / name
venv = (
venv_path
/ f"{self.base_env_name}-py{python_instance.minor_version.to_string()}"
)

# Create if needed
if not venv.exists() or create:
Expand All @@ -174,15 +167,15 @@ def activate(self, python: str) -> Env:
_venv = VirtualEnv(venv)
current_patch = ".".join(str(v) for v in _venv.version_info[:3])

if python_.patch_version.to_string() != current_patch:
if python_instance.patch_version.to_string() != current_patch:
create = True

self.create_venv(executable=python_.executable, force=create)
self.create_venv(python=python_instance, force=create)

# Activate
envs[self.base_env_name] = {
"minor": python_.minor_version.to_string(),
"patch": python_.patch_version.to_string(),
"minor": python_instance.minor_version.to_string(),
"patch": python_instance.patch_version.to_string(),
}
self.envs_file.write(envs)

Expand All @@ -203,8 +196,7 @@ def get(self, reload: bool = False) -> Env:
if self._env is not None and not reload:
return self._env

python = Python.get_preferred_python(config=self._poetry.config, io=self._io)
python_minor = python.minor_version.to_string()
python_minor: str | None = None

env = None
envs = None
Expand Down Expand Up @@ -237,6 +229,13 @@ def get(self, reload: bool = False) -> Env:

venv_path = self._poetry.config.virtualenvs_path

if python_minor is None:
# we only need to discover python version in this case
python = Python.get_preferred_python(
config=self._poetry.config, io=self._io
)
python_minor = python.minor_version.to_string()

name = f"{self.base_env_name}-py{python_minor.strip()}"

venv = venv_path / name
Expand Down Expand Up @@ -372,7 +371,7 @@ def in_project_venv_exists(self) -> bool:
def create_venv(
self,
name: str | None = None,
executable: Path | None = None,
python: Python | None = None,
force: bool = False,
) -> Env:
if self._env is not None and not force:
Expand Down Expand Up @@ -400,11 +399,11 @@ def create_venv(
use_poetry_python = self._poetry.config.get("virtualenvs.use-poetry-python")
venv_prompt = self._poetry.config.get("virtualenvs.prompt")

python = (
Python(executable)
if executable
else Python.get_preferred_python(config=self._poetry.config, io=self._io)
)
specific_python_requested = python is not None
if not python:
python = Python.get_preferred_python(
config=self._poetry.config, io=self._io
)

venv_path = (
self.in_project_venv
Expand All @@ -422,7 +421,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 use_poetry_python:
if specific_python_requested and use_poetry_python:
raise NoCompatiblePythonVersionFoundError(
self._poetry.package.python_versions,
python.patch_version.to_string(),
Expand Down
36 changes: 0 additions & 36 deletions src/poetry/utils/env/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,39 +31,3 @@ def __init__(self, e: CalledProcessError) -> None:
if e.stderr:
message_parts.append(f"Error output:\n{decode(e.stderr)}")
super().__init__("\n\n".join(message_parts))


class PythonVersionNotFoundError(EnvError):
def __init__(self, expected: str) -> None:
super().__init__(f"Could not find the python executable {expected}")


class NoCompatiblePythonVersionFoundError(EnvError):
def __init__(self, expected: str, given: str | None = None) -> None:
if given:
message = (
f"The specified Python version ({given}) "
f"is not supported by the project ({expected}).\n"
"Please choose a compatible version "
"or loosen the python constraint specified "
"in the pyproject.toml file."
)
else:
message = (
"Poetry was unable to find a compatible version. "
"If you have one, you can explicitly use it "
'via the "env use" command.'
)

super().__init__(message)


class InvalidCurrentPythonVersionError(EnvError):
def __init__(self, expected: str, given: str) -> 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.'
)

super().__init__(message)
6 changes: 6 additions & 0 deletions src/poetry/utils/env/python/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from __future__ import annotations

from poetry.utils.env.python.manager import Python


__all__ = ["Python"]
41 changes: 41 additions & 0 deletions src/poetry/utils/env/python/exceptions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
from __future__ import annotations


class PythonVersionError(Exception):
pass


class PythonVersionNotFoundError(PythonVersionError):
def __init__(self, expected: str) -> None:
super().__init__(f"Could not find the python executable {expected}")


class NoCompatiblePythonVersionFoundError(PythonVersionError):
def __init__(self, expected: str, given: str | None = None) -> None:
if given:
message = (
f"The specified Python version ({given}) "
f"is not supported by the project ({expected}).\n"
"Please choose a compatible version "
"or loosen the python constraint specified "
"in the pyproject.toml file."
)
else:
message = (
"Poetry was unable to find a compatible version. "
"If you have one, you can explicitly use it "
'via the "env use" command.'
)

super().__init__(message)


class InvalidCurrentPythonVersionError(PythonVersionError):
def __init__(self, expected: str, given: str) -> 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.'
)

super().__init__(message)
Loading