Commit b5ab46ed by Randy Döring Committed by Bjorn Neergaard

provider: raise error if there are incompatible constraints in the requirements of a package

parent 28ddcd8b
......@@ -59,6 +59,18 @@ if TYPE_CHECKING:
logger = logging.getLogger(__name__)
class IncompatibleConstraintsError(Exception):
"""
Exception when there are duplicate dependencies with incompatible constraints.
"""
def __init__(self, package: Package, *dependencies: Dependency) -> None:
constraints = "\n".join(dep.to_pep_508() for dep in dependencies)
super().__init__(
f"Incompatible constraints in requirements of {package}:\n{constraints}"
)
class Indicator(ProgressIndicator):
CONTEXT: str | None = None
......@@ -740,7 +752,7 @@ class Provider:
f"<warning>Different requirements found for {warnings}.</warning>"
)
deps = self._handle_any_marker_dependencies(deps)
deps = self._handle_any_marker_dependencies(package, deps)
overrides = []
overrides_marker_intersection: BaseMarker = AnyMarker()
......@@ -975,7 +987,7 @@ class Provider:
return deps
def _handle_any_marker_dependencies(
self, dependencies: list[Dependency]
self, package: Package, dependencies: list[Dependency]
) -> list[Dependency]:
"""
We need to check if one of the duplicate dependencies
......@@ -999,11 +1011,16 @@ class Provider:
any_markers_dependencies = [d for d in dependencies if d.marker.is_any()]
other_markers_dependencies = [d for d in dependencies if not d.marker.is_any()]
for dep_any in any_markers_dependencies:
if any_markers_dependencies:
for dep_other in other_markers_dependencies:
dep_other.constraint = dep_other.constraint.intersect(
dep_any.constraint
)
new_constraint = dep_other.constraint
for dep_any in any_markers_dependencies:
new_constraint = new_constraint.intersect(dep_any.constraint)
if new_constraint.is_empty():
raise IncompatibleConstraintsError(
package, dep_other, *any_markers_dependencies
)
dep_other.constraint = new_constraint
marker = other_markers_dependencies[0].marker
for other_dep in other_markers_dependencies[1:]:
......
from __future__ import annotations
import re
from pathlib import Path
from typing import TYPE_CHECKING
from typing import Any
......@@ -19,6 +21,7 @@ from poetry.factory import Factory
from poetry.packages import DependencyPackage
from poetry.puzzle import Solver
from poetry.puzzle.exceptions import SolverProblemError
from poetry.puzzle.provider import IncompatibleConstraintsError
from poetry.repositories.repository import Repository
from poetry.repositories.repository_pool import RepositoryPool
from poetry.utils.env import MockEnv
......@@ -1480,6 +1483,27 @@ def test_solver_duplicate_dependencies_different_constraints_merge_no_markers(
)
def test_solver_duplicate_dependencies_different_constraints_conflict(
solver: Solver, repo: Repository, package: ProjectPackage
) -> None:
package.add_dependency(Factory.create_dependency("A", ">=1.1"))
package.add_dependency(
Factory.create_dependency("A", {"version": "<1.1", "python": "3.10"})
)
repo.add_package(get_package("A", "1.0"))
repo.add_package(get_package("A", "1.1"))
repo.add_package(get_package("A", "1.2"))
expectation = (
"Incompatible constraints in requirements of root (1.0):\n"
'A (<1.1) ; python_version == "3.10"\n'
"A (>=1.1)"
)
with pytest.raises(IncompatibleConstraintsError, match=re.escape(expectation)):
solver.solve()
def test_solver_duplicate_dependencies_different_constraints_discard_no_markers1(
solver: Solver, repo: Repository, package: ProjectPackage
) -> None:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment