Skip to content

Commit

Permalink
Allow wildcard argument for --extra
Browse files Browse the repository at this point in the history
The goal is to make it easy to compile version locks for all runtime
dependencies in a way that is robust to human error. By using the
wildcard extra the risk of forgetting to list any extra is removed.

Since the expanded extras are needed when we look for the wildcard it
is moved to before the loop. This is OK because it does not depend on
the loop and nothing in the loop depends on its previous value.
  • Loading branch information
apljungquist committed Sep 18, 2022
1 parent 8d4a30f commit 76ac553
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 2 deletions.
12 changes: 10 additions & 2 deletions piptools/scripts/compile.py
Expand Up @@ -401,6 +401,8 @@ def cli(
# Parsing/collecting initial requirements
###

extras = tuple(itertools.chain.from_iterable(ex.split(",") for ex in extras))

constraints: List[InstallRequirement] = []
setup_file_found = False
for src_file in src_files:
Expand Down Expand Up @@ -442,6 +444,14 @@ def cli(
for req in metadata.get_all("Requires-Dist") or []
]
)
# Since "*" is not a valid extra there is no risk confusing an actual extra
# for the wildcard.
# https://peps.python.org/pep-0508/#grammar
if "*" in extras:
if len(extras) != 1:
msg = "--extra=* only makes sense if it is the only --extra"
raise click.BadParameter(msg)
extras = tuple(metadata.get_all("Provides-Extra"))
else:
constraints.extend(
parse_requirements(
Expand All @@ -452,8 +462,6 @@ def cli(
)
)

extras = tuple(itertools.chain.from_iterable(ex.split(",") for ex in extras))

if extras and not setup_file_found:
msg = "--extra has effect only with setup.py and PEP-517 input formats"
raise click.BadParameter(msg)
Expand Down
38 changes: 38 additions & 0 deletions tests/test_cli_compile.py
Expand Up @@ -2190,6 +2190,44 @@ 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_wildcard_extras(fake_dists, runner, make_module, fname, content):
"""
Test passing wildcard `--extra` includes all applicable extras.
"""
meta_path = make_module(fname=fname, content=content)
out = runner.invoke(
cli,
[
"-n",
"--extra",
"*",
"--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
)


def test_extras_fail_with_requirements_in(runner, tmpdir):
"""
Test that passing `--extra` with `requirements.in` input file fails.
Expand Down

0 comments on commit 76ac553

Please sign in to comment.