From 2959da449e0583d822026cf8036a58dc4ffebf51 Mon Sep 17 00:00:00 2001 From: samypr100 <3933065+samypr100@users.noreply.github.com> Date: Fri, 17 Feb 2023 15:45:26 -0500 Subject: [PATCH] Warning when invalid groups are referenced --- docs/managing-dependencies.md | 10 +++++- src/poetry/console/commands/group_command.py | 32 +++++++++++++++++ tests/console/commands/test_install.py | 36 ++++++++++++++++++++ 3 files changed, 77 insertions(+), 1 deletion(-) diff --git a/docs/managing-dependencies.md b/docs/managing-dependencies.md index 16622624857..c6c4bbba7bc 100644 --- a/docs/managing-dependencies.md +++ b/docs/managing-dependencies.md @@ -162,8 +162,16 @@ the `--only` option. poetry install --only docs ``` +{{% warning %}} + +Groups provided to `--with`, `--without`, and `--only` should at least be declared in `pyproject.toml`. +Poetry will display a **Warning** if a group that is not declared is used, letting the user know of a +potential mistake. + +{{% /warning %}} + {{% note %}} -If you only want to install the project's runtime dependencies, you can do so with the +If you only want to install the project's runtime dependencies, you can do so with the `--only main` notation: ```bash diff --git a/src/poetry/console/commands/group_command.py b/src/poetry/console/commands/group_command.py index 27438bf0c07..5450f45cfb9 100644 --- a/src/poetry/console/commands/group_command.py +++ b/src/poetry/console/commands/group_command.py @@ -1,5 +1,6 @@ from __future__ import annotations +from collections import defaultdict from typing import TYPE_CHECKING from cleo.helpers import option @@ -78,6 +79,7 @@ def activated_groups(self) -> set[str]: for groups in self.option(key, "") for group in groups.split(",") } + self.validate_groups(groups) for opt, new, group in [ ("no-dev", "only", MAIN_GROUP), @@ -107,3 +109,33 @@ def project_with_activated_groups_only(self) -> ProjectPackage: return self.poetry.package.with_dependency_groups( list(self.activated_groups), only=True ) + + def validate_groups(self, group_options: dict[str, set[str]]) -> bool: + """ + Currently issues a warning if it detects that a group is + not part of pyproject.toml + + Can be overridden to adapt behavior. + """ + invalid_options = defaultdict(set) + for opt, groups in group_options.items(): + for group in groups: + try: + self.poetry.package.dependency_group(group) + except ValueError: + invalid_options[opt].add(group) + if invalid_options: + line_err = ( + "The --with, " + "--without, " + "and --only " + "options may only have valid groups." + ) + for opt, invalid_groups in invalid_options.items(): + line_err += ( + " Invalid" + f" {','.join(sorted(invalid_groups))} provided to --{opt}." + ) + line_err += "" + self.line_error(line_err) + return len(invalid_options) == 0 diff --git a/tests/console/commands/test_install.py b/tests/console/commands/test_install.py index 0200a452bfa..317ac84f542 100644 --- a/tests/console/commands/test_install.py +++ b/tests/console/commands/test_install.py @@ -257,6 +257,42 @@ def test_only_root_conflicts_with_without_only( ) +@pytest.mark.parametrize( + ("options", "valid_groups"), + [ + ({"--with": MAIN_GROUP}, {MAIN_GROUP}), + ({"--with": "spam"}, set()), + ({"--with": "spam,foo"}, {"foo"}), + ({"--without": "spam"}, set()), + ({"--without": "spam,bar"}, {"bar"}), + ({"--with": "eggs,ham", "--without": "spam"}, set()), + ({"--with": "eggs,ham", "--without": "spam,baz"}, {"baz"}), + ({"--only": "spam"}, set()), + ({"--only": "bim"}, {"bim"}), + ({"--only": MAIN_GROUP}, {MAIN_GROUP}), + ], +) +def test_invalid_groups_with_without_only( + tester: CommandTester, + mocker: MockerFixture, + options: dict[str, str], + valid_groups: set[str], +): + mocker.patch.object(tester.command.installer, "run", return_value=0) + + cmd_args = " ".join(f"{flag} {groups}" for (flag, groups) in options.items()) + tester.execute(cmd_args) + + assert tester.status_code == 0 + + io_error = tester.io.fetch_error() + for opt, groups in options.items(): + group_list = groups.split(",") + invalid_groups = ",".join(sorted(set(group_list) - valid_groups)) + if invalid_groups: + assert f"Invalid {invalid_groups} provided to {opt}." in io_error + + def test_remove_untracked_outputs_deprecation_warning( tester: CommandTester, mocker: MockerFixture,