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: ...@@ -59,6 +59,18 @@ if TYPE_CHECKING:
logger = logging.getLogger(__name__) 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): class Indicator(ProgressIndicator):
CONTEXT: str | None = None CONTEXT: str | None = None
...@@ -740,7 +752,7 @@ class Provider: ...@@ -740,7 +752,7 @@ class Provider:
f"<warning>Different requirements found for {warnings}.</warning>" 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 = []
overrides_marker_intersection: BaseMarker = AnyMarker() overrides_marker_intersection: BaseMarker = AnyMarker()
...@@ -975,7 +987,7 @@ class Provider: ...@@ -975,7 +987,7 @@ class Provider:
return deps return deps
def _handle_any_marker_dependencies( def _handle_any_marker_dependencies(
self, dependencies: list[Dependency] self, package: Package, dependencies: list[Dependency]
) -> list[Dependency]: ) -> list[Dependency]:
""" """
We need to check if one of the duplicate dependencies We need to check if one of the duplicate dependencies
...@@ -999,11 +1011,16 @@ class Provider: ...@@ -999,11 +1011,16 @@ class Provider:
any_markers_dependencies = [d for d in dependencies if d.marker.is_any()] 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()] 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: for dep_other in other_markers_dependencies:
dep_other.constraint = dep_other.constraint.intersect( new_constraint = dep_other.constraint
dep_any.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 marker = other_markers_dependencies[0].marker
for other_dep in other_markers_dependencies[1:]: for other_dep in other_markers_dependencies[1:]:
......
from __future__ import annotations from __future__ import annotations
import re
from pathlib import Path from pathlib import Path
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from typing import Any from typing import Any
...@@ -19,6 +21,7 @@ from poetry.factory import Factory ...@@ -19,6 +21,7 @@ from poetry.factory import Factory
from poetry.packages import DependencyPackage from poetry.packages import DependencyPackage
from poetry.puzzle import Solver from poetry.puzzle import Solver
from poetry.puzzle.exceptions import SolverProblemError from poetry.puzzle.exceptions import SolverProblemError
from poetry.puzzle.provider import IncompatibleConstraintsError
from poetry.repositories.repository import Repository from poetry.repositories.repository import Repository
from poetry.repositories.repository_pool import RepositoryPool from poetry.repositories.repository_pool import RepositoryPool
from poetry.utils.env import MockEnv from poetry.utils.env import MockEnv
...@@ -1480,6 +1483,27 @@ def test_solver_duplicate_dependencies_different_constraints_merge_no_markers( ...@@ -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( def test_solver_duplicate_dependencies_different_constraints_discard_no_markers1(
solver: Solver, repo: Repository, package: ProjectPackage solver: Solver, repo: Repository, package: ProjectPackage
) -> None: ) -> 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