Commit b7da0867 by Sébastien Eustace

Fix dependency resolution for children of conditional dependencies

parent c2516250
......@@ -48,9 +48,9 @@ class DebugResolveCommand(Command):
for ex in extras:
dep.extras.append(ex)
package.python_versions = self.option("python") or (
self.poetry.package.python_versions
)
package.python_versions = self.option("python") or (
self.poetry.package.python_versions
)
pool = self.poetry.pool
......
......@@ -14,7 +14,7 @@ class Term(object):
See https://github.com/dart-lang/pub/tree/master/doc/solver.md#term.
"""
def __init__(self, dependency, is_positive): # type: Dependency # type: bool
def __init__(self, dependency, is_positive): # type: (Dependency, bool) -> None
self._dependency = dependency
self._positive = is_positive
......@@ -158,7 +158,10 @@ class Term(object):
if constraint.is_empty():
return
return Term(Dependency(self.dependency.name, constraint), is_positive)
dep = Dependency(self.dependency.name, constraint)
dep.python_versions = str(self.dependency.python_versions)
return Term(dep, is_positive)
def __str__(self):
return "{}{}".format("not " if not self.is_positive() else "", self._dependency)
......
......@@ -10,7 +10,6 @@ from poetry.version.markers import AnyMarker
from poetry.version.markers import parse_marker
from .constraints import parse_constraint as parse_generic_constraint
from .constraints.any_constraint import AnyConstraint
from .constraints.constraint import Constraint
from .constraints.multi_constraint import MultiConstraint
from .constraints.union_constraint import UnionConstraint
......@@ -49,6 +48,8 @@ class Dependency(object):
self._python_versions = "*"
self._python_constraint = parse_constraint("*")
self._transitive_python_versions = None
self._transitive_python_constraint = None
self._extras = []
self._in_extras = []
......@@ -96,10 +97,29 @@ class Dependency(object):
)
@property
def transitive_python_versions(self):
if self._transitive_python_versions is None:
return self._python_versions
return self._transitive_python_versions
@transitive_python_versions.setter
def transitive_python_versions(self, value):
self._transitive_python_versions = value
self._transitive_python_constraint = parse_constraint(value)
@property
def python_constraint(self):
return self._python_constraint
@property
def transitive_python_constraint(self):
if self._transitive_python_constraint is None:
return self._python_constraint
return self._transitive_python_constraint
@property
def extras(self): # type: () -> list
return self._extras
......
......@@ -317,7 +317,7 @@ class Provider:
def incompatibilities_for(
self, package
): # type: (Package) -> List[Incompatibility]
): # type: (DependencyPackage) -> List[Incompatibility]
"""
Returns incompatibilities that encapsulate a given package's dependencies,
or that it can't be safely selected.
......@@ -335,14 +335,19 @@ class Provider:
if not package.python_constraint.allows_all(
self._package.python_constraint
):
intersection = package.python_constraint.intersect(
package.dependency.transitive_python_constraint
)
difference = package.dependency.transitive_python_constraint.difference(
intersection
)
if (
package.dependency.python_constraint.is_any()
or not self._package.python_constraint.allows_all(
package.dependency.python_constraint
)
or not package.python_constraint.allows_all(
package.dependency.transitive_python_constraint.is_any()
or self._package.python_constraint.intersect(
package.dependency.python_constraint
)
).is_empty()
or intersection.is_empty()
or not difference.is_empty()
):
return [
Incompatibility(
......@@ -368,7 +373,9 @@ class Provider:
for dep in dependencies
]
def complete_package(self, package): # type: (str, Version) -> Package
def complete_package(
self, package
): # type: (DependencyPackage) -> DependencyPackage
if package.is_root():
return package
......@@ -518,6 +525,14 @@ class Provider:
)
raise CompatibilityError(*python_constraints)
if not package.dependency.python_constraint.is_any():
for dep in dependencies:
dep.transitive_python_versions = str(
dep.python_constraint.intersect(
package.dependency.python_constraint
)
)
package.requires = dependencies
return package
......
......@@ -432,9 +432,6 @@ class MultiMarker(BaseMarker):
if other.is_empty():
return other
if other in self._markers:
return other
new_markers = self._markers + [other]
return MultiMarker.of(*new_markers)
......
......@@ -962,6 +962,39 @@ def test_solver_does_not_trigger_conflict_for_python_constraint_if_python_requir
)
def test_solver_does_not_trigger_conflict_for_python_constraint_if_python_requirement_is_compatible_multiple(
solver, repo, package
):
package.python_versions = "~2.7 || ^3.4"
package.add_dependency("A", {"version": "^1.0", "python": "^3.6"})
package.add_dependency("B", {"version": "^1.0", "python": "^3.5.3"})
package_a = get_package("A", "1.0.0")
package_a.python_versions = ">=3.6"
package_a.add_dependency("B", "^1.0")
package_b = get_package("B", "1.0.0")
package_b.python_versions = ">=3.5.3"
repo.add_package(package_a)
repo.add_package(package_b)
ops = solver.solve()
check_solver_result(
ops,
[
{"job": "install", "package": package_b},
{"job": "install", "package": package_a},
],
)
assert str(ops[0].package.marker) == (
'python_version >= "3.6" and python_version < "4.0" '
'or python_version >= "3.5.3" and python_version < "4.0.0"'
)
def test_solver_triggers_conflict_for_dependency_python_not_fully_compatible_with_package_python(
solver, repo, package
):
......
......@@ -70,6 +70,15 @@ def test_single_marker_intersect_with_multi():
)
def test_single_marker_intersect_with_multi_with_duplicate():
m = parse_marker('python_version < "4.0"')
intersection = m.intersect(
parse_marker('sys_platform == "darwin" and python_version < "4.0"')
)
assert str(intersection) == 'sys_platform == "darwin" and python_version < "4.0"'
def test_single_marker_intersect_with_multi_compacts_constraint():
m = parse_marker('python_version < "3.6"')
......
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