27
27
28
28
from python .private .pypi .whl_installer .platform import (
29
29
Platform ,
30
- host_interpreter_minor_version ,
30
+ host_interpreter_version ,
31
31
)
32
32
33
33
@@ -62,12 +62,13 @@ def __init__(
62
62
"""
63
63
self .name : str = Deps ._normalize (name )
64
64
self ._platforms : Set [Platform ] = platforms or set ()
65
- self ._target_versions = {p .minor_version for p in platforms or {}}
66
- self ._default_minor_version = None
67
- if platforms and len (self ._target_versions ) > 2 :
65
+ self ._target_versions = {(p .minor_version , p .micro_version ) for p in platforms or {}}
66
+ if platforms and len (self ._target_versions ) > 1 :
68
67
# TODO @aignas 2024-06-23: enable this to be set via a CLI arg
69
68
# for being more explicit.
70
- self ._default_minor_version = host_interpreter_minor_version ()
69
+ self ._default_minor_version , _ = host_interpreter_version ()
70
+ else :
71
+ self ._default_minor_version = None
71
72
72
73
if None in self ._target_versions and len (self ._target_versions ) > 2 :
73
74
raise ValueError (
@@ -88,8 +89,13 @@ def __init__(
88
89
# Then add all of the requirements in order
89
90
self ._deps : Set [str ] = set ()
90
91
self ._select : Dict [Platform , Set [str ]] = defaultdict (set )
92
+
93
+ reqs_by_name = {}
91
94
for req in reqs :
92
- self ._add_req (req , want_extras )
95
+ reqs_by_name .setdefault (req .name , []).append (req )
96
+
97
+ for reqs in reqs_by_name .values ():
98
+ self ._add_req (reqs , want_extras )
93
99
94
100
def _add (self , dep : str , platform : Optional [Platform ]):
95
101
dep = Deps ._normalize (dep )
@@ -123,50 +129,6 @@ def _add(self, dep: str, platform: Optional[Platform]):
123
129
# Add the platform-specific dep
124
130
self ._select [platform ].add (dep )
125
131
126
- # Add the dep to specializations of the given platform if they
127
- # exist in the select statement.
128
- for p in platform .all_specializations ():
129
- if p not in self ._select :
130
- continue
131
-
132
- self ._select [p ].add (dep )
133
-
134
- if len (self ._select [platform ]) == 1 :
135
- # We are adding a new item to the select and we need to ensure that
136
- # existing dependencies from less specialized platforms are propagated
137
- # to the newly added dependency set.
138
- for p , deps in self ._select .items ():
139
- # Check if the existing platform overlaps with the given platform
140
- if p == platform or platform not in p .all_specializations ():
141
- continue
142
-
143
- self ._select [platform ].update (self ._select [p ])
144
-
145
- def _maybe_add_common_dep (self , dep ):
146
- if len (self ._target_versions ) < 2 :
147
- return
148
-
149
- platforms = [Platform ()] + [
150
- Platform (minor_version = v ) for v in self ._target_versions
151
- ]
152
-
153
- # If the dep is targeting all target python versions, lets add it to
154
- # the common dependency list to simplify the select statements.
155
- for p in platforms :
156
- if p not in self ._select :
157
- return
158
-
159
- if dep not in self ._select [p ]:
160
- return
161
-
162
- # All of the python version-specific branches have the dep, so lets add
163
- # it to the common deps.
164
- self ._deps .add (dep )
165
- for p in platforms :
166
- self ._select [p ].remove (dep )
167
- if not self ._select [p ]:
168
- self ._select .pop (p )
169
-
170
132
@staticmethod
171
133
def _normalize (name : str ) -> str :
172
134
return re .sub (r"[-_.]+" , "_" , name ).lower ()
@@ -227,66 +189,40 @@ def _resolve_extras(
227
189
228
190
return extras
229
191
230
- def _add_req (self , req : Requirement , extras : Set [str ]) -> None :
231
- if req .marker is None :
232
- self ._add (req .name , None )
233
- return
192
+ def _add_req (self , reqs : List [Requirement ], extras : Set [str ]) -> None :
193
+ platforms_to_add = set ()
194
+ for req in reqs :
195
+ if req .marker is None :
196
+ self ._add (req .name , None )
197
+ return
234
198
235
- marker_str = str (req .marker )
199
+ for plat in self ._platforms :
200
+ if plat in platforms_to_add :
201
+ # marker evaluation is more expensive than this check
202
+ continue
236
203
237
- if not self . _platforms :
238
- if any ( req . marker . evaluate ({ "extra" : extra }) for extra in extras ) :
239
- self . _add ( req . name , None )
240
- return
204
+ added = False
205
+ for extra in extras :
206
+ if added :
207
+ break
241
208
242
- # NOTE @aignas 2023-12-08: in order to have reasonable select statements
243
- # we do have to have some parsing of the markers, so it begs the question
244
- # if packaging should be reimplemented in Starlark to have the best solution
245
- # for now we will implement it in Python and see what the best parsing result
246
- # can be before making this decision.
247
- match_os = any (
248
- tag in marker_str
249
- for tag in [
250
- "os_name" ,
251
- "sys_platform" ,
252
- "platform_system" ,
253
- ]
254
- )
255
- match_arch = "platform_machine" in marker_str
256
- match_version = "version" in marker_str
209
+ if req .marker .evaluate (plat .env_markers (extra )):
210
+ platforms_to_add .add (plat )
211
+ added = True
212
+ break
257
213
258
- if not (match_os or match_arch or match_version ):
259
- if any (req .marker .evaluate ({"extra" : extra }) for extra in extras ):
260
- self ._add (req .name , None )
214
+ if len (platforms_to_add ) == len (self ._platforms ):
215
+ # the dep is in all target platforms, let's just add it to the regular
216
+ # list
217
+ self ._add (req .name , None )
261
218
return
262
219
263
- for plat in self ._platforms :
264
- if not any (
265
- req .marker .evaluate (plat .env_markers (extra )) for extra in extras
266
- ):
267
- continue
268
-
269
- if match_arch and self ._default_minor_version :
220
+ for plat in platforms_to_add :
221
+ if self ._default_minor_version is not None :
270
222
self ._add (req .name , plat )
271
- if plat .minor_version == self ._default_minor_version :
272
- self ._add (req .name , Platform (plat .os , plat .arch ))
273
- elif match_arch :
274
- self ._add (req .name , Platform (plat .os , plat .arch ))
275
- elif match_os and self ._default_minor_version :
276
- self ._add (req .name , Platform (plat .os , minor_version = plat .minor_version ))
277
- if plat .minor_version == self ._default_minor_version :
278
- self ._add (req .name , Platform (plat .os ))
279
- elif match_os :
280
- self ._add (req .name , Platform (plat .os ))
281
- elif match_version and self ._default_minor_version :
282
- self ._add (req .name , Platform (minor_version = plat .minor_version ))
283
- if plat .minor_version == self ._default_minor_version :
284
- self ._add (req .name , Platform ())
285
- elif match_version :
286
- self ._add (req .name , None )
287
223
288
- # Merge to common if possible after processing all platforms
289
- self ._maybe_add_common_dep (req .name )
224
+ if self . _default_minor_version is None or plat . minor_version == self . _default_minor_version :
225
+ self ._add (req .name , Platform ( os = plat . os , arch = plat . arch ) )
290
226
291
227
def build (self ) -> FrozenDeps :
292
228
return FrozenDeps (
0 commit comments