From a92a6af3245cdfac5512210c045735821513055f Mon Sep 17 00:00:00 2001 From: maxfenv <57399972+maxfenv@users.noreply.github.com> Date: Thu, 10 Nov 2022 18:11:47 +0000 Subject: [PATCH] Prompt user to use the backtracking resolver on errors (#1719) --- piptools/scripts/compile.py | 12 +++++++++++- tests/test_cli_compile.py | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/piptools/scripts/compile.py b/piptools/scripts/compile.py index f2d139d42..c0d9fbf5b 100755 --- a/piptools/scripts/compile.py +++ b/piptools/scripts/compile.py @@ -18,7 +18,7 @@ from .._compat import IS_CLICK_VER_8_PLUS, parse_requirements from ..cache import DependencyCache -from ..exceptions import PipToolsError +from ..exceptions import NoCandidateFound, PipToolsError from ..locations import CACHE_DIR from ..logging import log from ..repositories import LocalRequirementsRepository, PyPIRepository @@ -547,6 +547,16 @@ def cli( ) results = resolver.resolve(max_rounds=max_rounds) hashes = resolver.resolve_hashes(results) if generate_hashes else None + except NoCandidateFound as e: + if resolver_cls == LegacyResolver: # pragma: no branch + log.error( + "Using legacy resolver. " + "Consider using backtracking resolver with " + "`--resolver=backtracking`." + ) + + log.error(str(e)) + sys.exit(2) except PipToolsError as e: log.error(str(e)) sys.exit(2) diff --git a/tests/test_cli_compile.py b/tests/test_cli_compile.py index db0e55ea3..a53f1b712 100644 --- a/tests/test_cli_compile.py +++ b/tests/test_cli_compile.py @@ -2489,3 +2489,36 @@ def test_preserve_via_requirements_constrained_dependencies_when_run_twice( for output in (first_out, second_out): assert output.exit_code == 0, output assert output.stderr == expected_output + + +def test_failure_of_legacy_resolver_prompts_for_backtracking( + pip_conf, runner, tmpdir, make_package, make_wheel, current_resolver +): + """Test that pip-compile prompts to use the backtracking resolver""" + pkgs = [ + make_package("a", version="0.1", install_requires=["b==0.1"]), + make_package("a", version="0.2", install_requires=["b==0.2"]), + make_package("b", version="0.1"), + make_package("b", version="0.2"), + make_package("c", version="1", install_requires=["b==0.1", "a"]), + ] + + dists_dir = tmpdir / "dists" + for pkg in pkgs: + make_wheel(pkg, dists_dir) + + with open("requirements.in", "w") as req_in: + req_in.writelines(["c"]) + + out = runner.invoke( + cli, + ["--resolver", current_resolver, "--find-links", str(dists_dir)], + ) + + if current_resolver == "legacy": + assert out.exit_code == 2, out + assert "Consider using backtracking resolver with" in out.stderr + elif current_resolver == "backtracking": + assert out.exit_code == 0, out + else: # pragma: no cover + raise AssertionError("unreachable")