From 8f2e3d69782192920882bafc76c927a3887ee5b7 Mon Sep 17 00:00:00 2001 From: Stefano Rivera Date: Tue, 2 Mar 2021 11:46:31 -0800 Subject: [PATCH 1/2] Parse pkg_resources Dist versions with packaging.version Due to a mix of bundled and unbundled dependencies, pkg_resources Version class may not be the same as packaging's Version class. See: https://github.com/pypa/setuptools/issues/2052 --- news/9e768673-6079-491e-bbe0-d1593952f1c7.trivial.rst | 0 src/pip/_internal/metadata/pkg_resources.py | 6 +++++- src/pip/_internal/resolution/resolvelib/candidates.py | 11 ++++++++--- src/pip/_internal/resolution/resolvelib/resolver.py | 3 ++- 4 files changed, 15 insertions(+), 5 deletions(-) create mode 100644 news/9e768673-6079-491e-bbe0-d1593952f1c7.trivial.rst diff --git a/news/9e768673-6079-491e-bbe0-d1593952f1c7.trivial.rst b/news/9e768673-6079-491e-bbe0-d1593952f1c7.trivial.rst new file mode 100644 index 00000000000..e69de29bb2d diff --git a/src/pip/_internal/metadata/pkg_resources.py b/src/pip/_internal/metadata/pkg_resources.py index 5cd9eaee641..0196ff3476f 100644 --- a/src/pip/_internal/metadata/pkg_resources.py +++ b/src/pip/_internal/metadata/pkg_resources.py @@ -4,6 +4,7 @@ from pip._vendor import pkg_resources from pip._vendor.packaging.utils import canonicalize_name from pip._vendor.packaging.version import _BaseVersion +from pip._vendor.packaging.version import parse as parse_version from pip._internal.utils import misc # TODO: Move definition here. from pip._internal.utils.packaging import get_installer @@ -16,6 +17,7 @@ class Distribution(BaseDistribution): def __init__(self, dist): # type: (pkg_resources.Distribution) -> None self._dist = dist + self._version = None @classmethod def from_wheel(cls, path, name): @@ -45,7 +47,9 @@ def canonical_name(self): @property def version(self): # type: () -> _BaseVersion - return self._dist.parsed_version + if self._version is None: + self._version = parse_version(self._dist.version) + return self._version @property def installer(self): diff --git a/src/pip/_internal/resolution/resolvelib/candidates.py b/src/pip/_internal/resolution/resolvelib/candidates.py index 035e118d022..5638eb0c185 100644 --- a/src/pip/_internal/resolution/resolvelib/candidates.py +++ b/src/pip/_internal/resolution/resolvelib/candidates.py @@ -5,6 +5,7 @@ from pip._vendor.packaging.specifiers import InvalidSpecifier, SpecifierSet from pip._vendor.packaging.utils import canonicalize_name from pip._vendor.packaging.version import Version, _BaseVersion +from pip._vendor.packaging.version import parse as parse_version from pip._vendor.pkg_resources import Distribution from pip._internal.exceptions import HashError, MetadataInconsistent @@ -180,7 +181,7 @@ def name(self): def version(self): # type: () -> _BaseVersion if self._version is None: - self._version = self.dist.parsed_version + self._version = parse_version(self.dist.version) return self._version def format_for_error(self): @@ -206,7 +207,8 @@ def _check_metadata_consistency(self, dist): self._name, dist.project_name, ) - if self._version is not None and self._version != dist.parsed_version: + parsed_version = parse_version(dist.version) + if self._version is not None and self._version != parsed_version: raise MetadataInconsistent( self._ireq, "version", @@ -345,6 +347,7 @@ def __init__( self.dist = dist self._ireq = make_install_req_from_dist(dist, template) self._factory = factory + self._version = None # This is just logging some messages, so we can do it eagerly. # The returned dist would be exactly the same as self.dist because we @@ -387,7 +390,9 @@ def name(self): @property def version(self): # type: () -> _BaseVersion - return self.dist.parsed_version + if self._version is None: + self._version = parse_version(self.dist.version) + return self._version @property def is_editable(self): diff --git a/src/pip/_internal/resolution/resolvelib/resolver.py b/src/pip/_internal/resolution/resolvelib/resolver.py index eba441091b6..7826cfc0fab 100644 --- a/src/pip/_internal/resolution/resolvelib/resolver.py +++ b/src/pip/_internal/resolution/resolvelib/resolver.py @@ -4,6 +4,7 @@ from typing import TYPE_CHECKING, Dict, List, Optional, Set, Tuple from pip._vendor.packaging.utils import canonicalize_name +from pip._vendor.packaging.version import parse as parse_version from pip._vendor.resolvelib import ResolutionImpossible from pip._vendor.resolvelib import Resolver as RLResolver from pip._vendor.resolvelib.resolvers import Result @@ -139,7 +140,7 @@ def resolve(self, root_reqs, check_supported_wheels): elif self.factory.force_reinstall: # The --force-reinstall flag is set -- reinstall. ireq.should_reinstall = True - elif installed_dist.parsed_version != candidate.version: + elif parse_version(installed_dist.version) != candidate.version: # The installation is different in version -- reinstall. ireq.should_reinstall = True elif candidate.is_editable or dist_is_editable(installed_dist): From ba4b7f110ddf620e211be08ee1822362f9d564fc Mon Sep 17 00:00:00 2001 From: Stefano Rivera Date: Wed, 3 Mar 2021 09:27:36 -0800 Subject: [PATCH 2/2] Don't cache _version --- src/pip/_internal/metadata/pkg_resources.py | 5 +---- src/pip/_internal/resolution/resolvelib/candidates.py | 5 +---- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/src/pip/_internal/metadata/pkg_resources.py b/src/pip/_internal/metadata/pkg_resources.py index 0196ff3476f..81fc35c0ff0 100644 --- a/src/pip/_internal/metadata/pkg_resources.py +++ b/src/pip/_internal/metadata/pkg_resources.py @@ -17,7 +17,6 @@ class Distribution(BaseDistribution): def __init__(self, dist): # type: (pkg_resources.Distribution) -> None self._dist = dist - self._version = None @classmethod def from_wheel(cls, path, name): @@ -47,9 +46,7 @@ def canonical_name(self): @property def version(self): # type: () -> _BaseVersion - if self._version is None: - self._version = parse_version(self._dist.version) - return self._version + return parse_version(self._dist.version) @property def installer(self): diff --git a/src/pip/_internal/resolution/resolvelib/candidates.py b/src/pip/_internal/resolution/resolvelib/candidates.py index 5638eb0c185..cb3a51b51fc 100644 --- a/src/pip/_internal/resolution/resolvelib/candidates.py +++ b/src/pip/_internal/resolution/resolvelib/candidates.py @@ -347,7 +347,6 @@ def __init__( self.dist = dist self._ireq = make_install_req_from_dist(dist, template) self._factory = factory - self._version = None # This is just logging some messages, so we can do it eagerly. # The returned dist would be exactly the same as self.dist because we @@ -390,9 +389,7 @@ def name(self): @property def version(self): # type: () -> _BaseVersion - if self._version is None: - self._version = parse_version(self.dist.version) - return self._version + return parse_version(self.dist.version) @property def is_editable(self):