Skip to content

Commit a0211b0

Browse files
committed
Cache values for 'is_available()'
1 parent b33b0c0 commit a0211b0

File tree

1 file changed

+22
-3
lines changed

1 file changed

+22
-3
lines changed

src/whichprovides/__init__.py

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
"""
77

88
import dataclasses
9+
import functools
910
import pathlib
1011
import re
1112
import shutil
@@ -290,6 +291,7 @@ def whichprovides(cls, filepaths: typing.Collection[str]) -> dict[str, ProvidedB
290291
return results
291292

292293

294+
@functools.cache
293295
def _package_providers() -> list[type[PackageProvider]]:
294296
"""Returns a list of package providers sorted in
295297
the order that they should be attempted.
@@ -305,6 +307,25 @@ def all_subclasses(cls):
305307
return sorted(all_subclasses(PackageProvider), key=lambda p: p._resolve_order)
306308

307309

310+
# Cache the value of PackageProvider.is_available()
311+
_PACKAGE_PROVIDERS_IS_AVAILABLE: dict[type[PackageProvider], bool] = {}
312+
313+
314+
def _available_package_providers() -> (
315+
typing.Generator[type[PackageProvider], None, None]
316+
):
317+
"""We use a generator here because PackageProviders might not
318+
all need to be queried for 'is_available()' if 'whichprovides()'
319+
is able to find matches for all file paths.
320+
"""
321+
values_cache = _PACKAGE_PROVIDERS_IS_AVAILABLE
322+
for package_provider in _package_providers():
323+
if package_provider not in values_cache:
324+
values_cache[package_provider] = package_provider.is_available()
325+
if values_cache[package_provider]:
326+
yield package_provider
327+
328+
308329
def whichprovides(filepath: typing.Union[str, list[str]]) -> dict[str, ProvidedBy]:
309330
"""Return a package URL (PURL) for the package that provides a file"""
310331
if isinstance(filepath, str):
@@ -318,12 +339,10 @@ def whichprovides(filepath: typing.Union[str, list[str]]) -> dict[str, ProvidedB
318339
str(pathlib.Path(filepath).resolve()): filepath for filepath in filepaths
319340
}
320341
filepath_provided_by: dict[str, ProvidedBy] = {}
321-
for package_provider in _package_providers():
342+
for package_provider in _available_package_providers():
322343
remaining = set(resolved_filepaths) - set(filepath_provided_by)
323344
if not remaining:
324345
break
325-
if not package_provider.is_available():
326-
continue
327346
results = package_provider.whichprovides(remaining)
328347
filepath_provided_by.update(results)
329348

0 commit comments

Comments
 (0)