From e9eb2df09036a26d99b9c6c8a8ae7a3ed7f4cdfd Mon Sep 17 00:00:00 2001 From: Andy Kluger Date: Fri, 17 Jan 2020 00:17:54 -0500 Subject: [PATCH] compile: separately handle existing pins marked to-upgrade (-P), and exclude -P args not already pinned or primarily required; fixes #759 --- piptools/scripts/compile.py | 23 +++++++++++++++-------- tests/test_cli_compile.py | 16 ++++++++++++++++ 2 files changed, 31 insertions(+), 8 deletions(-) diff --git a/piptools/scripts/compile.py b/piptools/scripts/compile.py index 3e2272a1d..ced20338f 100755 --- a/piptools/scripts/compile.py +++ b/piptools/scripts/compile.py @@ -282,6 +282,8 @@ def cli( key_from_req(install_req.req): install_req for install_req in upgrade_reqs_gen } + existing_pins_to_upgrade = {} + # Proxy with a LocalRequirementsRepository if --upgrade is not specified # (= default invocation) if not upgrade and os.path.exists(output_file.name): @@ -293,13 +295,15 @@ def cli( ) # Exclude packages from --upgrade-package/-P from the existing - # constraints - existing_pins = { - key_from_req(ireq.req): ireq - for ireq in ireqs - if is_pinned_requirement(ireq) - and key_from_req(ireq.req) not in upgrade_install_reqs - } + # constraints, and separately gather pins to be upgraded + existing_pins = {} + for ireq in filter(is_pinned_requirement, ireqs): + key = key_from_req(ireq.req) + ( + existing_pins_to_upgrade + if key in upgrade_install_reqs + else existing_pins + )[key] = ireq repository = LocalRequirementsRepository(existing_pins, repository) ### @@ -345,7 +349,10 @@ def cli( key_from_ireq(ireq) for ireq in constraints if not ireq.constraint } - constraints.extend(upgrade_install_reqs.values()) + allowed_upgrades = primary_packages | set(existing_pins_to_upgrade) + constraints.extend( + ireq for key, ireq in upgrade_install_reqs.items() if key in allowed_upgrades + ) # Filter out pip environment markers which do not match (PEP496) constraints = [ diff --git a/tests/test_cli_compile.py b/tests/test_cli_compile.py index b876bdfa8..dbaa3f771 100644 --- a/tests/test_cli_compile.py +++ b/tests/test_cli_compile.py @@ -370,6 +370,22 @@ def test_upgrade_packages_option(pip_conf, runner): assert "small-fake-b==0.3" in out.stderr +def test_upgrade_packages_option_irrelevant(pip_conf, runner): + """ + piptools ignores --upgrade-package/-P items not already constrained. + """ + with open("requirements.in", "w") as req_in: + req_in.write("small-fake-a") + with open("requirements.txt", "w") as req_in: + req_in.write("small-fake-a==0.1") + + out = runner.invoke(cli, ["-P", "small-fake-b"]) + + assert out.exit_code == 0 + assert "small-fake-a==0.1" in out.stderr + assert "small-fake-b==0.3" not in out.stderr + + def test_upgrade_packages_option_no_existing_file(pip_conf, runner): """ piptools respects --upgrade-package/-P inline list when the output file