From d10835afbc56e9f473b79c75414ce2844ee6d3f2 Mon Sep 17 00:00:00 2001 From: Frost Ming Date: Fri, 10 Feb 2023 11:23:42 +0800 Subject: [PATCH] fix: prefer built distributions (#1697) --- news/1535.bugfix.md | 1 + src/pdm/models/candidates.py | 37 ++++++++++++++++++----------------- src/pdm/models/environment.py | 1 + 3 files changed, 21 insertions(+), 18 deletions(-) create mode 100644 news/1535.bugfix.md diff --git a/news/1535.bugfix.md b/news/1535.bugfix.md new file mode 100644 index 0000000000..5c319035da --- /dev/null +++ b/news/1535.bugfix.md @@ -0,0 +1 @@ +Prefer built distributions when finding packages for metadata extraction. diff --git a/src/pdm/models/candidates.py b/src/pdm/models/candidates.py index bb7c298203..da4ae9f66b 100644 --- a/src/pdm/models/candidates.py +++ b/src/pdm/models/candidates.py @@ -77,34 +77,35 @@ def _filter_none(data: dict[str, Any]) -> dict[str, Any]: def _find_best_match_link( finder: PackageFinder, req: Requirement, - hashes: dict[Link, str] | None, + links: Iterable[Link] | None = None, ignore_compatibility: bool = False, ) -> Link | None: """Get the best matching link for a requirement""" # This function is called when a lock file candidate is given or incompatible wheel # In this case, the requirement must be pinned, so no need to pass allow_prereleases - # If hashes are not empty, find the best match from the links, otherwise find from + # If links are not empty, find the best match from the links, otherwise find from # the package sources. def attempt_to_find() -> Link | None: - if hashes is None: - best = finder.find_best_match( - req.as_line(), allow_yanked=req.is_pinned - ).best - return best.link if best is not None else None - # We don't evaluate against the hashes, they will be validated later. - evaluator = finder.build_evaluator(req.name) - packages: Iterable[Package] = filter(None, map(evaluator.evaluate_link, hashes)) - best = max(packages, key=finder._sort_key, default=None) + if links is None: + best = finder.find_best_match(req.as_line()).best + else: + # this branch won't be executed twice if ignore_compatibility is True + evaluator = finder.build_evaluator(req.name) + packages = finder._evaluate_links(links, evaluator) + best = max(packages, key=finder._sort_key, default=None) return best.link if best is not None else None - original_ignore = finder.ignore_compatibility - link = attempt_to_find() - if link is None and ignore_compatibility and not original_ignore: - finder.ignore_compatibility = ignore_compatibility - link = attempt_to_find() - finder.ignore_compatibility = original_ignore - return link + assert finder.ignore_compatibility is False + found = attempt_to_find() + if ignore_compatibility and (found is None or not found.is_wheel): + # try to find a wheel for easy metadata extraction + finder.ignore_compatibility = finder.prefer_binary = True + new_found = attempt_to_find() + if new_found is not None: + found = new_found + finder.ignore_compatibility = finder.prefer_binary = False + return found class Candidate: diff --git a/src/pdm/models/environment.py b/src/pdm/models/environment.py index e668d80389..e99d6788e3 100644 --- a/src/pdm/models/environment.py +++ b/src/pdm/models/environment.py @@ -172,6 +172,7 @@ def get_finder( find_links=find_links, target_python=self.target_python, ignore_compatibility=ignore_compatibility, + prefer_binary=ignore_compatibility, no_binary=os.getenv("PDM_NO_BINARY", "").split(","), only_binary=os.getenv("PDM_ONLY_BINARY", "").split(","), respect_source_order=self.project.pyproject.settings.get(