Skip to content

Commit

Permalink
Use existing .venv even without explicit in-project (#7792)
Browse files Browse the repository at this point in the history
  • Loading branch information
dimbleby authored Apr 22, 2023
1 parent 6eccf92 commit dd483c8
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 22 deletions.
45 changes: 24 additions & 21 deletions src/poetry/utils/env.py
Original file line number Diff line number Diff line change
Expand Up @@ -588,6 +588,11 @@ def get_python_version(

return Version.parse(version)

@property
def in_project_venv(self) -> Path:
venv: Path = self._poetry.file.parent / ".venv"
return venv

def activate(self, python: str) -> Env:
venv_path = self._poetry.config.virtualenvs_path
cwd = self._poetry.file.parent
Expand Down Expand Up @@ -621,12 +626,11 @@ def activate(self, python: str) -> Env:
patch = python_version.text

create = False
is_root_venv = self._poetry.config.get("virtualenvs.in-project")
# If we are required to create the virtual environment in the root folder,
# If we are required to create the virtual environment in the project directory,
# create or recreate it if needed
if is_root_venv:
if self.use_in_project_venv():
create = False
venv = self._poetry.file.parent / ".venv"
venv = self.in_project_venv
if venv.exists():
# We need to check if the patch version is correct
_venv = VirtualEnv(venv)
Expand Down Expand Up @@ -730,12 +734,8 @@ def get(self, reload: bool = False) -> Env:

if not in_venv or env is not None:
# Checking if a local virtualenv exists
if (
self._poetry.config.get("virtualenvs.in-project") is not False
and (cwd / ".venv").exists()
and (cwd / ".venv").is_dir()
):
venv = cwd / ".venv"
if self.use_in_project_venv():
venv = self.in_project_venv

return VirtualEnv(venv)

Expand Down Expand Up @@ -772,12 +772,8 @@ def list(self, name: str | None = None) -> list[VirtualEnv]:
venv_path = self._poetry.config.virtualenvs_path
env_list = [VirtualEnv(p) for p in sorted(venv_path.glob(f"{venv_name}-py*"))]

venv = self._poetry.file.parent / ".venv"
if (
self._poetry.config.get("virtualenvs.in-project") is not False
and venv.exists()
and venv.is_dir()
):
if self.use_in_project_venv():
venv = self.in_project_venv
env_list.insert(0, VirtualEnv(venv))
return env_list

Expand Down Expand Up @@ -891,6 +887,12 @@ def remove(self, python: str) -> Env:

return VirtualEnv(venv_path, venv_path)

def use_in_project_venv(self) -> bool:
in_project: bool | None = self._poetry.config.get("virtualenvs.in-project")
if in_project is not None:
return in_project
return self.in_project_venv.is_dir()

def create_venv(
self,
name: str | None = None,
Expand Down Expand Up @@ -918,7 +920,7 @@ def create_venv(
return env

create_venv = self._poetry.config.get("virtualenvs.create")
root_venv = self._poetry.config.get("virtualenvs.in-project")
in_project_venv = self.use_in_project_venv()
prefer_active_python = self._poetry.config.get(
"virtualenvs.prefer-active-python"
)
Expand All @@ -927,12 +929,13 @@ def create_venv(
if not executable and prefer_active_python:
executable = self._detect_active_python()

venv_path: Path = (
cwd / ".venv" if root_venv else self._poetry.config.virtualenvs_path
venv_path = (
self.in_project_venv
if in_project_venv
else self._poetry.config.virtualenvs_path
)
if not name:
name = self._poetry.package.name
assert name is not None

python_patch = ".".join([str(v) for v in sys.version_info[:3]])
python_minor = ".".join([str(v) for v in sys.version_info[:2]])
Expand Down Expand Up @@ -1007,7 +1010,7 @@ def create_venv(
self._poetry.package.python_versions
)

if root_venv:
if in_project_venv:
venv = venv_path
else:
name = self.generate_env_name(name, str(cwd))
Expand Down
48 changes: 47 additions & 1 deletion tests/utils/test_env.py
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,52 @@ def check_output(cmd: list[str], *args: Any, **kwargs: Any) -> str:
return check_output


def test_activate_in_project_venv_no_explicit_config(
tmp_path: Path,
manager: EnvManager,
poetry: Poetry,
mocker: MockerFixture,
venv_name: str,
in_project_venv_dir: Path,
) -> None:
mocker.patch("shutil.which", side_effect=lambda py: f"/usr/bin/{py}")
mocker.patch(
"subprocess.check_output",
side_effect=check_output_wrapper(),
)
mocker.patch(
"subprocess.Popen.communicate",
side_effect=[
("/prefix", None),
('{"version_info": [3, 7, 0]}', None),
("/prefix", None),
("/prefix", None),
("/prefix", None),
],
)
m = mocker.patch("poetry.utils.env.EnvManager.build_venv", side_effect=build_venv)

env = manager.activate("python3.7")

assert env.path == tmp_path / "poetry-fixture-simple" / ".venv"
assert env.base == Path("/prefix")

m.assert_called_with(
tmp_path / "poetry-fixture-simple" / ".venv",
executable=Path("/usr/bin/python3.7"),
flags={
"always-copy": False,
"system-site-packages": False,
"no-pip": False,
"no-setuptools": False,
},
prompt="simple-project-py3.7",
)

envs_file = TOMLFile(tmp_path / "envs.toml")
assert not envs_file.exists()


def test_activate_activates_non_existing_virtualenv_no_envs_file(
tmp_path: Path,
manager: EnvManager,
Expand Down Expand Up @@ -1382,7 +1428,7 @@ def test_activate_with_in_project_setting_does_not_fail_if_no_venvs_dir(
)
mocker.patch(
"subprocess.Popen.communicate",
side_effect=[("/prefix", None), ("/prefix", None)],
side_effect=[("/prefix", None), ("/prefix", None), ("/prefix", None)],
)
m = mocker.patch("poetry.utils.env.EnvManager.build_venv")

Expand Down

0 comments on commit dd483c8

Please sign in to comment.