Skip to content

Commit

Permalink
provider: allow fallback to installed packages
Browse files Browse the repository at this point in the history
  • Loading branch information
abn committed May 27, 2022
1 parent 62c2897 commit 7ed4c68
Show file tree
Hide file tree
Showing 3 changed files with 96 additions and 11 deletions.
66 changes: 57 additions & 9 deletions src/poetry/puzzle/provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
from poetry.packages import DependencyPackage
from poetry.packages.package_collection import PackageCollection
from poetry.puzzle.exceptions import OverrideNeeded
from poetry.repositories.exceptions import PackageNotFound
from poetry.utils.helpers import download_file
from poetry.vcs.git import Git

Expand All @@ -46,10 +47,12 @@

from poetry.core.packages.dependency import Dependency
from poetry.core.packages.package import Package
from poetry.core.packages.specification import PackageSpecification
from poetry.core.semver.version_constraint import VersionConstraint
from poetry.core.version.markers import BaseMarker

from poetry.repositories import Pool
from poetry.repositories import Repository
from poetry.utils.env import Env


Expand Down Expand Up @@ -124,6 +127,7 @@ def __init__(
pool: Pool,
io: Any,
env: Env | None = None,
installed: Repository | None = None,
) -> None:
self._package = package
self._pool = pool
Expand All @@ -136,6 +140,7 @@ def __init__(
self._deferred_cache: dict[Dependency, Package] = {}
self._load_deferred = True
self._source_root: Path | None = None
self._installed = installed

@property
def pool(self) -> Pool:
Expand Down Expand Up @@ -185,6 +190,36 @@ def validate_package_for_dependency(
f" package's name: {package.name}"
)

def search_for_installed_packages(
self,
specification: PackageSpecification,
) -> list[Package]:
"""
Search for installed packages, when available, that provides the given
specification.
This is useful when dealing with packages that are under development, not
published on package sources and/or only available via system installations.
"""
if not self._installed:
return []

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

def search_for(
self,
dependency: (
Expand Down Expand Up @@ -227,6 +262,9 @@ def search_for(
reverse=True,
)

if not packages:
packages = self.search_for_installed_packages(dependency)

return PackageCollection(dependency, packages)

def search_for_vcs(self, dependency: VCSDependency) -> list[Package]:
Expand Down Expand Up @@ -478,15 +516,25 @@ def complete_package(self, package: DependencyPackage) -> DependencyPackage:
"url",
"git",
}:
package = DependencyPackage(
package.dependency,
self._pool.package(
package.name,
package.version.text,
extras=list(package.dependency.extras),
repository=package.dependency.source_name,
),
)
try:
package = DependencyPackage(
package.dependency,
self._pool.package(
package.name,
package.version.text,
extras=list(package.dependency.extras),
repository=package.dependency.source_name,
),
)
except PackageNotFound as e:
for pkg in self.search_for_installed_packages(package.dependency):
package = DependencyPackage(
package.dependency,
pkg,
)
break
else:
raise e from e
requires = package.requires
else:
requires = package.requires
Expand Down
4 changes: 3 additions & 1 deletion src/poetry/puzzle/solver.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,9 @@ def __init__(
self._io = io

if provider is None:
provider = Provider(self._package, self._pool, self._io)
provider = Provider(
self._package, self._pool, self._io, installed=installed
)

self._provider = provider
self._overrides: list[dict[DependencyPackage, dict[str, Dependency]]] = []
Expand Down
37 changes: 36 additions & 1 deletion tests/puzzle/test_solver.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,12 @@ def solver(
io: NullIO,
) -> Solver:
return Solver(
package, pool, installed, locked, io, provider=Provider(package, pool, io)
package,
pool,
installed,
locked,
io,
provider=Provider(package, pool, io, installed=installed),
)


Expand Down Expand Up @@ -174,6 +179,36 @@ def test_install_non_existing_package_fail(
solver.solve()


def test_install_unpublished_package_does_not_fail(
installed: InstalledRepository,
solver: Solver,
repo: Repository,
package: ProjectPackage,
):
package.add_dependency(Factory.create_dependency("B", "1"))

package_a = get_package("A", "1.0")
package_b = get_package("B", "1")
package_b.add_dependency(Factory.create_dependency("A", "1.0"))

repo.add_package(package_a)
installed.add_package(package_b)

transaction = solver.solve()

check_solver_result(
transaction,
[
{"job": "install", "package": package_a},
{
"job": "install",
"package": package_b,
"skipped": True, # already installed
},
],
)


def test_solver_with_deps(solver: Solver, repo: Repository, package: ProjectPackage):
package.add_dependency(Factory.create_dependency("A", "*"))

Expand Down

0 comments on commit 7ed4c68

Please sign in to comment.