9
9
"""
10
10
11
11
import functools
12
- import itertools
13
12
14
13
from pip ._vendor .six .moves import collections_abc # type: ignore
15
14
16
15
from pip ._internal .utils .typing import MYPY_CHECK_RUNNING
17
16
18
17
if MYPY_CHECK_RUNNING :
19
- from typing import Callable , Iterator , Optional
18
+ from typing import Callable , Iterator , Optional , Set , Tuple
19
+
20
+ from pip ._vendor .packaging .version import _BaseVersion
20
21
21
22
from .base import Candidate
22
23
24
+ IndexCandidateInfo = Tuple [_BaseVersion , Callable [[], Optional [Candidate ]]]
25
+
26
+
27
+ def _iter_built (infos ):
28
+ # type: (Iterator[IndexCandidateInfo]) -> Iterator[Candidate]
29
+ """Iterator for ``FoundCandidates``.
30
+
31
+ This iterator is used the package is not already installed. Candidates
32
+ from index come later in their normal ordering.
33
+ """
34
+ versions_found = set () # type: Set[_BaseVersion]
35
+ for version , func in infos :
36
+ if version in versions_found :
37
+ continue
38
+ candidate = func ()
39
+ if candidate is None :
40
+ continue
41
+ yield candidate
42
+ versions_found .add (version )
43
+
44
+
45
+ def _iter_built_with_prepended (installed , infos ):
46
+ # type: (Candidate, Iterator[IndexCandidateInfo]) -> Iterator[Candidate]
47
+ """Iterator for ``FoundCandidates``.
48
+
49
+ This iterator is used when the resolver prefers the already-installed
50
+ candidate and NOT to upgrade. The installed candidate is therefore
51
+ always yielded first, and candidates from index come later in their
52
+ normal ordering, except skipped when the version is already installed.
53
+ """
54
+ yield installed
55
+ versions_found = {installed .version } # type: Set[_BaseVersion]
56
+ for version , func in infos :
57
+ if version in versions_found :
58
+ continue
59
+ candidate = func ()
60
+ if candidate is None :
61
+ continue
62
+ yield candidate
63
+ versions_found .add (version )
64
+
23
65
24
- def _insert_installed (installed , others ):
25
- # type: (Candidate, Iterator[Candidate ]) -> Iterator[Candidate]
66
+ def _iter_built_with_inserted (installed , infos ):
67
+ # type: (Candidate, Iterator[IndexCandidateInfo ]) -> Iterator[Candidate]
26
68
"""Iterator for ``FoundCandidates``.
27
69
28
70
This iterator is used when the resolver prefers to upgrade an
@@ -33,16 +75,22 @@ def _insert_installed(installed, others):
33
75
the installed candidate exactly once before we start yielding older or
34
76
equivalent candidates, or after all other candidates if they are all newer.
35
77
"""
36
- installed_yielded = False
37
- for candidate in others :
78
+ versions_found = set () # type: Set[_BaseVersion]
79
+ for version , func in infos :
80
+ if version in versions_found :
81
+ continue
38
82
# If the installed candidate is better, yield it first.
39
- if not installed_yielded and installed .version >= candidate . version :
83
+ if installed .version >= version :
40
84
yield installed
41
- installed_yielded = True
85
+ versions_found .add (installed .version )
86
+ candidate = func ()
87
+ if candidate is None :
88
+ continue
42
89
yield candidate
90
+ versions_found .add (version )
43
91
44
92
# If the installed candidate is older than all other candidates.
45
- if not installed_yielded :
93
+ if installed . version not in versions_found :
46
94
yield installed
47
95
48
96
@@ -56,11 +104,11 @@ class FoundCandidates(collections_abc.Sequence):
56
104
"""
57
105
def __init__ (
58
106
self ,
59
- get_others , # type: Callable[[], Iterator[Candidate ]]
107
+ get_infos , # type: Callable[[], Iterator[IndexCandidateInfo ]]
60
108
installed , # type: Optional[Candidate]
61
109
prefers_installed , # type: bool
62
110
):
63
- self ._get_others = get_others
111
+ self ._get_infos = get_infos
64
112
self ._installed = installed
65
113
self ._prefers_installed = prefers_installed
66
114
@@ -73,16 +121,12 @@ def __getitem__(self, index):
73
121
74
122
def __iter__ (self ):
75
123
# type: () -> Iterator[Candidate]
124
+ infos = self ._get_infos ()
76
125
if not self ._installed :
77
- return self ._get_others ()
78
- others = (
79
- candidate
80
- for candidate in self ._get_others ()
81
- if candidate .version != self ._installed .version
82
- )
126
+ return _iter_built (infos )
83
127
if self ._prefers_installed :
84
- return itertools . chain ([ self ._installed ], others )
85
- return _insert_installed (self ._installed , others )
128
+ return _iter_built_with_prepended ( self ._installed , infos )
129
+ return _iter_built_with_inserted (self ._installed , infos )
86
130
87
131
def __len__ (self ):
88
132
# type: () -> int
0 commit comments