Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix an infinite loop in the solver #6178

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 3 additions & 5 deletions src/poetry/mixology/version_solver.py
Original file line number Diff line number Diff line change
Expand Up @@ -513,11 +513,9 @@ def _get_locked(
locked = self._locked.get(dependency.name, [])
for dependency_package in locked:
package = dependency_package.package
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())
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I stumbled over such a construct in #6165 (and removed it, too). I assume this was a workaround to deal with a previous shortcoming somewhere else that has been fixed in the meantime.

):
if (
allow_similar or dependency.is_same_package_as(package)
) and dependency.constraint.allows(package.version):
return DependencyPackage(dependency, package)
return None

Expand Down
13 changes: 6 additions & 7 deletions src/poetry/puzzle/provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@
from poetry.core.packages.directory_dependency import DirectoryDependency
from poetry.core.packages.file_dependency import FileDependency
from poetry.core.packages.package import Package
from poetry.core.packages.specification import PackageSpecification
from poetry.core.packages.url_dependency import URLDependency
from poetry.core.packages.vcs_dependency import VCSDependency
from poetry.core.semver.version_constraint import VersionConstraint
Expand Down Expand Up @@ -193,11 +192,11 @@ def validate_package_for_dependency(

def search_for_installed_packages(
self,
specification: PackageSpecification,
dependency: Dependency,
) -> list[Package]:
"""
Search for installed packages, when available, that provides the given
specification.
Search for installed packages, when available, that satisfy the given
dependency.

This is useful when dealing with packages that are under development, not
published on package sources and/or only available via system installations.
Expand All @@ -207,17 +206,17 @@ def search_for_installed_packages(

logger.debug(
"Falling back to installed packages to discover metadata for <c2>%s</>",
specification.complete_name,
dependency.complete_name,
)
packages = [
package
for package in self._installed_packages
if package.provides(specification)
if package.satisfies(dependency, ignore_source_type=True)
]
logger.debug(
"Found <c2>%d</> compatible packages for <c2>%s</>",
len(packages),
specification.complete_name,
dependency.complete_name,
)
return packages

Expand Down
33 changes: 33 additions & 0 deletions tests/puzzle/test_solver.py
Original file line number Diff line number Diff line change
Expand Up @@ -3648,3 +3648,36 @@ def test_solver_incompatible_dependency_with_and_without_extras(
{"job": "install", "package": foo},
],
)


def test_update_with_prerelease_and_no_solution(
solver: Solver,
repo: Repository,
installed: InstalledRepository,
package: ProjectPackage,
locked: Repository,
):
# Locked and installed: cleo which depends on an old version of crashtest.
cleo = get_package("cleo", "1.0.0a5")
crashtest = get_package("crashtest", "0.3.0")
cleo.add_dependency(Factory.create_dependency("crashtest", {"version": "<0.4.0"}))
locked.add_package(cleo)
locked.add_package(crashtest)

installed.add_package(cleo)
installed.add_package(crashtest)

# Try to upgrade to a new version of crashtest, this will be disallowed by the
# dependency from cleo.
package.add_dependency(Factory.create_dependency("cleo", "^1.0.0a5"))
package.add_dependency(Factory.create_dependency("crashtest", "^0.4.0"))

newer_crashtest = get_package("crashtest", "0.4.0")
even_newer_crashtest = get_package("crashtest", "0.4.1")
repo.add_package(cleo)
repo.add_package(crashtest)
repo.add_package(newer_crashtest)
repo.add_package(even_newer_crashtest)

with pytest.raises(SolverProblemError):
solver.solve()