Skip to content

Commit

Permalink
Added virtualenvs.prompt option to config (#5606)
Browse files Browse the repository at this point in the history
  • Loading branch information
Secrus authored May 23, 2022
1 parent f1c589d commit 8a2eceb
Show file tree
Hide file tree
Showing 7 changed files with 50 additions and 5 deletions.
9 changes: 9 additions & 0 deletions docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ virtualenvs.options.no-setuptools = false
virtualenvs.options.system-site-packages = false
virtualenvs.path = "{cache-dir}/virtualenvs" # /path/to/cache/directory/virtualenvs
virtualenvs.prefer-active-python = false
virtualenvs.prompt = "{project_name}-py{python_version}"
```

## Displaying a single configuration setting
Expand Down Expand Up @@ -228,6 +229,14 @@ existing `.venv` directory.
Directory where virtual environments will be created.
Defaults to `{cache-dir}/virtualenvs` (`{cache-dir}\virtualenvs` on Windows).

### `virtualenvs.prompt`

**Type**: string

Format string defining the prompt to be displayed when the virtual environment is activated.
The variables `project_name` and `python_version` are available for formatting.
Defaults to `"{project_name}-py{python_version}"`.

### `virtualenvs.options.always-copy`

**Type**: boolean
Expand Down
17 changes: 12 additions & 5 deletions src/poetry/config/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ class Config:
"no-setuptools": False,
},
"prefer-active-python": False,
"prompt": "{project_name}-py{python_version}",
},
"experimental": {"new-installer": True, "system-git-client": False},
"installer": {"parallel": True, "max-workers": None, "no-binary": None},
Expand Down Expand Up @@ -234,11 +235,17 @@ def process(self, value: Any) -> Any:
if not isinstance(value, str):
return value

return re.sub(
r"{(.+?)}",
lambda m: self.get(m.group(1)), # type: ignore[no-any-return]
value,
)
def resolve_from_config(match: re.Match[str]) -> Any:
key = match.group(1)
config_value = self.get(key)
if config_value:
return config_value

# The key doesn't exist in the config but might be resolved later,
# so we keep it as a format variable.
return f"{{{key}}}"

return re.sub(r"{(.+?)}", resolve_from_config, value)

@staticmethod
def _get_normalizer(name: str) -> Callable[[str], Any]:
Expand Down
5 changes: 5 additions & 0 deletions src/poetry/console/commands/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,11 @@ def unique_config_values(self) -> dict[str, tuple[Any, Any, Any]]:
int_normalizer,
None,
),
"virtualenvs.prompt": (
str,
lambda val: str(val),
"{project_name}-py{python_version}",
),
"installer.no-binary": (
PackageFilterPolicy.validator,
PackageFilterPolicy.normalize,
Expand Down
11 changes: 11 additions & 0 deletions src/poetry/utils/env.py
Original file line number Diff line number Diff line change
Expand Up @@ -879,6 +879,7 @@ def create_venv(
prefer_active_python = self._poetry.config.get(
"virtualenvs.prefer-active-python"
)
venv_prompt = self._poetry.config.get("virtualenvs.prompt")

if not executable and prefer_active_python:
executable = self._detect_active_python(io)
Expand Down Expand Up @@ -980,6 +981,11 @@ def create_venv(
name = f"{name}-py{python_minor.strip()}"
venv = venv_path / name

if venv_prompt is not None:
venv_prompt = venv_prompt.format(
project_name=self._poetry.package.name, python_version=python_minor
)

if not venv.exists():
if create_venv is False:
io.write_line(
Expand Down Expand Up @@ -1011,6 +1017,7 @@ def create_venv(
venv,
executable=executable,
flags=self._poetry.config.get("virtualenvs.options"),
prompt=venv_prompt,
)

# venv detection:
Expand Down Expand Up @@ -1040,6 +1047,7 @@ def build_venv(
with_pip: bool | None = None,
with_wheel: bool | None = None,
with_setuptools: bool | None = None,
prompt: str | None = None,
) -> virtualenv.run.session.Session:
flags = flags or {}

Expand Down Expand Up @@ -1071,6 +1079,9 @@ def build_venv(
executable or sys.executable,
]

if prompt is not None:
args.extend(["--prompt", prompt])

for flag, value in flags.items():
if value is True:
args.append(f"--{flag}")
Expand Down
1 change: 1 addition & 0 deletions tests/console/commands/env/test_use.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ def test_activate_activates_non_existing_virtualenv_no_envs_file(
"no-pip": False,
"no-setuptools": False,
},
prompt="simple-project-py3.7",
)

envs_file = TOMLFile(venv_cache / "envs.toml")
Expand Down
3 changes: 3 additions & 0 deletions tests/console/commands/test_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ def test_list_displays_default_value_if_not_set(
virtualenvs.options.system-site-packages = false
virtualenvs.path = {venv_path} # {config_cache_dir / 'virtualenvs'}
virtualenvs.prefer-active-python = false
virtualenvs.prompt = "{{project_name}}-py{{python_version}}"
"""

assert tester.io.fetch_output() == expected
Expand Down Expand Up @@ -92,6 +93,7 @@ def test_list_displays_set_get_setting(
virtualenvs.options.system-site-packages = false
virtualenvs.path = {venv_path} # {config_cache_dir / 'virtualenvs'}
virtualenvs.prefer-active-python = false
virtualenvs.prompt = "{{project_name}}-py{{python_version}}"
"""

assert config.set_config_source.call_count == 0
Expand Down Expand Up @@ -144,6 +146,7 @@ def test_list_displays_set_get_local_setting(
virtualenvs.options.system-site-packages = false
virtualenvs.path = {venv_path} # {config_cache_dir / 'virtualenvs'}
virtualenvs.prefer-active-python = false
virtualenvs.prompt = "{{project_name}}-py{{python_version}}"
"""

assert config.set_config_source.call_count == 1
Expand Down
9 changes: 9 additions & 0 deletions tests/utils/test_env.py
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,7 @@ def test_activate_activates_non_existing_virtualenv_no_envs_file(
"no-pip": False,
"no-setuptools": False,
},
prompt="simple-project-py3.7",
)

envs_file = TOMLFile(Path(tmp_dir) / "envs.toml")
Expand Down Expand Up @@ -355,6 +356,7 @@ def test_activate_activates_different_virtualenv_with_envs_file(
"no-pip": False,
"no-setuptools": False,
},
prompt="simple-project-py3.6",
)

assert envs_file.exists()
Expand Down Expand Up @@ -418,6 +420,7 @@ def test_activate_activates_recreates_for_different_patch(
"no-pip": False,
"no-setuptools": False,
},
prompt="simple-project-py3.7",
)
remove_venv_m.assert_called_with(Path(tmp_dir) / f"{venv_name}-py3.7")

Expand Down Expand Up @@ -855,6 +858,7 @@ def test_create_venv_tries_to_find_a_compatible_python_executable_using_generic_
"no-pip": False,
"no-setuptools": False,
},
prompt="simple-project-py3.7",
)


Expand Down Expand Up @@ -888,6 +892,7 @@ def test_create_venv_tries_to_find_a_compatible_python_executable_using_specific
"no-pip": False,
"no-setuptools": False,
},
prompt="simple-project-py3.9",
)


Expand Down Expand Up @@ -980,6 +985,7 @@ def test_create_venv_uses_patch_version_to_detect_compatibility(
"no-pip": False,
"no-setuptools": False,
},
prompt=f"simple-project-py{version.major}.{version.minor}",
)


Expand Down Expand Up @@ -1021,6 +1027,7 @@ def test_create_venv_uses_patch_version_to_detect_compatibility_with_executable(
"no-pip": False,
"no-setuptools": False,
},
prompt=f"simple-project-py{version.major}.{version.minor - 1}",
)


Expand Down Expand Up @@ -1091,6 +1098,7 @@ def test_activate_with_in_project_setting_does_not_fail_if_no_venvs_dir(
"no-pip": False,
"no-setuptools": False,
},
prompt="simple-project-py3.7",
)

envs_file = TOMLFile(Path(tmp_dir) / "virtualenvs" / "envs.toml")
Expand Down Expand Up @@ -1324,6 +1332,7 @@ def test_create_venv_accepts_fallback_version_w_nonzero_patchlevel(
"no-pip": False,
"no-setuptools": False,
},
prompt="simple-project-py3.5",
)


Expand Down

0 comments on commit 8a2eceb

Please sign in to comment.