From a09dd292d030d861700a34897698c573f292515c Mon Sep 17 00:00:00 2001 From: Matt Davis Date: Mon, 28 Aug 2023 22:13:56 -0400 Subject: [PATCH 1/4] Restore the ignore compatability finder patch from prior pipenv versions --- .../pip/_internal/index/package_finder.py | 31 +++-- .../patched/pip23-compatability-finder.patch | 114 ++++++++++++++++++ 2 files changed, 136 insertions(+), 9 deletions(-) create mode 100644 tasks/vendoring/patches/patched/pip23-compatability-finder.patch diff --git a/pipenv/patched/pip/_internal/index/package_finder.py b/pipenv/patched/pip/_internal/index/package_finder.py index e74e6623..cc81f35c 100644 --- a/pipenv/patched/pip/_internal/index/package_finder.py +++ b/pipenv/patched/pip/_internal/index/package_finder.py @@ -125,6 +125,7 @@ class LinkEvaluator: target_python: TargetPython, allow_yanked: bool, ignore_requires_python: Optional[bool] = None, + ignore_compatibility: Optional[bool] = None, ) -> None: """ :param project_name: The user supplied package name. @@ -142,6 +143,8 @@ class LinkEvaluator: :param ignore_requires_python: Whether to ignore incompatible PEP 503 "data-requires-python" values in HTML links. Defaults to False. + :param ignore_compatibility: Whether to ignore + compatibility of python versions and allow all versions of packages. """ if ignore_requires_python is None: ignore_requires_python = False @@ -151,6 +154,7 @@ class LinkEvaluator: self._ignore_requires_python = ignore_requires_python self._formats = formats self._target_python = target_python + self._ignore_compatibility = ignore_compatibility self.project_name = project_name @@ -181,10 +185,10 @@ class LinkEvaluator: LinkType.format_unsupported, f"unsupported archive format: {ext}", ) - if "binary" not in self._formats and ext == WHEEL_EXTENSION: + if "binary" not in self._formats and ext == WHEEL_EXTENSION and not self._ignore_compatibility: reason = f"No binaries permitted for {self.project_name}" return (LinkType.format_unsupported, reason) - if "macosx10" in link.path and ext == ".zip": + if "macosx10" in link.path and ext == ".zip" and not self._ignore_compatibility: return (LinkType.format_unsupported, "macosx10 one") if ext == WHEEL_EXTENSION: try: @@ -199,7 +203,7 @@ class LinkEvaluator: return (LinkType.different_project, reason) supported_tags = self._target_python.get_tags() - if not wheel.supported(supported_tags): + if not wheel.supported(supported_tags) and not self._ignore_compatibility: # Include the wheel's tags in the reason string to # simplify troubleshooting compatibility issues. file_tags = ", ".join(wheel.get_formatted_file_tags()) @@ -240,7 +244,7 @@ class LinkEvaluator: version_info=self._target_python.py_version_info, ignore_requires_python=self._ignore_requires_python, ) - if not supports_python: + if not supports_python and not self._ignore_compatibility: reason = f"{version} Requires-Python {link.requires_python}" return (LinkType.requires_python_mismatch, reason) @@ -487,7 +491,11 @@ class CandidateEvaluator: return sorted(filtered_applicable_candidates, key=self._sort_key) - def _sort_key(self, candidate: InstallationCandidate) -> CandidateSortingKey: + def _sort_key( + self, + candidate: InstallationCandidate, + ignore_compatibility: bool = True + ) -> CandidateSortingKey: """ Function to pass as the `key` argument to a call to sorted() to sort InstallationCandidates by preference. @@ -532,10 +540,12 @@ class CandidateEvaluator: ) ) except ValueError: - raise UnsupportedWheel( - "{} is not a supported wheel for this platform. It " - "can't be sorted.".format(wheel.filename) - ) + if not ignore_compatibility: + raise UnsupportedWheel( + "{} is not a supported wheel for this platform. It " + "can't be sorted.".format(wheel.filename) + ) + pri = -support_num if self._prefer_binary: binary_preference = 1 if wheel.build_tag is not None: @@ -602,6 +612,7 @@ class PackageFinder: format_control: Optional[FormatControl] = None, candidate_prefs: Optional[CandidatePreferences] = None, ignore_requires_python: Optional[bool] = None, + ignore_compatibility: Optional[bool] = False, ) -> None: """ This constructor is primarily meant to be used by the create() class @@ -623,6 +634,7 @@ class PackageFinder: self._ignore_requires_python = ignore_requires_python self._link_collector = link_collector self._target_python = target_python + self._ignore_compatibility = ignore_compatibility self.format_control = format_control @@ -723,6 +735,7 @@ class PackageFinder: target_python=self._target_python, allow_yanked=self._allow_yanked, ignore_requires_python=self._ignore_requires_python, + ignore_compatibility=self._ignore_compatibility, ) def _sort_links(self, links: Iterable[Link]) -> List[Link]: diff --git a/tasks/vendoring/patches/patched/pip23-compatability-finder.patch b/tasks/vendoring/patches/patched/pip23-compatability-finder.patch new file mode 100644 index 00000000..4bfbcd29 --- /dev/null +++ b/tasks/vendoring/patches/patched/pip23-compatability-finder.patch @@ -0,0 +1,114 @@ +diff --git a/pipenv/patched/pip/_internal/index/package_finder.py b/pipenv/patched/pip/_internal/index/package_finder.py +index e74e6623..cc81f35c 100644 +--- a/pipenv/patched/pip/_internal/index/package_finder.py ++++ b/pipenv/patched/pip/_internal/index/package_finder.py +@@ -125,6 +125,7 @@ class LinkEvaluator: + target_python: TargetPython, + allow_yanked: bool, + ignore_requires_python: Optional[bool] = None, ++ ignore_compatibility: Optional[bool] = None, + ) -> None: + """ + :param project_name: The user supplied package name. +@@ -142,6 +143,8 @@ class LinkEvaluator: + :param ignore_requires_python: Whether to ignore incompatible + PEP 503 "data-requires-python" values in HTML links. Defaults + to False. ++ :param ignore_compatibility: Whether to ignore ++ compatibility of python versions and allow all versions of packages. + """ + if ignore_requires_python is None: + ignore_requires_python = False +@@ -151,6 +154,7 @@ class LinkEvaluator: + self._ignore_requires_python = ignore_requires_python + self._formats = formats + self._target_python = target_python ++ self._ignore_compatibility = ignore_compatibility + + self.project_name = project_name + +@@ -181,10 +185,10 @@ class LinkEvaluator: + LinkType.format_unsupported, + f"unsupported archive format: {ext}", + ) +- if "binary" not in self._formats and ext == WHEEL_EXTENSION: ++ if "binary" not in self._formats and ext == WHEEL_EXTENSION and not self._ignore_compatibility: + reason = f"No binaries permitted for {self.project_name}" + return (LinkType.format_unsupported, reason) +- if "macosx10" in link.path and ext == ".zip": ++ if "macosx10" in link.path and ext == ".zip" and not self._ignore_compatibility: + return (LinkType.format_unsupported, "macosx10 one") + if ext == WHEEL_EXTENSION: + try: +@@ -199,7 +203,7 @@ class LinkEvaluator: + return (LinkType.different_project, reason) + + supported_tags = self._target_python.get_tags() +- if not wheel.supported(supported_tags): ++ if not wheel.supported(supported_tags) and not self._ignore_compatibility: + # Include the wheel's tags in the reason string to + # simplify troubleshooting compatibility issues. + file_tags = ", ".join(wheel.get_formatted_file_tags()) +@@ -240,7 +244,7 @@ class LinkEvaluator: + version_info=self._target_python.py_version_info, + ignore_requires_python=self._ignore_requires_python, + ) +- if not supports_python: ++ if not supports_python and not self._ignore_compatibility: + reason = f"{version} Requires-Python {link.requires_python}" + return (LinkType.requires_python_mismatch, reason) + +@@ -487,7 +491,11 @@ class CandidateEvaluator: + + return sorted(filtered_applicable_candidates, key=self._sort_key) + +- def _sort_key(self, candidate: InstallationCandidate) -> CandidateSortingKey: ++ def _sort_key( ++ self, ++ candidate: InstallationCandidate, ++ ignore_compatibility: bool = True ++ ) -> CandidateSortingKey: + """ + Function to pass as the `key` argument to a call to sorted() to sort + InstallationCandidates by preference. +@@ -532,10 +540,12 @@ class CandidateEvaluator: + ) + ) + except ValueError: +- raise UnsupportedWheel( +- "{} is not a supported wheel for this platform. It " +- "can't be sorted.".format(wheel.filename) +- ) ++ if not ignore_compatibility: ++ raise UnsupportedWheel( ++ "{} is not a supported wheel for this platform. It " ++ "can't be sorted.".format(wheel.filename) ++ ) ++ pri = -support_num + if self._prefer_binary: + binary_preference = 1 + if wheel.build_tag is not None: +@@ -602,6 +612,7 @@ class PackageFinder: + format_control: Optional[FormatControl] = None, + candidate_prefs: Optional[CandidatePreferences] = None, + ignore_requires_python: Optional[bool] = None, ++ ignore_compatibility: Optional[bool] = False, + ) -> None: + """ + This constructor is primarily meant to be used by the create() class +@@ -623,6 +634,7 @@ class PackageFinder: + self._ignore_requires_python = ignore_requires_python + self._link_collector = link_collector + self._target_python = target_python ++ self._ignore_compatibility = ignore_compatibility + + self.format_control = format_control + +@@ -723,6 +735,7 @@ class PackageFinder: + target_python=self._target_python, + allow_yanked=self._allow_yanked, + ignore_requires_python=self._ignore_requires_python, ++ ignore_compatibility=self._ignore_compatibility, + ) + + def _sort_links(self, links: Iterable[Link]) -> List[Link]: From cff4540f6ee264c3222e966092cb65b4054008ce Mon Sep 17 00:00:00 2001 From: Matt Davis Date: Mon, 28 Aug 2023 22:21:54 -0400 Subject: [PATCH 2/4] Attempt to restore prior behavior of collecting hashes ignoring the compatibility of the current system --- pipenv/utils/resolver.py | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/pipenv/utils/resolver.py b/pipenv/utils/resolver.py index 34277872..8b69d9e8 100644 --- a/pipenv/utils/resolver.py +++ b/pipenv/utils/resolver.py @@ -245,7 +245,6 @@ class Resolver: resolver.skipped[package_name] = dep resolver.initial_constraints = constraints resolver.index_lookup = index_lookup - resolver.finder.index_lookup = index_lookup resolver.markers_lookup = markers_lookup return resolver @@ -335,12 +334,12 @@ class Resolver: ) return finder - @property - def finder(self): + def finder(self, ignore_compatibility=False): finder = self.package_finder index_lookup = self.prepare_index_lookup() finder._link_collector.index_lookup = index_lookup finder._link_collector.search_scope.index_lookup = index_lookup + finder._ignore_compatibility = ignore_compatibility return finder @cached_property @@ -349,7 +348,7 @@ class Resolver: pip_options.extra_index_urls = [] return parse_requirements( self.constraint_file, - finder=self.finder, + finder=self.finder(), session=self.session, options=pip_options, ) @@ -361,7 +360,7 @@ class Resolver: parsed_default_constraints = parse_requirements( self.default_constraint_file, constraint=True, - finder=self.finder, + finder=self.finder(), session=self.session, options=pip_options, ) @@ -411,7 +410,7 @@ class Resolver: globally_managed=True ) as directory: pip_options = self.pip_options - finder = self.finder + finder = self.finder() wheel_cache = WheelCache(pip_options.cache_dir) preparer = self.pip_command.make_requirement_preparer( temp_build_dir=directory, @@ -455,9 +454,11 @@ class Resolver: if result.markers: self.markers[result.name] = result.markers else: - candidate = self.finder.find_best_candidate( - result.name, result.specifier - ).best_candidate + candidate = ( + self.finder() + .find_best_candidate(result.name, result.specifier) + .best_candidate + ) if candidate: requires_python = candidate.link.requires_python if requires_python: @@ -500,9 +501,11 @@ class Resolver: if hashes: return hashes - applicable_candidates = self.finder.find_best_candidate( - ireq.name, ireq.specifier - ).iter_applicable() + applicable_candidates = ( + self.finder(ignore_compatibility=True) + .find_best_candidate(ireq.name, ireq.specifier) + .iter_applicable() + ) applicable_candidates = list(applicable_candidates) if applicable_candidates: return sorted( From 84ce337847ab9399165e75d13937e9e608be7620 Mon Sep 17 00:00:00 2001 From: Matt Davis Date: Fri, 1 Sep 2023 17:53:06 -0400 Subject: [PATCH 3/4] Handle case of not resolving all hashes from the google artifact registry --- pipenv/project.py | 2 +- pipenv/utils/resolver.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pipenv/project.py b/pipenv/project.py index 7a8978f0..8f7c8850 100644 --- a/pipenv/project.py +++ b/pipenv/project.py @@ -348,7 +348,7 @@ class Project: return self.prepend_hash_types(collected_hashes, FAVORITE_HASH) - except (ValueError, KeyError, ConnectionError): + except Exception: if self.s.is_verbose(): click.echo( "{}: Error generating hash for {}".format( diff --git a/pipenv/utils/resolver.py b/pipenv/utils/resolver.py index bee39003..fc1a188b 100644 --- a/pipenv/utils/resolver.py +++ b/pipenv/utils/resolver.py @@ -334,7 +334,7 @@ class Resolver: ) return finder - def finder(self, ignore_compatibility=False): + def finder(self, ignore_compatibility=True): finder = self.package_finder index_lookup = self.prepare_index_lookup() finder._link_collector.index_lookup = index_lookup From 70fe658910991f43acb6bec71324017f73c5ad1a Mon Sep 17 00:00:00 2001 From: Matt Davis Date: Tue, 5 Sep 2023 10:07:34 -0400 Subject: [PATCH 4/4] add news fragment --- news/5887.bugfix.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 news/5887.bugfix.rst diff --git a/news/5887.bugfix.rst b/news/5887.bugfix.rst new file mode 100644 index 00000000..05218526 --- /dev/null +++ b/news/5887.bugfix.rst @@ -0,0 +1 @@ +Restore the ignore compatibility finder pip patch to resolve issues collecting hashes from google artifact registry (and possibly others).