Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow options in config from both pip-compile and pip-sync #1933

Merged
merged 6 commits into from
Jul 26, 2023
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 28 additions & 17 deletions piptools/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -591,33 +591,44 @@ def _validate_config(
:raises click.NoSuchOption: if config contains unknown keys.
:raises click.BadOptionUsage: if config contains invalid values.
"""
cli_params = {
param.name: param
for param in click_context.command.params
if param.name is not None
from piptools.scripts.compile import cli as compile_cli
from piptools.scripts.sync import cli as sync_cli
chrysle marked this conversation as resolved.
Show resolved Hide resolved

compile_cli_params = {
param.name: param for param in compile_cli.params if param.name is not None
}

sync_cli_params = {
param.name: param for param in sync_cli.params if param.name is not None
}

all_keys = set(compile_cli_params) | set(sync_cli_params)

for key, value in config.items():
# Validate unknown keys
if key not in cli_params:
possibilities = difflib.get_close_matches(key, cli_params.keys())
# Validate unknown keys in both compile and sync
if key not in all_keys:
possibilities = difflib.get_close_matches(key, all_keys)
raise click.NoSuchOption(
option_name=key,
message=f"No such config key {key!r}.",
possibilities=possibilities,
ctx=click_context,
)

# Validate invalid values
param = cli_params[key]
try:
param.type.convert(value=value, param=param, ctx=click_context)
except Exception as e:
raise click.BadOptionUsage(
option_name=key,
message=f"Invalid value for config key {key!r}: {value!r}.",
ctx=click_context,
) from e
# Validate values for both compile and sync
for cli_params in (compile_cli_params, sync_cli_params):
param = cli_params.get(key)
if param is None:
continue
chrysle marked this conversation as resolved.
Show resolved Hide resolved

try:
param.type.convert(value=value, param=param, ctx=click_context)
chrysle marked this conversation as resolved.
Show resolved Hide resolved
except Exception as e:
raise click.BadOptionUsage(
option_name=key,
message=f"Invalid value for config key {key!r}: {value!r}.",
ctx=click_context,
) from e


def select_config_file(src_files: tuple[str, ...]) -> Path | None:
Expand Down
14 changes: 14 additions & 0 deletions tests/test_cli_compile.py
Original file line number Diff line number Diff line change
Expand Up @@ -3019,6 +3019,20 @@ def test_raise_error_on_invalid_config_option(
assert "Invalid value for config key 'dry_run': ['invalid', 'value']" in out.stderr


def test_allow_in_config_pip_sync_option(pip_conf, runner, tmp_path, make_config_file):
config_file = make_config_file("--ask", True) # pip-sync's option

req_in = tmp_path / "requirements.in"
req_in.touch()

out = runner.invoke(
cli, [req_in.as_posix(), "--verbose", "--config", config_file.as_posix()]
)

assert out.exit_code == 0
assert "Using pip-tools configuration defaults found" in out.stderr


def test_cli_boolean_flag_config_option_has_valid_context(
pip_conf, runner, tmp_path, make_config_file
):
Expand Down
13 changes: 13 additions & 0 deletions tests/test_cli_sync.py
Original file line number Diff line number Diff line change
Expand Up @@ -424,3 +424,16 @@ def test_raise_error_on_invalid_config_option(run, runner, tmp_path, make_config

assert out.exit_code == 2
assert "Invalid value for config key 'dry_run': ['invalid', 'value']" in out.stderr


@mock.patch("piptools.sync.run")
def test_allow_in_config_pip_compile_option(run, runner, tmp_path, make_config_file):
config_file = make_config_file("generate-hashes", True) # pip-compile's option

with open(sync.DEFAULT_REQUIREMENTS_FILE, "w") as reqs_txt:
reqs_txt.write("six==1.10.0")

out = runner.invoke(cli, ["--verbose", "--config", config_file.as_posix()])

assert out.exit_code == 0
assert "Using pip-tools configuration defaults found" in out.stderr