From 779062808089da7bed189abf5fd14bfd20d79431 Mon Sep 17 00:00:00 2001 From: Tzu-ping Chung Date: Wed, 17 Apr 2019 08:31:03 +0800 Subject: [PATCH 1/7] Comment fix --- src/pip/_internal/index.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/pip/_internal/index.py b/src/pip/_internal/index.py index 1f251448be7..b4cad9df868 100644 --- a/src/pip/_internal/index.py +++ b/src/pip/_internal/index.py @@ -727,7 +727,8 @@ def find_requirement(self, req, upgrade): def _format_versions(cand_iter): # This repeated parse_version and str() conversion is needed to # handle different vendoring sources from pip and pkg_resources. - # If we stop using the pkg_resources provided specifier. + # If we stop using the pkg_resources provided specifier and start + # using our own, we can drop the cast to str(). return ", ".join(sorted( {str(c.version) for c in cand_iter}, key=parse_version, From 5b1fb22e4766ddc1fded93498805a8fe94081760 Mon Sep 17 00:00:00 2001 From: Tzu-ping Chung Date: Wed, 17 Apr 2019 08:39:24 +0800 Subject: [PATCH 2/7] Generate the filtered version set eargerly --- ...ac3bb3-d29f-4e63-a3e5-f3d31da9283f.trivial | 0 src/pip/_internal/index.py | 46 +++++++++++-------- 2 files changed, 27 insertions(+), 19 deletions(-) create mode 100644 news/5aac3bb3-d29f-4e63-a3e5-f3d31da9283f.trivial diff --git a/news/5aac3bb3-d29f-4e63-a3e5-f3d31da9283f.trivial b/news/5aac3bb3-d29f-4e63-a3e5-f3d31da9283f.trivial new file mode 100644 index 00000000000..e69de29bb2d diff --git a/src/pip/_internal/index.py b/src/pip/_internal/index.py index b4cad9df868..49452c7c69e 100644 --- a/src/pip/_internal/index.py +++ b/src/pip/_internal/index.py @@ -270,16 +270,36 @@ class FoundCandidates(object): def __init__( self, candidates, # type: List[InstallationCandidate] - specifier, # type: specifiers.BaseSpecifier - prereleases, # type: Optional[bool] + versions, # type: Set[_BaseVersion] sort_key, # type: Callable[[InstallationCandidate], Any] ): # type: (...) -> None self._candidates = candidates - self._specifier = specifier - self._prereleases = prereleases + self._versions = versions self._sort_key = sort_key + @classmethod + def from_specifier( + cls, + candidates, # type: List[InstallationCandidate] + specifier, # type: specifiers.BaseSpecifier + prereleases, # type: Optional[bool] + sort_key, # type: Callable[[InstallationCandidate], Any] + ): + # type: (...) -> FoundCandidates + versions = set(specifier.filter( + # We turn the version object into a str here because otherwise + # when we're debundled but setuptools isn't, Python will see + # packaging.version.Version and + # pkg_resources._vendor.packaging.version.Version as different + # types. This way we'll use a str as a common data interchange + # format. If we stop using the pkg_resources provided specifier + # and start using our own, we can drop the cast to str(). + [str(c.version) for c in candidates], + prereleases=prereleases, + )) + cls(candidates, versions, sort_key) + def iter_all(self): # type: () -> Iterable[InstallationCandidate] """Iterate through all candidates. @@ -290,20 +310,8 @@ def iter_applicable(self): # type: () -> Iterable[InstallationCandidate] """Iterate through candidates matching the given specifier. """ - # Filter out anything which doesn't match our specifier. - versions = set(self._specifier.filter( - # We turn the version object into a str here because otherwise - # when we're debundled but setuptools isn't, Python will see - # packaging.version.Version and - # pkg_resources._vendor.packaging.version.Version as different - # types. This way we'll use a str as a common data interchange - # format. If we stop using the pkg_resources provided specifier - # and start using our own, we can drop the cast to str(). - [str(c.version) for c in self._candidates], - prereleases=self._prereleases, - )) - # Again, converting to str to deal with debundling. - return (c for c in self._candidates if str(c.version) in versions) + # Again, converting version to str to deal with debundling. + return (c for c in self.iter_all() if str(c.version) in self._versions) def get_best(self): # type: () -> Optional[InstallationCandidate] @@ -702,7 +710,7 @@ def find_candidates( Returns a `FoundCandidates` instance. """ - return FoundCandidates( + return FoundCandidates.from_specifier( self.find_all_candidates(project_name), specifier=specifier, prereleases=(self.allow_all_prereleases or None), From 288f5b9cb0d4db8dbc174f681ea3d73dc56c1c64 Mon Sep 17 00:00:00 2001 From: Tzu-ping Chung Date: Wed, 17 Apr 2019 09:40:04 +0800 Subject: [PATCH 3/7] Return! --- src/pip/_internal/index.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pip/_internal/index.py b/src/pip/_internal/index.py index 49452c7c69e..01f320cfb38 100644 --- a/src/pip/_internal/index.py +++ b/src/pip/_internal/index.py @@ -298,7 +298,7 @@ def from_specifier( [str(c.version) for c in candidates], prereleases=prereleases, )) - cls(candidates, versions, sort_key) + return cls(candidates, versions, sort_key) def iter_all(self): # type: () -> Iterable[InstallationCandidate] From 635a9b5c8fa5526e2fddec2fea4b39eb307452e6 Mon Sep 17 00:00:00 2001 From: Tzu-ping Chung Date: Thu, 18 Apr 2019 15:26:48 +0800 Subject: [PATCH 4/7] Defailt find_candidates()'s specifier to None --- src/pip/_internal/index.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/pip/_internal/index.py b/src/pip/_internal/index.py index 01f320cfb38..16be51e832f 100644 --- a/src/pip/_internal/index.py +++ b/src/pip/_internal/index.py @@ -700,8 +700,8 @@ def find_all_candidates(self, project_name): def find_candidates( self, - project_name, # type: str - specifier=specifiers.SpecifierSet(), # type: specifiers.BaseSpecifier + project_name, # type: str + specifier=None, # type: Optional[specifiers.BaseSpecifier] ): """Find matches for the given project and specifier. @@ -710,6 +710,8 @@ def find_candidates( Returns a `FoundCandidates` instance. """ + if specifier is None: + specifier = specifiers.SpecifierSet() return FoundCandidates.from_specifier( self.find_all_candidates(project_name), specifier=specifier, From 60caa9692126796321b3cd059ac0c82d63a2d8e8 Mon Sep 17 00:00:00 2001 From: Tzu-ping Chung Date: Thu, 18 Apr 2019 15:31:22 +0800 Subject: [PATCH 5/7] Make FoundCandidates._versions a set of strings --- src/pip/_internal/index.py | 43 +++++++++++++++----------------------- 1 file changed, 17 insertions(+), 26 deletions(-) diff --git a/src/pip/_internal/index.py b/src/pip/_internal/index.py index 16be51e832f..786761d4c25 100644 --- a/src/pip/_internal/index.py +++ b/src/pip/_internal/index.py @@ -270,35 +270,26 @@ class FoundCandidates(object): def __init__( self, candidates, # type: List[InstallationCandidate] - versions, # type: Set[_BaseVersion] + specifier, # type: specifiers.BaseSpecifier + prereleases, # type: Optional[bool] sort_key, # type: Callable[[InstallationCandidate], Any] ): # type: (...) -> None self._candidates = candidates - self._versions = versions self._sort_key = sort_key - - @classmethod - def from_specifier( - cls, - candidates, # type: List[InstallationCandidate] - specifier, # type: specifiers.BaseSpecifier - prereleases, # type: Optional[bool] - sort_key, # type: Callable[[InstallationCandidate], Any] - ): - # type: (...) -> FoundCandidates - versions = set(specifier.filter( - # We turn the version object into a str here because otherwise - # when we're debundled but setuptools isn't, Python will see - # packaging.version.Version and - # pkg_resources._vendor.packaging.version.Version as different - # types. This way we'll use a str as a common data interchange - # format. If we stop using the pkg_resources provided specifier - # and start using our own, we can drop the cast to str(). - [str(c.version) for c in candidates], - prereleases=prereleases, - )) - return cls(candidates, versions, sort_key) + self._versions = { + str(v) for v in specifier.filter( + # We turn the version object into a str here because otherwise + # when we're debundled but setuptools isn't, Python will see + # packaging.version.Version and + # pkg_resources._vendor.packaging.version.Version as different + # types. This way we'll use a str as a common data interchange + # format. If we stop using the pkg_resources provided specifier + # and start using our own, we can drop the cast to str(). + (str(c.version) for c in candidates), + prereleases=prereleases, + ) + } def iter_all(self): # type: () -> Iterable[InstallationCandidate] @@ -308,7 +299,7 @@ def iter_all(self): def iter_applicable(self): # type: () -> Iterable[InstallationCandidate] - """Iterate through candidates matching the given specifier. + """Iterate through candidates matching the desired versions. """ # Again, converting version to str to deal with debundling. return (c for c in self.iter_all() if str(c.version) in self._versions) @@ -712,7 +703,7 @@ def find_candidates( """ if specifier is None: specifier = specifiers.SpecifierSet() - return FoundCandidates.from_specifier( + return FoundCandidates( self.find_all_candidates(project_name), specifier=specifier, prereleases=(self.allow_all_prereleases or None), From 58393770daca2772a45ca6507583459db166a1e5 Mon Sep 17 00:00:00 2001 From: Tzu-ping Chung Date: Sat, 20 Apr 2019 00:56:41 +0800 Subject: [PATCH 6/7] Bring back FoundCandidates' classmethod constructor --- src/pip/_internal/index.py | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/src/pip/_internal/index.py b/src/pip/_internal/index.py index 786761d4c25..caeb4ea6d1f 100644 --- a/src/pip/_internal/index.py +++ b/src/pip/_internal/index.py @@ -258,6 +258,9 @@ def _get_html_page(link, session=None): class FoundCandidates(object): """A collection of candidates, returned by `PackageFinder.find_candidates`. + This class is only intended to be instantiated by PackageFinder through + the `from_specifier()` constructor. + Arguments: * `candidates`: A sequence of all available candidates found. @@ -270,14 +273,24 @@ class FoundCandidates(object): def __init__( self, candidates, # type: List[InstallationCandidate] - specifier, # type: specifiers.BaseSpecifier - prereleases, # type: Optional[bool] + versions, # type: Set[str] sort_key, # type: Callable[[InstallationCandidate], Any] ): # type: (...) -> None self._candidates = candidates self._sort_key = sort_key - self._versions = { + self._versions = versions + + @classmethod + def from_specifier( + cls, + candidates, # type: List[InstallationCandidate] + specifier, # type: specifiers.BaseSpecifier + prereleases, # type: Optional[bool] + sort_key, # type: Callable[[InstallationCandidate], Any] + ): + # type: (...) -> FoundCandidates + versions = { str(v) for v in specifier.filter( # We turn the version object into a str here because otherwise # when we're debundled but setuptools isn't, Python will see @@ -290,6 +303,7 @@ def __init__( prereleases=prereleases, ) } + return cls(candidates, versions, sort_key) def iter_all(self): # type: () -> Iterable[InstallationCandidate] @@ -703,7 +717,7 @@ def find_candidates( """ if specifier is None: specifier = specifiers.SpecifierSet() - return FoundCandidates( + return FoundCandidates.from_specifier( self.find_all_candidates(project_name), specifier=specifier, prereleases=(self.allow_all_prereleases or None), From b553b4c6155ad75c5c89d3c02a0e650fb32668f6 Mon Sep 17 00:00:00 2001 From: Tzu-ping Chung Date: Sat, 20 Apr 2019 00:58:48 +0800 Subject: [PATCH 7/7] Docstring reword --- src/pip/_internal/index.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/pip/_internal/index.py b/src/pip/_internal/index.py index caeb4ea6d1f..c836e1646d0 100644 --- a/src/pip/_internal/index.py +++ b/src/pip/_internal/index.py @@ -313,7 +313,8 @@ def iter_all(self): def iter_applicable(self): # type: () -> Iterable[InstallationCandidate] - """Iterate through candidates matching the desired versions. + """Iterate through candidates matching the versions associated with + this instance. """ # Again, converting version to str to deal with debundling. return (c for c in self.iter_all() if str(c.version) in self._versions)