diff --git a/piptools/resolver.py b/piptools/resolver.py index 750e6c993..cd59da4b0 100644 --- a/piptools/resolver.py +++ b/piptools/resolver.py @@ -520,6 +520,8 @@ def resolve(self, max_rounds: int = 10) -> set[InstallRequirement]: ), get_build_tracker() as build_tracker, global_tempdir_manager(), indent_log(): # Mark direct/primary/user_supplied packages for ireq in self.constraints: + if ireq.constraint: + ireq.extras = set() # pip does not support extras in constraints ireq.user_supplied = True # Pass compiled requirements from `requirements.txt` @@ -535,7 +537,7 @@ def resolve(self, max_rounds: int = 10) -> set[InstallRequirement]: if not primary_ireq.specifier.contains(version, prereleases): continue - ireq.extras = set() # pip does not support extras in constraints + ireq.extras = set() ireq.constraint = True ireq.user_supplied = False compatible_existing_constraints[key_from_ireq(ireq)] = ireq diff --git a/tests/test_cli_compile.py b/tests/test_cli_compile.py index 428894e29..693cff130 100644 --- a/tests/test_cli_compile.py +++ b/tests/test_cli_compile.py @@ -939,6 +939,56 @@ def test_upgrade_packages_version_option_and_upgrade_no_existing_file(pip_conf, assert "small-fake-b==0.1" in out.stderr +def test_upgrade_package_with_extra(runner, make_package, make_sdist, tmpdir): + """ + piptools ignores extras on --upgrade-package/-P items if already constrained. + """ + test_package_1 = make_package( + "test_package_1", version="0.1", extras_require={"more": "test_package_2"} + ) + test_package_2 = make_package( + "test_package_2", + version="0.1", + ) + dists_dir = tmpdir / "dists" + for pkg in (test_package_1, test_package_2): + make_sdist(pkg, dists_dir) + + # Constrain our requirement with an extra + with open("requirements.in", "w") as req_in: + req_in.write("test-package-1[more]") + + # Run update on test-package-1[more] -- this should be equivalent + # to running an update on test-package-1 + out = runner.invoke( + cli, + [ + "--output-file", + "-", + "--quiet", + "--find-links", + str(dists_dir), + "--no-annotate", + "--no-header", + "--no-emit-options", + "--no-build-isolation", + "--upgrade-package", + "test-package-1[more]", + ], + ) + + assert out.exit_code == 0, out + assert ( + dedent( + """\ + test-package-1[more]==0.1 + test-package-2==0.1 + """ + ) + == out.stdout + ) + + def test_quiet_option(pip_conf, runner): with open("requirements.in", "w") as req_in: req_in.write("small-fake-a")