Skip to content

Commit 831f32e

Browse files
authored
Merge pull request #9699 from uranusjr/resolvelib-types
2 parents fe27218 + 9ceabb5 commit 831f32e

File tree

15 files changed

+245
-45
lines changed

15 files changed

+245
-45
lines changed

news/resolvelib.vendor.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Upgrade vendored resolvelib to 0.5.5.

src/pip/_internal/resolution/resolvelib/factory.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
Set,
1313
Tuple,
1414
TypeVar,
15+
cast,
1516
)
1617

1718
from pip._vendor.packaging.specifiers import SpecifierSet
@@ -419,7 +420,7 @@ def _report_requires_python_error(self, causes):
419420
return UnsupportedPythonVersion(message)
420421

421422
def _report_single_requirement_conflict(self, req, parent):
422-
# type: (Requirement, Candidate) -> DistributionNotFound
423+
# type: (Requirement, Optional[Candidate]) -> DistributionNotFound
423424
if parent is None:
424425
req_disp = str(req)
425426
else:
@@ -439,7 +440,7 @@ def _report_single_requirement_conflict(self, req, parent):
439440

440441
def get_installation_error(
441442
self,
442-
e, # type: ResolutionImpossible
443+
e, # type: ResolutionImpossible[Requirement, Candidate]
443444
constraints, # type: Dict[str, Constraint]
444445
):
445446
# type: (...) -> InstallationError
@@ -455,7 +456,11 @@ def get_installation_error(
455456
and not cause.requirement.is_satisfied_by(self._python_candidate)
456457
]
457458
if requires_python_causes:
458-
return self._report_requires_python_error(requires_python_causes)
459+
# The comprehension above makes sure all Requirement instances are
460+
# RequiresPythonRequirement, so let's cast for convinience.
461+
return self._report_requires_python_error(
462+
cast("Sequence[ConflictCause]", requires_python_causes),
463+
)
459464

460465
# Otherwise, we have a set of causes which can't all be satisfied
461466
# at once.

src/pip/_internal/resolution/resolvelib/provider.py

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,20 @@
1-
from typing import Any, Dict, Iterable, Optional, Sequence, Tuple, Union
1+
from typing import TYPE_CHECKING, Dict, Iterable, Optional, Sequence, Union
22

33
from pip._vendor.resolvelib.providers import AbstractProvider
44

55
from .base import Candidate, Constraint, Requirement
66
from .factory import Factory
77

8+
if TYPE_CHECKING:
9+
from pip._vendor.resolvelib.providers import Preference
10+
from pip._vendor.resolvelib.resolvers import RequirementInformation
11+
12+
PreferenceInformation = RequirementInformation[Requirement, Candidate]
13+
14+
_ProviderBase = AbstractProvider[Requirement, Candidate, str]
15+
else:
16+
_ProviderBase = AbstractProvider
17+
818
# Notes on the relationship between the provider, the factory, and the
919
# candidate and requirement classes.
1020
#
@@ -24,7 +34,7 @@
2434
# services to those objects (access to pip's finder and preparer).
2535

2636

27-
class PipProvider(AbstractProvider):
37+
class PipProvider(_ProviderBase):
2838
"""Pip's provider implementation for resolvelib.
2939
3040
:params constraints: A mapping of constraints specified by the user. Keys
@@ -50,17 +60,17 @@ def __init__(
5060
self._upgrade_strategy = upgrade_strategy
5161
self._user_requested = user_requested
5262

53-
def identify(self, dependency):
63+
def identify(self, requirement_or_candidate):
5464
# type: (Union[Requirement, Candidate]) -> str
55-
return dependency.name
65+
return requirement_or_candidate.name
5666

5767
def get_preference(
5868
self,
5969
resolution, # type: Optional[Candidate]
60-
candidates, # type: Sequence[Candidate]
61-
information, # type: Sequence[Tuple[Requirement, Candidate]]
70+
candidates, # type: Iterable[Candidate]
71+
information, # type: Iterable[PreferenceInformation]
6272
):
63-
# type: (...) -> Any
73+
# type: (...) -> Preference
6474
"""Produce a sort key for given requirement based on preference.
6575
6676
The lower the return value is, the more preferred this group of

src/pip/_internal/resolution/resolvelib/resolver.py

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
import functools
22
import logging
33
import os
4-
from typing import TYPE_CHECKING, Dict, List, Optional, Set, Tuple
4+
from typing import TYPE_CHECKING, Dict, List, Optional, Set, Tuple, cast
55

66
from pip._vendor.packaging.utils import canonicalize_name
77
from pip._vendor.packaging.version import parse as parse_version
88
from pip._vendor.resolvelib import BaseReporter, ResolutionImpossible
99
from pip._vendor.resolvelib import Resolver as RLResolver
10-
from pip._vendor.resolvelib.resolvers import Result
10+
from pip._vendor.resolvelib.structs import DirectedGraph
1111

1212
from pip._internal.cache import WheelCache
1313
from pip._internal.exceptions import InstallationError
@@ -28,11 +28,14 @@
2828
from pip._internal.utils.filetypes import is_archive_file
2929
from pip._internal.utils.misc import dist_is_editable
3030

31-
from .base import Constraint
31+
from .base import Candidate, Constraint, Requirement
3232
from .factory import Factory
3333

