From 7fec7122cf083f5955492ce65bddaee8ee2227b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Randy=20D=C3=B6ring?= <30527984+radoering@users.noreply.github.com> Date: Mon, 4 Oct 2021 15:29:53 +0200 Subject: [PATCH] Merge any marker constraints into constraints with specific markers --- poetry/puzzle/provider.py | 21 +++++++++++++++--- tests/puzzle/test_solver.py | 43 +++++++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 3 deletions(-) diff --git a/poetry/puzzle/provider.py b/poetry/puzzle/provider.py index 76bf2a56f39..f273a87c4df 100644 --- a/poetry/puzzle/provider.py +++ b/poetry/puzzle/provider.py @@ -659,6 +659,14 @@ def complete_package(self, package: DependencyPackage) -> DependencyPackage: # - ipython (1.2.4) ; implementation_name == "pypy" # # the marker for `ipython` will become `implementation_name != "pypy"`. + # + # Further, we have to merge the constraints of the requirements + # without markers into the constraints of the requirements with markers. + # for instance, if we have the following dependencies: + # - foo (>= 1.2) + # - foo (!= 1.2.1) ; python == 3.10 + # + # the constraint for the second entry will become (!= 1.2.1, >= 1.2) any_markers_dependencies = [d for d in _deps if d.marker.is_any()] other_markers_dependencies = [d for d in _deps if not d.marker.is_any()] @@ -667,9 +675,16 @@ def complete_package(self, package: DependencyPackage) -> DependencyPackage: for other_dep in other_markers_dependencies[1:]: marker = marker.union(other_dep.marker) - for i, d in enumerate(_deps): - if d.marker.is_any(): - _deps[i].marker = marker.invert() + inverted_marker = marker.invert() + for dep_any in any_markers_dependencies: + dep_any.marker = inverted_marker + for dep_other in other_markers_dependencies: + dep_other.set_constraint( + dep_other.constraint.intersect(dep_any.constraint) + ) + # TODO: Setting _pretty_constraint can be removed once the following issue has been fixed + # https://github.com/python-poetry/poetry/issues/4589 + dep_other._pretty_constraint = str(dep_other.constraint) overrides = [] for _dep in _deps: diff --git a/tests/puzzle/test_solver.py b/tests/puzzle/test_solver.py index 4c991225ebe..612a37e43a4 100644 --- a/tests/puzzle/test_solver.py +++ b/tests/puzzle/test_solver.py @@ -1142,6 +1142,49 @@ def test_solver_duplicate_dependencies_different_constraints_same_requirements( assert str(e.value) == expected +def test_solver_duplicate_dependencies_different_constraints_merge_no_markers( + solver, repo, package +): + package.add_dependency(Factory.create_dependency("A", "*")) + package.add_dependency(Factory.create_dependency("B", "1.0")) + + package_a10 = get_package("A", "1.0") + package_a10.add_dependency(Factory.create_dependency("C", {"version": "^1.0"})) + + package_a20 = get_package("A", "2.0") + package_a20.add_dependency( + Factory.create_dependency("C", {"version": "^2.0"}) # incompatible with B + ) + package_a20.add_dependency( + Factory.create_dependency("C", {"version": "!=2.1", "python": "3.10"}) + ) + + package_b = get_package("B", "1.0") + package_b.add_dependency(Factory.create_dependency("C", {"version": "<2.0"})) + + package_c10 = get_package("C", "1.0") + package_c20 = get_package("C", "2.0") + package_c21 = get_package("C", "2.1") + + repo.add_package(package_a10) + repo.add_package(package_a20) + repo.add_package(package_b) + repo.add_package(package_c10) + repo.add_package(package_c20) + repo.add_package(package_c21) + + transaction = solver.solve() + + check_solver_result( + transaction, + [ + {"job": "install", "package": package_c10}, + {"job": "install", "package": package_a10}, # only a10, not a20 + {"job": "install", "package": package_b}, + ], + ) + + def test_solver_duplicate_dependencies_sub_dependencies(solver, repo, package): package.add_dependency(Factory.create_dependency("A", "*"))