Skip to content

Commit

Permalink
Better message when command parsing on empty input (#2807)
Browse files Browse the repository at this point in the history
  • Loading branch information
gaborbernat committed Jan 2, 2023
1 parent d202833 commit 997128c
Show file tree
Hide file tree
Showing 6 changed files with 27 additions and 1 deletion.
1 change: 1 addition & 0 deletions docs/changelog/2695.bugfix.rst
@@ -0,0 +1 @@
Fail more gracefully when pip :ref:`install_command` is empty - by :user:`jayaddison`.
2 changes: 2 additions & 0 deletions src/tox/config/loader/str_convert.py
Expand Up @@ -63,6 +63,8 @@ def to_command(value: str) -> Command:
pos = splitter.instream.tell()
except ValueError:
args.append(value[pos:])
if len(args) == 0:
raise ValueError(f"attempting to parse {value!r} into a command failed")
if args[0] != "-" and args[0].startswith("-"):
args[0] = args[0][1:]
args = ["-"] + args
Expand Down
5 changes: 4 additions & 1 deletion src/tox/tox_env/python/pip/pip_install.py
Expand Up @@ -160,7 +160,10 @@ def _execute_installer(self, deps: Sequence[Any], of_type: str) -> None:
outcome.assert_success()

def build_install_cmd(self, args: Sequence[str]) -> list[str]:
cmd: Command = self._env.conf["install_command"]
try:
cmd: Command = self._env.conf["install_command"]
except ValueError as exc:
raise Fail(f"unable to determine pip install command: {str(exc)}") from exc
install_command = cmd.args
try:
opts_at = install_command.index("{packages}")
Expand Down
1 change: 1 addition & 0 deletions tests/config/loader/test_str_convert.py
Expand Up @@ -62,6 +62,7 @@ def test_str_convert_ok(raw: str, value: Any, of_type: type[Any]) -> None:
("a", TypeVar, TypeError, r"a cannot cast to .*typing.TypeVar.*"),
("3", Literal["1", "2"], ValueError, r"3 must be one of \('1', '2'\)"),
("3", Union[str, int], TypeError, r"3 cannot cast to typing.Union\[str, int\]"),
("", Command, ValueError, r"attempting to parse '' into a command failed"),
],
)
def test_str_convert_nok(raw: str, of_type: type[Any], msg: str, exc_type: type[Exception]) -> None:
Expand Down
8 changes: 8 additions & 0 deletions tests/session/cmd/test_show_config.py
Expand Up @@ -99,6 +99,14 @@ def test_show_config_exception(tox_project: ToxProjectCreator) -> None:
assert txt in outcome.out


def test_show_config_empty_install_command_exception(tox_project: ToxProjectCreator) -> None:
project = tox_project({"tox.ini": "[testenv:a]\ninstall_command="})
outcome = project.run("c", "-e", "a", "-k", "install_command")
outcome.assert_success()
txt = "\ninstall_command = # Exception: " "ValueError(\"attempting to parse '' into a command failed\")"
assert txt in outcome.out


@pytest.mark.parametrize("stdout_is_atty", [True, False])
def test_pass_env_config_default(tox_project: ToxProjectCreator, stdout_is_atty: bool, mocker: MockerFixture) -> None:
mocker.patch("sys.stdout.isatty", return_value=stdout_is_atty)
Expand Down
11 changes: 11 additions & 0 deletions tests/tox_env/python/pip/test_pip_install.py
Expand Up @@ -6,8 +6,10 @@
from unittest.mock import Mock

import pytest
from packaging.requirements import Requirement

from tox.pytest import CaptureFixture, ToxProjectCreator
from tox.tox_env.errors import Fail


@pytest.mark.parametrize("arg", [object, [object]])
Expand Down Expand Up @@ -35,6 +37,15 @@ def test_pip_install_empty_list(tox_project: ToxProjectCreator) -> None:
assert execute_calls.call_count == 0


def test_pip_install_empty_command_error(tox_project: ToxProjectCreator) -> None:
proj = tox_project({"tox.ini": "[testenv]\ninstall_command="})
result = proj.run("l")
pip = result.state.envs["py"].installer

with pytest.raises(Fail, match="unable to determine pip install command"):
pip.install([Requirement("name")], "section", "type")


def test_pip_install_flags_only_error(tox_project: ToxProjectCreator) -> None:
proj = tox_project({"tox.ini": "[testenv:py]\ndeps=-i a"})
result = proj.run("r")
Expand Down

0 comments on commit 997128c

Please sign in to comment.