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