diff --git a/src/ewoks/_requirements/poetry.py b/src/ewoks/_requirements/poetry.py index e5dfa35..2f3cceb 100644 --- a/src/ewoks/_requirements/poetry.py +++ b/src/ewoks/_requirements/poetry.py @@ -222,7 +222,7 @@ def _version_tuple(version: str) -> Tuple[int, ...]: return tuple(int(part) for part in version.split(".") if part.isdigit()) -def _python_env(python: Union[str, Path]) -> Dict[str, str]: +def _python_env(python: Union[str, Path]) -> Dict[str, Optional[str]]: """Poetry searches `PATH` for a python interpreter, which is not necessarily a working one. Make sure it finds this interpreter first. The environment of a project is the `.venv` directory inside it. @@ -231,6 +231,10 @@ def _python_env(python: Union[str, Path]) -> Dict[str, str]: return { "PATH": os.pathsep.join([str(Path(python).parent), path]), "POETRY_VIRTUALENVS_IN_PROJECT": "true", + # Poetry uses an active virtual or conda environment, for example the one + # of `poetry run`, instead of the environment of the project + "VIRTUAL_ENV": None, + "CONDA_PREFIX": None, } diff --git a/src/ewoks/_requirements/utils/base_manager.py b/src/ewoks/_requirements/utils/base_manager.py index 31d15cb..2ae0ef6 100644 --- a/src/ewoks/_requirements/utils/base_manager.py +++ b/src/ewoks/_requirements/utils/base_manager.py @@ -326,11 +326,15 @@ def _add_ewoks( pass def _check_output( - self, *args: Union[str, Path], extra_env: Optional[Mapping[str, str]] = None + self, + *args: Union[str, Path], + extra_env: Optional[Mapping[str, Optional[str]]] = None, ) -> str: return process.check_output(*self._cmd_args, *args, extra_env=extra_env) def _check_call( - self, *args: Union[str, Path], extra_env: Optional[Mapping[str, str]] = None + self, + *args: Union[str, Path], + extra_env: Optional[Mapping[str, Optional[str]]] = None, ) -> None: process.check_call(*self._cmd_args, *args, extra_env=extra_env) diff --git a/src/ewoks/_requirements/utils/process.py b/src/ewoks/_requirements/utils/process.py index 8495f2c..1143589 100644 --- a/src/ewoks/_requirements/utils/process.py +++ b/src/ewoks/_requirements/utils/process.py @@ -2,6 +2,7 @@ import os import subprocess from pathlib import Path +from typing import Dict from typing import Mapping from typing import Optional from typing import Union @@ -10,9 +11,11 @@ def check_output( - *args: Union[str, Path], extra_env: Optional[Mapping[str, str]] = None + *args: Union[str, Path], extra_env: Optional[Mapping[str, Optional[str]]] = None ) -> str: - """ + """`extra_env` adds environment variables to the current ones, or removes them + when their value is `None`. + :raises RuntimeError: command failed """ logger.debug("Capture output of %s", args) @@ -25,9 +28,11 @@ def check_output( def check_call( - *args: Union[str, Path], extra_env: Optional[Mapping[str, str]] = None + *args: Union[str, Path], extra_env: Optional[Mapping[str, Optional[str]]] = None ) -> None: - """ + """`extra_env` adds environment variables to the current ones, or removes them + when their value is `None`. + :raises RuntimeError: command failed """ logger.debug("Execute %s", args) @@ -39,7 +44,10 @@ def check_call( raise RuntimeError(f"Command failed: {args}") from ex -def _environment(extra_env: Optional[Mapping[str, str]]) -> Optional[Mapping[str, str]]: +def _environment( + extra_env: Optional[Mapping[str, Optional[str]]], +) -> Optional[Dict[str, str]]: if not extra_env: return None - return {**os.environ, **extra_env} + environment = {**os.environ, **extra_env} + return {name: value for name, value in environment.items() if value is not None} diff --git a/src/ewoks/tests/requirements/test_poetry.py b/src/ewoks/tests/requirements/test_poetry.py index 1654c9b..26d07f6 100644 --- a/src/ewoks/tests/requirements/test_poetry.py +++ b/src/ewoks/tests/requirements/test_poetry.py @@ -1,6 +1,7 @@ """Tests specific to the poetry package manager.""" import sys +import venv import pytest @@ -65,6 +66,24 @@ def test_environments_root(monkeypatch, tmp_path): assert PoetryManager().environments_root() == tmp_path +@pytest.mark.skipif(PoetryManager().version() is None, reason="poetry is not installed") +@pytest.mark.parametrize("variable", ["VIRTUAL_ENV", "CONDA_PREFIX"]) +def test_create_environment_with_active_environment(variable, monkeypatch, tmp_path): + """The environment is the one of the project, also when another environment is + active, for example the one of `poetry run`.""" + active = tmp_path / "active" + venv.create(active) + monkeypatch.setenv(variable, str(active)) + # Poetry ignores the base environment of conda + monkeypatch.setenv("CONDA_DEFAULT_ENV", "active") + + environment = PoetryManager().create_environment( + tmp_path / "project", PYTHON_VERSION + ) + + assert environment.exists() + + def test_environments_root_not_available(caplog): """Environments of ewoks when poetry cannot provide its environment directory.""" manager = PoetryManager("poetry-does-not-exist")