diff --git a/piptools/scripts/compile.py b/piptools/scripts/compile.py index 9424968ac..18a3b312f 100755 --- a/piptools/scripts/compile.py +++ b/piptools/scripts/compile.py @@ -79,6 +79,12 @@ def _get_default_option(option_name: str) -> Any: multiple=True, help="Name of an extras_require group to install; may be used more than once", ) +@click.option( + "--all-extras", + is_flag=True, + default=False, + help="Install all extras_require groups", +) @click.option( "-f", "--find-links", @@ -259,6 +265,7 @@ def cli( pre: bool, rebuild: bool, extras: Tuple[str, ...], + all_extras: bool, find_links: Tuple[str, ...], index_url: str, extra_index_url: Tuple[str, ...], @@ -442,6 +449,11 @@ def cli( for req in metadata.get_all("Requires-Dist") or [] ] ) + if all_extras: + if extras: + msg = "--extra has no effect when used with --all-extras" + raise click.BadParameter(msg) + extras = tuple(metadata.get_all("Provides-Extra")) else: constraints.extend( parse_requirements( diff --git a/tests/test_cli_compile.py b/tests/test_cli_compile.py index 72acd52fe..5b9d57f03 100644 --- a/tests/test_cli_compile.py +++ b/tests/test_cli_compile.py @@ -2190,6 +2190,70 @@ def test_multiple_extras(fake_dists, runner, make_module, fname, content, extra_ assert "extra ==" not in out.stderr +@pytest.mark.network +@pytest.mark.parametrize(("fname", "content"), METADATA_TEST_CASES) +def test_all_extras(fake_dists, runner, make_module, fname, content): + """ + Test passing `--all-extras` includes all applicable extras. + """ + meta_path = make_module(fname=fname, content=content) + out = runner.invoke( + cli, + [ + "-n", + "--all-extras", + "--find-links", + fake_dists, + "--no-annotate", + "--no-emit-options", + "--no-header", + meta_path, + ], + ) + assert out.exit_code == 0, out.stderr + assert ( + dedent( + """\ + small-fake-a==0.1 + small-fake-b==0.2 + small-fake-c==0.3 + small-fake-d==0.4 + small-fake-e==0.5 + small-fake-f==0.6 + Dry-run, so nothing updated. + """ + ) + == out.stderr + ) + + +# This should not depend on the metadata format so testing all cases is wasteful +@pytest.mark.parametrize(("fname", "content"), METADATA_TEST_CASES[:1]) +def test_all_extras_fail_with_extra(fake_dists, runner, make_module, fname, content): + """ + Test that passing `--all-extras` and `--extra` fails. + """ + meta_path = make_module(fname=fname, content=content) + out = runner.invoke( + cli, + [ + "-n", + "--all-extras", + "--extra", + "dev", + "--find-links", + fake_dists, + "--no-annotate", + "--no-emit-options", + "--no-header", + meta_path, + ], + ) + assert out.exit_code == 2 + exp = "--extra has no effect when used with --all-extras" + assert exp in out.stderr + + def test_extras_fail_with_requirements_in(runner, tmpdir): """ Test that passing `--extra` with `requirements.in` input file fails.