Commit 78b3b551 by finswimmer Committed by Bjorn Neergaard

refactor: IO for EnvManager is now set on init

parent 14b7f1ee
...@@ -295,8 +295,8 @@ class Application(BaseApplication): ...@@ -295,8 +295,8 @@ class Application(BaseApplication):
io = event.io io = event.io
poetry = command.poetry poetry = command.poetry
env_manager = EnvManager(poetry) env_manager = EnvManager(poetry, io=io)
env = env_manager.create_venv(io) env = env_manager.create_venv()
if env.is_venv() and io.is_verbose(): if env.is_venv() and io.is_verbose():
io.write_line(f"Using virtualenv: <comment>{env.path}</>") io.write_line(f"Using virtualenv: <comment>{env.path}</>")
......
...@@ -14,14 +14,14 @@ class EnvUseCommand(Command): ...@@ -14,14 +14,14 @@ class EnvUseCommand(Command):
def handle(self) -> int: def handle(self) -> int:
from poetry.utils.env import EnvManager from poetry.utils.env import EnvManager
manager = EnvManager(self.poetry) manager = EnvManager(self.poetry, io=self.io)
if self.argument("python") == "system": if self.argument("python") == "system":
manager.deactivate(self.io) manager.deactivate()
return 0 return 0
env = manager.activate(self.argument("python"), self.io) env = manager.activate(self.argument("python"))
self.line(f"Using virtualenv: <comment>{env.path}</>") self.line(f"Using virtualenv: <comment>{env.path}</>")
......
...@@ -25,6 +25,7 @@ import packaging.tags ...@@ -25,6 +25,7 @@ import packaging.tags
import tomlkit import tomlkit
import virtualenv import virtualenv
from cleo.io.null_io import NullIO
from cleo.io.outputs.output import Verbosity from cleo.io.outputs.output import Verbosity
from packaging.tags import Tag from packaging.tags import Tag
from packaging.tags import interpreter_name from packaging.tags import interpreter_name
...@@ -515,8 +516,9 @@ class EnvManager: ...@@ -515,8 +516,9 @@ class EnvManager:
ENVS_FILE = "envs.toml" ENVS_FILE = "envs.toml"
def __init__(self, poetry: Poetry) -> None: def __init__(self, poetry: Poetry, io: None | IO = None) -> None:
self._poetry = poetry self._poetry = poetry
self._io = io or NullIO()
def _full_python_path(self, python: str) -> str: def _full_python_path(self, python: str) -> str:
try: try:
...@@ -533,26 +535,28 @@ class EnvManager: ...@@ -533,26 +535,28 @@ class EnvManager:
return executable return executable
def _detect_active_python(self, io: IO) -> str | None: def _detect_active_python(self) -> str | None:
executable = None executable = None
try: try:
io.write_error_line( self._io.write_error_line(
"Trying to detect current active python executable as specified in the" "Trying to detect current active python executable as specified in the"
" config.", " config.",
verbosity=Verbosity.VERBOSE, verbosity=Verbosity.VERBOSE,
) )
executable = self._full_python_path("python") executable = self._full_python_path("python")
io.write_error_line(f"Found: {executable}", verbosity=Verbosity.VERBOSE) self._io.write_error_line(
f"Found: {executable}", verbosity=Verbosity.VERBOSE
)
except CalledProcessError: except CalledProcessError:
io.write_error_line( self._io.write_error_line(
"Unable to detect the current active python executable. Falling back to" "Unable to detect the current active python executable. Falling back to"
" default.", " default.",
verbosity=Verbosity.VERBOSE, verbosity=Verbosity.VERBOSE,
) )
return executable return executable
def activate(self, python: str, io: IO) -> Env: def activate(self, python: str) -> Env:
venv_path = self._poetry.config.virtualenvs_path venv_path = self._poetry.config.virtualenvs_path
cwd = self._poetry.file.parent cwd = self._poetry.file.parent
...@@ -598,7 +602,7 @@ class EnvManager: ...@@ -598,7 +602,7 @@ class EnvManager:
if patch != current_patch: if patch != current_patch:
create = True create = True
self.create_venv(io, executable=python, force=create) self.create_venv(executable=python, force=create)
return self.get(reload=True) return self.get(reload=True)
...@@ -632,7 +636,7 @@ class EnvManager: ...@@ -632,7 +636,7 @@ class EnvManager:
if patch != current_patch: if patch != current_patch:
create = True create = True
self.create_venv(io, executable=python, force=create) self.create_venv(executable=python, force=create)
# Activate # Activate
envs[base_env_name] = {"minor": minor, "patch": patch} envs[base_env_name] = {"minor": minor, "patch": patch}
...@@ -640,7 +644,7 @@ class EnvManager: ...@@ -640,7 +644,7 @@ class EnvManager:
return self.get(reload=True) return self.get(reload=True)
def deactivate(self, io: IO) -> None: def deactivate(self) -> None:
venv_path = self._poetry.config.virtualenvs_path venv_path = self._poetry.config.virtualenvs_path
name = self.generate_env_name( name = self.generate_env_name(
self._poetry.package.name, str(self._poetry.file.parent) self._poetry.package.name, str(self._poetry.file.parent)
...@@ -652,7 +656,7 @@ class EnvManager: ...@@ -652,7 +656,7 @@ class EnvManager:
env = envs.get(name) env = envs.get(name)
if env is not None: if env is not None:
venv = venv_path / f"{name}-py{env['minor']}" venv = venv_path / f"{name}-py{env['minor']}"
io.write_error_line( self._io.write_error_line(
f"Deactivating virtualenv: <comment>{venv}</comment>" f"Deactivating virtualenv: <comment>{venv}</comment>"
) )
del envs[name] del envs[name]
...@@ -855,7 +859,6 @@ class EnvManager: ...@@ -855,7 +859,6 @@ class EnvManager:
def create_venv( def create_venv(
self, self,
io: IO,
name: str | None = None, name: str | None = None,
executable: str | None = None, executable: str | None = None,
force: bool = False, force: bool = False,
...@@ -888,7 +891,7 @@ class EnvManager: ...@@ -888,7 +891,7 @@ class EnvManager:
venv_prompt = self._poetry.config.get("virtualenvs.prompt") venv_prompt = self._poetry.config.get("virtualenvs.prompt")
if not executable and prefer_active_python: if not executable and prefer_active_python:
executable = self._detect_active_python(io) executable = self._detect_active_python()
venv_path = cwd / ".venv" if root_venv else self._poetry.config.virtualenvs_path venv_path = cwd / ".venv" if root_venv else self._poetry.config.virtualenvs_path
if not name: if not name:
...@@ -921,7 +924,7 @@ class EnvManager: ...@@ -921,7 +924,7 @@ class EnvManager:
self._poetry.package.python_versions, python_patch self._poetry.package.python_versions, python_patch
) )
io.write_error_line( self._io.write_error_line(
f"<warning>The currently activated Python version {python_patch} is not" f"<warning>The currently activated Python version {python_patch} is not"
f" supported by the project ({self._poetry.package.python_versions}).\n" f" supported by the project ({self._poetry.package.python_versions}).\n"
"Trying to find and use a compatible version.</warning> " "Trying to find and use a compatible version.</warning> "
...@@ -944,8 +947,8 @@ class EnvManager: ...@@ -944,8 +947,8 @@ class EnvManager:
python = "python" + python_to_try python = "python" + python_to_try
if io.is_debug(): if self._io.is_debug():
io.write_error_line(f"<debug>Trying {python}</debug>") self._io.write_error_line(f"<debug>Trying {python}</debug>")
try: try:
python_patch = decode( python_patch = decode(
...@@ -964,7 +967,9 @@ class EnvManager: ...@@ -964,7 +967,9 @@ class EnvManager:
continue continue
if supported_python.allows(Version.parse(python_patch)): if supported_python.allows(Version.parse(python_patch)):
io.write_error_line(f"Using <c1>{python}</c1> ({python_patch})") self._io.write_error_line(
f"Using <c1>{python}</c1> ({python_patch})"
)
executable = python executable = python
python_minor = ".".join(python_patch.split(".")[:2]) python_minor = ".".join(python_patch.split(".")[:2])
break break
...@@ -989,7 +994,7 @@ class EnvManager: ...@@ -989,7 +994,7 @@ class EnvManager:
if not venv.exists(): if not venv.exists():
if create_venv is False: if create_venv is False:
io.write_error_line( self._io.write_error_line(
"<fg=black;bg=yellow>" "<fg=black;bg=yellow>"
"Skipping virtualenv creation, " "Skipping virtualenv creation, "
"as specified in config file." "as specified in config file."
...@@ -998,7 +1003,7 @@ class EnvManager: ...@@ -998,7 +1003,7 @@ class EnvManager:
return self.get_system_env() return self.get_system_env()
io.write_error_line( self._io.write_error_line(
f"Creating virtualenv <c1>{name}</> in" f"Creating virtualenv <c1>{name}</> in"
f" {venv_path if not WINDOWS else get_real_windows_path(venv_path)!s}" f" {venv_path if not WINDOWS else get_real_windows_path(venv_path)!s}"
) )
...@@ -1006,15 +1011,17 @@ class EnvManager: ...@@ -1006,15 +1011,17 @@ class EnvManager:
create_venv = False create_venv = False
if force: if force:
if not env.is_sane(): if not env.is_sane():
io.write_error_line( self._io.write_error_line(
f"<warning>The virtual environment found in {env.path} seems to" f"<warning>The virtual environment found in {env.path} seems to"
" be broken.</warning>" " be broken.</warning>"
) )
io.write_error_line(f"Recreating virtualenv <c1>{name}</> in {venv!s}") self._io.write_error_line(
f"Recreating virtualenv <c1>{name}</> in {venv!s}"
)
self.remove_venv(venv) self.remove_venv(venv)
create_venv = True create_venv = True
elif io.is_very_verbose(): elif self._io.is_very_verbose():
io.write_error_line(f"Virtualenv <c1>{name}</> already exists.") self._io.write_error_line(f"Virtualenv <c1>{name}</> already exists.")
if create_venv: if create_venv:
self.build_venv( self.build_venv(
......
...@@ -11,7 +11,6 @@ from typing import Any ...@@ -11,7 +11,6 @@ from typing import Any
import pytest import pytest
import tomlkit import tomlkit
from cleo.io.null_io import NullIO
from poetry.core.constraints.version import Version from poetry.core.constraints.version import Version
from poetry.core.toml.file import TOMLFile from poetry.core.toml.file import TOMLFile
...@@ -226,7 +225,7 @@ def test_activate_activates_non_existing_virtualenv_no_envs_file( ...@@ -226,7 +225,7 @@ def test_activate_activates_non_existing_virtualenv_no_envs_file(
) )
m = mocker.patch("poetry.utils.env.EnvManager.build_venv", side_effect=build_venv) m = mocker.patch("poetry.utils.env.EnvManager.build_venv", side_effect=build_venv)
env = manager.activate("python3.7", NullIO()) env = manager.activate("python3.7")
m.assert_called_with( m.assert_called_with(
Path(tmp_dir) / f"{venv_name}-py3.7", Path(tmp_dir) / f"{venv_name}-py3.7",
...@@ -275,7 +274,7 @@ def test_activate_activates_existing_virtualenv_no_envs_file( ...@@ -275,7 +274,7 @@ def test_activate_activates_existing_virtualenv_no_envs_file(
) )
m = mocker.patch("poetry.utils.env.EnvManager.build_venv", side_effect=build_venv) m = mocker.patch("poetry.utils.env.EnvManager.build_venv", side_effect=build_venv)
env = manager.activate("python3.7", NullIO()) env = manager.activate("python3.7")
m.assert_not_called() m.assert_not_called()
...@@ -319,7 +318,7 @@ def test_activate_activates_same_virtualenv_with_envs_file( ...@@ -319,7 +318,7 @@ def test_activate_activates_same_virtualenv_with_envs_file(
) )
m = mocker.patch("poetry.utils.env.EnvManager.create_venv") m = mocker.patch("poetry.utils.env.EnvManager.create_venv")
env = manager.activate("python3.7", NullIO()) env = manager.activate("python3.7")
m.assert_not_called() m.assert_not_called()
...@@ -362,7 +361,7 @@ def test_activate_activates_different_virtualenv_with_envs_file( ...@@ -362,7 +361,7 @@ def test_activate_activates_different_virtualenv_with_envs_file(
) )
m = mocker.patch("poetry.utils.env.EnvManager.build_venv", side_effect=build_venv) m = mocker.patch("poetry.utils.env.EnvManager.build_venv", side_effect=build_venv)
env = manager.activate("python3.6", NullIO()) env = manager.activate("python3.6")
m.assert_called_with( m.assert_called_with(
Path(tmp_dir) / f"{venv_name}-py3.6", Path(tmp_dir) / f"{venv_name}-py3.6",
...@@ -426,7 +425,7 @@ def test_activate_activates_recreates_for_different_patch( ...@@ -426,7 +425,7 @@ def test_activate_activates_recreates_for_different_patch(
"poetry.utils.env.EnvManager.remove_venv", side_effect=EnvManager.remove_venv "poetry.utils.env.EnvManager.remove_venv", side_effect=EnvManager.remove_venv
) )
env = manager.activate("python3.7", NullIO()) env = manager.activate("python3.7")
build_venv_m.assert_called_with( build_venv_m.assert_called_with(
Path(tmp_dir) / f"{venv_name}-py3.7", Path(tmp_dir) / f"{venv_name}-py3.7",
...@@ -487,7 +486,7 @@ def test_activate_does_not_recreate_when_switching_minor( ...@@ -487,7 +486,7 @@ def test_activate_does_not_recreate_when_switching_minor(
"poetry.utils.env.EnvManager.remove_venv", side_effect=EnvManager.remove_venv "poetry.utils.env.EnvManager.remove_venv", side_effect=EnvManager.remove_venv
) )
env = manager.activate("python3.6", NullIO()) env = manager.activate("python3.6")
build_venv_m.assert_not_called() build_venv_m.assert_not_called()
remove_venv_m.assert_not_called() remove_venv_m.assert_not_called()
...@@ -523,7 +522,7 @@ def test_deactivate_non_activated_but_existing( ...@@ -523,7 +522,7 @@ def test_deactivate_non_activated_but_existing(
side_effect=check_output_wrapper(), side_effect=check_output_wrapper(),
) )
manager.deactivate(NullIO()) manager.deactivate()
env = manager.get() env = manager.get()
assert env.path == Path(tmp_dir) / f"{venv_name}-py{python}" assert env.path == Path(tmp_dir) / f"{venv_name}-py{python}"
...@@ -563,7 +562,7 @@ def test_deactivate_activated( ...@@ -563,7 +562,7 @@ def test_deactivate_activated(
side_effect=check_output_wrapper(), side_effect=check_output_wrapper(),
) )
manager.deactivate(NullIO()) manager.deactivate()
env = manager.get() env = manager.get()
assert env.path == Path(tmp_dir) / f"{venv_name}-py{version.major}.{version.minor}" assert env.path == Path(tmp_dir) / f"{venv_name}-py{version.major}.{version.minor}"
...@@ -999,7 +998,7 @@ def test_create_venv_tries_to_find_a_compatible_python_executable_using_generic_ ...@@ -999,7 +998,7 @@ def test_create_venv_tries_to_find_a_compatible_python_executable_using_generic_
"poetry.utils.env.EnvManager.build_venv", side_effect=lambda *args, **kwargs: "" "poetry.utils.env.EnvManager.build_venv", side_effect=lambda *args, **kwargs: ""
) )
manager.create_venv(NullIO()) manager.create_venv()
m.assert_called_with( m.assert_called_with(
config_virtualenvs_path / f"{venv_name}-py3.7", config_virtualenvs_path / f"{venv_name}-py3.7",
...@@ -1033,7 +1032,7 @@ def test_create_venv_tries_to_find_a_compatible_python_executable_using_specific ...@@ -1033,7 +1032,7 @@ def test_create_venv_tries_to_find_a_compatible_python_executable_using_specific
"poetry.utils.env.EnvManager.build_venv", side_effect=lambda *args, **kwargs: "" "poetry.utils.env.EnvManager.build_venv", side_effect=lambda *args, **kwargs: ""
) )
manager.create_venv(NullIO()) manager.create_venv()
m.assert_called_with( m.assert_called_with(
config_virtualenvs_path / f"{venv_name}-py3.9", config_virtualenvs_path / f"{venv_name}-py3.9",
...@@ -1062,7 +1061,7 @@ def test_create_venv_fails_if_no_compatible_python_version_could_be_found( ...@@ -1062,7 +1061,7 @@ def test_create_venv_fails_if_no_compatible_python_version_could_be_found(
) )
with pytest.raises(NoCompatiblePythonVersionFound) as e: with pytest.raises(NoCompatiblePythonVersionFound) as e:
manager.create_venv(NullIO()) manager.create_venv()
expected_message = ( expected_message = (
"Poetry was unable to find a compatible version. " "Poetry was unable to find a compatible version. "
...@@ -1088,7 +1087,7 @@ def test_create_venv_does_not_try_to_find_compatible_versions_with_executable( ...@@ -1088,7 +1087,7 @@ def test_create_venv_does_not_try_to_find_compatible_versions_with_executable(
) )
with pytest.raises(NoCompatiblePythonVersionFound) as e: with pytest.raises(NoCompatiblePythonVersionFound) as e:
manager.create_venv(NullIO(), executable="3.8") manager.create_venv(executable="3.8")
expected_message = ( expected_message = (
"The specified Python version (3.8.0) is not supported by the project (^4.8).\n" "The specified Python version (3.8.0) is not supported by the project (^4.8).\n"
...@@ -1125,7 +1124,7 @@ def test_create_venv_uses_patch_version_to_detect_compatibility( ...@@ -1125,7 +1124,7 @@ def test_create_venv_uses_patch_version_to_detect_compatibility(
"poetry.utils.env.EnvManager.build_venv", side_effect=lambda *args, **kwargs: "" "poetry.utils.env.EnvManager.build_venv", side_effect=lambda *args, **kwargs: ""
) )
manager.create_venv(NullIO()) manager.create_venv()
assert not check_output.called assert not check_output.called
m.assert_called_with( m.assert_called_with(
...@@ -1165,9 +1164,7 @@ def test_create_venv_uses_patch_version_to_detect_compatibility_with_executable( ...@@ -1165,9 +1164,7 @@ def test_create_venv_uses_patch_version_to_detect_compatibility_with_executable(
"poetry.utils.env.EnvManager.build_venv", side_effect=lambda *args, **kwargs: "" "poetry.utils.env.EnvManager.build_venv", side_effect=lambda *args, **kwargs: ""
) )
manager.create_venv( manager.create_venv(executable=f"python{version.major}.{version.minor - 1}")
NullIO(), executable=f"python{version.major}.{version.minor - 1}"
)
assert check_output.called assert check_output.called
m.assert_called_with( m.assert_called_with(
...@@ -1189,7 +1186,7 @@ def test_create_venv_fails_if_current_python_version_is_not_supported( ...@@ -1189,7 +1186,7 @@ def test_create_venv_fails_if_current_python_version_is_not_supported(
if "VIRTUAL_ENV" in os.environ: if "VIRTUAL_ENV" in os.environ:
del os.environ["VIRTUAL_ENV"] del os.environ["VIRTUAL_ENV"]
manager.create_venv(NullIO()) manager.create_venv()
current_version = Version.parse(".".join(str(c) for c in sys.version_info[:3])) current_version = Version.parse(".".join(str(c) for c in sys.version_info[:3]))
next_version = ".".join( next_version = ".".join(
...@@ -1199,7 +1196,7 @@ def test_create_venv_fails_if_current_python_version_is_not_supported( ...@@ -1199,7 +1196,7 @@ def test_create_venv_fails_if_current_python_version_is_not_supported(
poetry.package.python_versions = package_version poetry.package.python_versions = package_version
with pytest.raises(InvalidCurrentPythonVersionError) as e: with pytest.raises(InvalidCurrentPythonVersionError) as e:
manager.create_venv(NullIO()) manager.create_venv()
expected_message = ( expected_message = (
f"Current Python version ({current_version}) is not allowed by the project" f"Current Python version ({current_version}) is not allowed by the project"
...@@ -1239,7 +1236,7 @@ def test_activate_with_in_project_setting_does_not_fail_if_no_venvs_dir( ...@@ -1239,7 +1236,7 @@ def test_activate_with_in_project_setting_does_not_fail_if_no_venvs_dir(
) )
m = mocker.patch("poetry.utils.env.EnvManager.build_venv") m = mocker.patch("poetry.utils.env.EnvManager.build_venv")
manager.activate("python3.7", NullIO()) manager.activate("python3.7")
m.assert_called_with( m.assert_called_with(
poetry.file.parent / ".venv", poetry.file.parent / ".venv",
...@@ -1472,7 +1469,7 @@ def test_create_venv_accepts_fallback_version_w_nonzero_patchlevel( ...@@ -1472,7 +1469,7 @@ def test_create_venv_accepts_fallback_version_w_nonzero_patchlevel(
"poetry.utils.env.EnvManager.build_venv", side_effect=lambda *args, **kwargs: "" "poetry.utils.env.EnvManager.build_venv", side_effect=lambda *args, **kwargs: ""
) )
manager.create_venv(NullIO()) manager.create_venv()
assert check_output.called assert check_output.called
m.assert_called_with( m.assert_called_with(
...@@ -1581,7 +1578,7 @@ def test_create_venv_project_name_empty_sets_correct_prompt( ...@@ -1581,7 +1578,7 @@ def test_create_venv_project_name_empty_sets_correct_prompt(
"poetry.utils.env.EnvManager.build_venv", side_effect=lambda *args, **kwargs: "" "poetry.utils.env.EnvManager.build_venv", side_effect=lambda *args, **kwargs: ""
) )
manager.create_venv(NullIO()) manager.create_venv()
m.assert_called_with( m.assert_called_with(
config_virtualenvs_path / f"{venv_name}-py3.7", config_virtualenvs_path / f"{venv_name}-py3.7",
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment