Skip to content

Commit

Permalink
solver: do not drop required locked dependencies when locking with --…
Browse files Browse the repository at this point in the history
…no-update option
  • Loading branch information
radoering authored and abn committed Apr 10, 2022
1 parent d34dba7 commit b91531e
Show file tree
Hide file tree
Showing 5 changed files with 77 additions and 24 deletions.
2 changes: 1 addition & 1 deletion src/poetry/mixology/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
def resolve_version(
root: ProjectPackage,
provider: Provider,
locked: dict[str, DependencyPackage] = None,
locked: dict[str, list[DependencyPackage]] = None,
use_latest: list[str] = None,
) -> SolverResult:
solver = VersionSolver(root, provider, locked=locked, use_latest=use_latest)
Expand Down
30 changes: 12 additions & 18 deletions src/poetry/mixology/version_solver.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,13 @@
from poetry.mixology.result import SolverResult
from poetry.mixology.set_relation import SetRelation
from poetry.mixology.term import Term
from poetry.packages import DependencyPackage


if TYPE_CHECKING:
from poetry.core.packages.package import Package
from poetry.core.packages.project_package import ProjectPackage

from poetry.packages import DependencyPackage
from poetry.puzzle.provider import Provider


Expand Down Expand Up @@ -74,7 +74,7 @@ def __init__(
self,
root: ProjectPackage,
provider: Provider,
locked: dict[str, Package] = None,
locked: dict[str, list[Package]] = None,
use_latest: list[str] = None,
):
self._root = root
Expand Down Expand Up @@ -485,25 +485,19 @@ def _add_incompatibility(self, incompatibility: Incompatibility) -> None:

def _get_locked(
self, dependency: Dependency, *, allow_similar: bool = False
) -> Package | None:
) -> DependencyPackage | None:
if dependency.name in self._use_latest:
return None

locked = self._locked.get(dependency.name)
if not locked:
return None

if not allow_similar and not dependency.is_same_package_as(locked):
return None

if not (
dependency.constraint.allows(locked.version)
or locked.is_prerelease()
and dependency.constraint.allows(locked.version.next_patch())
):
return None

return locked
locked = self._locked.get(dependency.name, [])
for package in locked:
if (allow_similar or dependency.is_same_package_as(package)) and (
dependency.constraint.allows(package.version)
or package.is_prerelease()
and dependency.constraint.allows(package.version.next_patch())
):
return DependencyPackage(dependency, package.package)
return None

def _log(self, text: str) -> None:
self._provider.debug(text, self._solution.attempted_solutions)
11 changes: 7 additions & 4 deletions src/poetry/puzzle/solver.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,10 +123,13 @@ def _solve(self, use_latest: list[str] = None) -> tuple[list[Package], list[int]
if self._provider._overrides:
self._overrides.append(self._provider._overrides)

locked = {
package.name: DependencyPackage(package.to_dependency(), package)
for package in self._locked.packages
}
locked = defaultdict(list)
for package in self._locked.packages:
locked[package.name].append(
DependencyPackage(package.to_dependency(), package)
)
for packages in locked.values():
packages.sort(key=lambda package: package.version, reverse=True)

try:
result = resolve_version(
Expand Down
4 changes: 3 additions & 1 deletion tests/mixology/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,9 @@ def check_solver_result(
use_latest: list[str] | None = None,
) -> None:
if locked is not None:
locked = {k: DependencyPackage(l.to_dependency(), l) for k, l in locked.items()}
locked = {
k: [DependencyPackage(l.to_dependency(), l)] for k, l in locked.items()
}

solver = VersionSolver(root, provider, locked=locked, use_latest=use_latest)
try:
Expand Down
54 changes: 54 additions & 0 deletions tests/puzzle/test_solver.py
Original file line number Diff line number Diff line change
Expand Up @@ -3148,3 +3148,57 @@ def test_solver_should_not_raise_errors_for_irrelevant_transitive_python_constra
{"job": "install", "package": virtualenv},
],
)


@pytest.mark.parametrize("is_locked", [False, True])
def test_solver_keeps_multiple_locked_dependencies_for_same_package(
solver: Solver,
repo: Repository,
package: Package,
locked: Repository,
is_locked: bool,
):
solver.provider.set_package_python_versions("^3.6")
package.add_dependency(
Factory.create_dependency("A", {"version": "~1.1", "python": "<3.7"})
)
package.add_dependency(
Factory.create_dependency("A", {"version": "~1.2", "python": ">=3.7"})
)

a11 = Package("A", "1.1")
a12 = Package("A", "1.2")

a11.add_dependency(Factory.create_dependency("B", {"version": ">=0.3"}))
a12.add_dependency(Factory.create_dependency("B", {"version": ">=0.3"}))

b03 = Package("B", "0.3")
b04 = Package("B", "0.4")
b04.python_versions = ">=3.6.2,<4.0.0"

repo.add_package(a11)
repo.add_package(a12)
repo.add_package(b03)
repo.add_package(b04)

if is_locked:
a11_locked = a11.clone()
a11_locked.python_versions = "<3.7"
locked.add_package(a11_locked)
a12_locked = a12.clone()
a12_locked.python_versions = ">=3.7"
locked.add_package(a12_locked)
locked.add_package(b03.clone())
locked.add_package(b04.clone())

transaction = solver.solve()

check_solver_result(
transaction,
[
{"job": "install", "package": b03},
{"job": "install", "package": b04},
{"job": "install", "package": a11},
{"job": "install", "package": a12},
],
)

0 comments on commit b91531e

Please sign in to comment.