7
7
Iterable ,
8
8
Iterator ,
9
9
List ,
10
+ Mapping ,
10
11
Optional ,
11
12
Sequence ,
12
13
Set ,
@@ -104,6 +105,9 @@ def __init__(
104
105
self ._installed_candidate_cache = (
105
106
{}
106
107
) # type: Dict[str, AlreadyInstalledCandidate]
108
+ self ._extras_candidate_cache = (
109
+ {}
110
+ ) # type: Dict[Tuple[int, FrozenSet[str]], ExtrasCandidate]
107
111
108
112
if not ignore_installed :
109
113
self ._installed_dists = {
@@ -118,6 +122,16 @@ def force_reinstall(self):
118
122
# type: () -> bool
119
123
return self ._force_reinstall
120
124
125
+ def _make_extras_candidate (self , base , extras ):
126
+ # type: (BaseCandidate, FrozenSet[str]) -> ExtrasCandidate
127
+ cache_key = (id (base ), extras )
128
+ try :
129
+ candidate = self ._extras_candidate_cache [cache_key ]
130
+ except KeyError :
131
+ candidate = ExtrasCandidate (base , extras )
132
+ self ._extras_candidate_cache [cache_key ] = candidate
133
+ return candidate
134
+
121
135
def _make_candidate_from_dist (
122
136
self ,
123
137
dist , # type: Distribution
@@ -130,9 +144,9 @@ def _make_candidate_from_dist(
130
144
except KeyError :
131
145
base = AlreadyInstalledCandidate (dist , template , factory = self )
132
146
self ._installed_candidate_cache [dist .key ] = base
133
- if extras :
134
- return ExtrasCandidate ( base , extras )
135
- return base
147
+ if not extras :
148
+ return base
149
+ return self . _make_extras_candidate ( base , extras )
136
150
137
151
def _make_candidate_from_link (
138
152
self ,
@@ -182,18 +196,18 @@ def _make_candidate_from_link(
182
196
return None
183
197
base = self ._link_candidate_cache [link ]
184
198
185
- if extras :
186
- return ExtrasCandidate ( base , extras )
187
- return base
199
+ if not extras :
200
+ return base
201
+ return self . _make_extras_candidate ( base , extras )
188
202
189
203
def _iter_found_candidates (
190
204
self ,
191
- ireqs , # type : Sequence[InstallRequirement]
192
- specifier , # type : SpecifierSet
193
- hashes , # type : Hashes
194
- prefers_installed , # type : bool
195
- ):
196
- # type: (... ) -> Iterable[Candidate]
205
+ ireqs : Sequence [InstallRequirement ],
206
+ specifier : SpecifierSet ,
207
+ hashes : Hashes ,
208
+ prefers_installed : bool ,
209
+ incompatible_ids : Set [ int ],
210
+ ) -> Iterable [Candidate ]:
197
211
if not ireqs :
198
212
return ()
199
213
@@ -257,20 +271,27 @@ def iter_index_candidate_infos():
257
271
iter_index_candidate_infos ,
258
272
installed_candidate ,
259
273
prefers_installed ,
274
+ incompatible_ids ,
260
275
)
261
276
262
277
def find_candidates (
263
278
self ,
264
- requirements , # type: Sequence[Requirement]
265
- constraint , # type: Constraint
266
- prefers_installed , # type: bool
267
- ):
268
- # type: (...) -> Iterable[Candidate]
279
+ identifier : str ,
280
+ requirements : Mapping [str , Iterator [Requirement ]],
281
+ incompatibilities : Mapping [str , Iterator [Candidate ]],
282
+ constraint : Constraint ,
283
+ prefers_installed : bool ,
284
+ ) -> Iterable [Candidate ]:
285
+
286
+ # Since we cache all the candidates, incompatibility identification
287
+ # can be made quicker by comparing only the id() values.
288
+ incompat_ids = {id (c ) for c in incompatibilities .get (identifier , ())}
289
+
269
290
explicit_candidates = set () # type: Set[Candidate]
270
291
ireqs = [] # type: List[InstallRequirement]
271
- for req in requirements :
292
+ for req in requirements [ identifier ] :
272
293
cand , ireq = req .get_candidate_lookup ()
273
- if cand is not None :
294
+ if cand is not None and id ( cand ) not in incompat_ids :
274
295
explicit_candidates .add (cand )
275
296
if ireq is not None :
276
297
ireqs .append (ireq )
@@ -283,13 +304,14 @@ def find_candidates(
283
304
constraint .specifier ,
284
305
constraint .hashes ,
285
306
prefers_installed ,
307
+ incompat_ids ,
286
308
)
287
309
288
310
return (
289
311
c
290
312
for c in explicit_candidates
291
313
if constraint .is_satisfied_by (c )
292
- and all (req .is_satisfied_by (c ) for req in requirements )
314
+ and all (req .is_satisfied_by (c ) for req in requirements [ identifier ] )
293
315
)
294
316
295
317
def make_requirement_from_install_req (self , ireq , requested_extras ):
0 commit comments