3434
if TYPE_CHECKING:
35-
from pip._vendor.resolvelib.structs import DirectedGraph
35+
from pip._vendor.resolvelib.resolvers import Result as RLResult
36+
37+
Result = RLResult[Requirement, Candidate, str]
38+
3639

3740
logger = logging.getLogger(__name__)
3841

@@ -114,7 +117,10 @@ def resolve(self, root_reqs, check_supported_wheels):
114117
reporter = PipDebuggingReporter() # type: BaseReporter
115118
else:
116119
reporter = PipReporter()
117-
resolver = RLResolver(provider, reporter)
120+
resolver = RLResolver(
121+
provider,
122+
reporter,
123+
) # type: RLResolver[Requirement, Candidate, str]
118124

119125
try:
120126
try_to_avoid_resolution_too_deep = 2000000
@@ -123,7 +129,10 @@ def resolve(self, root_reqs, check_supported_wheels):
123129
)
124130

125131
except ResolutionImpossible as e:
126-
error = self.factory.get_installation_error(e, constraints)
132+
error = self.factory.get_installation_error(
133+
cast("ResolutionImpossible[Requirement, Candidate]", e),
134+
constraints,
135+
)
127136
raise error from e
128137

129138
req_set = RequirementSet(check_supported_wheels=check_supported_wheels)
@@ -148,7 +157,7 @@ def resolve(self, root_reqs, check_supported_wheels):
148157
# The incoming distribution is editable, or different in
149158
# editable-ness to installation -- reinstall.
150159
ireq.should_reinstall = True
151-
elif candidate.source_link.is_file:
160+
elif candidate.source_link and candidate.source_link.is_file:
152161
# The incoming distribution is under file://
153162
if candidate.source_link.is_wheel:
154163
# is a local wheel -- do nothing.
@@ -236,7 +245,7 @@ def get_installation_order(self, req_set):
236245

237246

238247
def get_topological_weights(graph, expected_node_count):
239-
# type: (DirectedGraph, int) -> Dict[Optional[str], int]
248+
# type: (DirectedGraph[Optional[str]], int) -> Dict[Optional[str], int]
240249
"""Assign weights to each node based on how "deep" they are.
241250
242251
This implementation may change at any point in the future without prior

src/pip/_vendor/resolvelib.pyi

Lines changed: 0 additions & 1 deletion
This file was deleted.

src/pip/_vendor/resolvelib/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
"ResolutionTooDeep",
1212
]
1313

14-
__version__ = "0.5.4"
14+
__version__ = "0.5.5"
1515

1616

1717
from .providers import AbstractProvider, AbstractResolver
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
__version__: str
2+
3+
from .providers import (
4+
AbstractResolver as AbstractResolver,
5+
AbstractProvider as AbstractProvider,
6+
)
7+
from .reporters import BaseReporter as BaseReporter
8+
from .resolvers import (
9+
InconsistentCandidate as InconsistentCandidate,
10+
RequirementsConflicted as RequirementsConflicted,
11+
Resolver as Resolver,
12+
ResolutionError as ResolutionError,
13+
ResolutionImpossible as ResolutionImpossible,
14+
ResolutionTooDeep as ResolutionTooDeep,
15+
)

src/pip/_vendor/resolvelib/providers.py

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,10 @@ class AbstractProvider(object):
22
"""Delegate class to provide requirement interface for the resolver."""
33

44
def identify(self, requirement_or_candidate):
5-
"""Given a requirement or candidate, return an identifier for it.
5+
"""Given a requirement, return an identifier for it.
66
7-
This is used in many places to identify a requirement or candidate,
8-
e.g. whether two requirements should have their specifier parts merged,
9-
whether two candidates would conflict with each other (because they
10-
have same name but different versions).
7+
This is used to identify a requirement, e.g. whether two requirements
8+
should have their specifier parts merged.
119
"""
1210
raise NotImplementedError
1311

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
from typing import (
2+
Any,
3+
Collection,
4+
Generic,
5+
Iterable,
6+
Mapping,
7+
Optional,
8+
Protocol,
9+
Sequence,
10+
Union,
11+
)
12+
13+
from .reporters import BaseReporter
14+
from .resolvers import RequirementInformation
15+
from .structs import (
16+
KT,
17+
RT,
18+
CT,
19+
IterableView,
20+
Matches,
21+
)
22+
23+
class Preference(Protocol):
24+
def __lt__(self, __other: Any) -> bool: ...
25+
26+
class AbstractProvider(Generic[RT, CT, KT]):
27+
def identify(self, requirement_or_candidate: Union[RT, CT]) -> KT: ...
28+
def get_preference(
29+
self,
30+
resolution: Optional[CT],
31+
candidates: IterableView[CT],
32+
information: Collection[RequirementInformation[RT, CT]],
33+
) -> Preference: ...
34+
def find_matches(self, requirements: Sequence[RT]) -> Matches: ...
35+
def is_satisfied_by(self, requirement: RT, candidate: CT) -> bool: ...
36+
def get_dependencies(self, candidate: CT) -> Iterable[RT]: ...
37+
38+
class AbstractResolver(Generic[RT, CT, KT]):
39+
base_exception = Exception
40+
provider: AbstractProvider[RT, CT, KT]
41+
reporter: BaseReporter
42+
def __init__(
43+
self, provider: AbstractProvider[RT, CT, KT], reporter: BaseReporter
44+
): ...

src/pip/_vendor/resolvelib/py.typed

Whitespace-only changes.

0 commit comments

Comments
 (0)