Commit f0e55b0a by Randy Döring

solver: support for yanked releases according to PEP 592

parent c1d77a1a
......@@ -290,6 +290,7 @@ class Provider:
packages.sort(
key=lambda p: (
not p.yanked,
not p.is_prerelease() and not dependency.allows_prereleases(),
p.version,
),
......
......@@ -45,8 +45,10 @@ FIXTURE_PATH = Path(__file__).parent / "fixtures"
MOCK_DEFAULT_GIT_REVISION = "9cf87a285a2d3fbb0b9fa621997b3acc3631ed24"
def get_package(name: str, version: str | Version) -> Package:
return Package(name, version)
def get_package(
name: str, version: str | Version, yanked: str | bool = False
) -> Package:
return Package(name, version, yanked=yanked)
def get_dependency(
......
......@@ -13,6 +13,7 @@ from poetry.packages import DependencyPackage
if TYPE_CHECKING:
from poetry.core.packages.project_package import ProjectPackage
from poetry.mixology import SolverResult
from poetry.repositories import Repository
from tests.mixology.version_solver.conftest import Provider
......@@ -23,8 +24,9 @@ def add_to_repo(
version: str,
deps: dict[str, str] | None = None,
python: str | None = None,
yanked: bool = False,
) -> None:
package = Package(name, version)
package = Package(name, version, yanked=yanked)
if python:
package.python_versions = python
......@@ -43,7 +45,7 @@ def check_solver_result(
tries: int | None = None,
locked: dict[str, Package] | None = None,
use_latest: list[str] | None = None,
) -> None:
) -> SolverResult | None:
if locked is not None:
locked = {
k: [DependencyPackage(l.to_dependency(), l)] for k, l in locked.items()
......@@ -59,20 +61,22 @@ def check_solver_result(
if tries is not None:
assert solver.solution.attempted_solutions == tries
return
return None
raise
except AssertionError as e:
if error:
assert str(e) == error
return
return None
raise
packages = {}
for package in solution.packages:
packages[package.name] = str(package.version)
assert result == packages
assert packages == result
if tries is not None:
assert solution.attempted_solutions == tries
return solution
......@@ -2,6 +2,8 @@ from __future__ import annotations
from typing import TYPE_CHECKING
import pytest
from poetry.factory import Factory
from tests.mixology.helpers import add_to_repo
from tests.mixology.helpers import check_solver_result
......@@ -87,3 +89,44 @@ def test_circular_dependency(
add_to_repo(repo, "bar", "1.0.0", deps={"foo": "1.0.0"})
check_solver_result(root, provider, {"foo": "1.0.0", "bar": "1.0.0"})
@pytest.mark.parametrize(
"constraint, versions, yanked_versions, expected",
[
(">=1", ["1", "2"], [], "2"),
(">=1", ["1", "2"], ["2"], "1"),
(">=1", ["1", "2", "3"], ["2"], "3"),
(">=1", ["1", "2", "3"], ["2", "3"], "1"),
(">1", ["1", "2"], ["2"], "error"),
(">1", ["2"], ["2"], "error"),
(">=2", ["2"], ["2"], "error"),
("==2", ["2"], ["2"], "2"),
("==2", ["2", "2+local"], [], "2+local"),
("==2", ["2", "2+local"], ["2+local"], "2"),
],
)
def test_yanked_release(
root: ProjectPackage,
provider: Provider,
repo: Repository,
constraint: str,
versions: list[str],
yanked_versions: list[str],
expected: str,
) -> None:
root.add_dependency(Factory.create_dependency("foo", constraint))
for version in versions:
add_to_repo(repo, "foo", version, yanked=version in yanked_versions)
if expected == "error":
result = None
error = (
f"Because myapp depends on foo ({constraint}) which doesn't match any "
"versions, version solving failed."
)
else:
result = {"foo": expected}
error = None
check_solver_result(root, provider, result, error)
......@@ -169,3 +169,31 @@ def test_with_compatible_locked_dependencies_with_extras(
"baz": get_package("baz", "1.0.0"),
},
)
def test_with_yanked_package_in_lock(
root: ProjectPackage, provider: Provider, repo: Repository
):
root.add_dependency(Factory.create_dependency("foo", "*"))
add_to_repo(repo, "foo", "1")
add_to_repo(repo, "foo", "2", yanked=True)
# yanked version is kept in lock file
locked_foo = get_package("foo", "2")
assert not locked_foo.yanked
result = check_solver_result(
root,
provider,
result={"foo": "2"},
locked={"foo": locked_foo},
)
foo = result.packages[0]
assert foo.yanked
# without considering the lock file, the other version is chosen
check_solver_result(
root,
provider,
result={"foo": "1"},
)
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