35
35
from poetry .packages import DependencyPackage
36
36
from poetry .packages .package_collection import PackageCollection
37
37
from poetry .puzzle .exceptions import OverrideNeeded
38
+ from poetry .repositories .exceptions import PackageNotFound
38
39
from poetry .utils .helpers import download_file
39
40
from poetry .vcs .git import Git
40
41
46
47
47
48
from poetry .core .packages .dependency import Dependency
48
49
from poetry .core .packages .package import Package
50
+ from poetry .core .packages .specification import PackageSpecification
49
51
from poetry .core .semver .version_constraint import VersionConstraint
50
52
from poetry .core .version .markers import BaseMarker
51
53
52
54
from poetry .repositories import Pool
55
+ from poetry .repositories import Repository
53
56
from poetry .utils .env import Env
54
57
55
58
@@ -124,6 +127,7 @@ def __init__(
124
127
pool : Pool ,
125
128
io : Any ,
126
129
env : Env | None = None ,
130
+ installed : Repository | None = None ,
127
131
) -> None :
128
132
self ._package = package
129
133
self ._pool = pool
@@ -136,6 +140,7 @@ def __init__(
136
140
self ._deferred_cache : dict [Dependency , Package ] = {}
137
141
self ._load_deferred = True
138
142
self ._source_root : Path | None = None
143
+ self ._installed = installed
139
144
140
145
@property
141
146
def pool (self ) -> Pool :
@@ -185,6 +190,36 @@ def validate_package_for_dependency(
185
190
f" package's name: { package .name } "
186
191
)
187
192
193
+ def search_for_installed_packages (
194
+ self ,
195
+ specification : PackageSpecification ,
196
+ ) -> list [Package ]:
197
+ """
198
+ Search for installed packages, when available, that provides the given
199
+ specification.
200
+
201
+ This is useful when dealing with packages that are under development, not
202
+ published on package sources and/or only available via system installations.
203
+ """
204
+ if not self ._installed :
205
+ return []
206
+
207
+ logger .debug (
208
+ "Falling back to installed packages to discover metadata for <c2>%s</>" ,
209
+ specification .complete_name ,
210
+ )
211
+ packages = [
212
+ package
213
+ for package in self ._installed .packages
214
+ if package .provides (specification )
215
+ ]
216
+ logger .debug (
217
+ "Found <c2>%d</> compatible packages for <c2>%s</>" ,
218
+ len (packages ),
219
+ specification .complete_name ,
220
+ )
221
+ return packages
222
+
188
223
def search_for (
189
224
self ,
190
225
dependency : (
@@ -227,6 +262,9 @@ def search_for(
227
262
reverse = True ,
228
263
)
229
264
265
+ if not packages :
266
+ packages = self .search_for_installed_packages (dependency )
267
+
230
268
return PackageCollection (dependency , packages )
231
269
232
270
def search_for_vcs (self , dependency : VCSDependency ) -> list [Package ]:
@@ -478,15 +516,29 @@ def complete_package(self, package: DependencyPackage) -> DependencyPackage:
478
516
"url" ,
479
517
"git" ,
480
518
}:
481
- package = DependencyPackage (
482
- package .dependency ,
483
- self ._pool .package (
484
- package .name ,
485
- package .version .text ,
486
- extras = list (package .dependency .extras ),
487
- repository = package .dependency .source_name ,
488
- ),
489
- )
519
+ try :
520
+ package = DependencyPackage (
521
+ package .dependency ,
522
+ self ._pool .package (
523
+ package .name ,
524
+ package .version .text ,
525
+ extras = list (package .dependency .extras ),
526
+ repository = package .dependency .source_name ,
527
+ ),
528
+ )
529
+ except PackageNotFound as e :
530
+ try :
531
+ package = next (
532
+ DependencyPackage (
533
+ package .dependency ,
534
+ pkg ,
535
+ )
536
+ for pkg in self .search_for_installed_packages (
537
+ package .dependency
538
+ )
539
+ )
540
+ except StopIteration :
541
+ raise e from e
490
542
requires = package .requires
491
543
else :
492
544
requires = package .requires
0 commit comments