2727
2828from python .private .pypi .whl_installer .platform import (
2929 Platform ,
30- host_interpreter_minor_version ,
30+ host_interpreter_version ,
3131)
3232
3333
@@ -62,12 +62,13 @@ def __init__(
6262 """
6363 self .name : str = Deps ._normalize (name )
6464 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 :
6867 # TODO @aignas 2024-06-23: enable this to be set via a CLI arg
6968 # 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
7172
7273 if None in self ._target_versions and len (self ._target_versions ) > 2 :
7374 raise ValueError (
@@ -88,8 +89,13 @@ def __init__(
8889 # Then add all of the requirements in order
8990 self ._deps : Set [str ] = set ()
9091 self ._select : Dict [Platform , Set [str ]] = defaultdict (set )
92+
93+ reqs_by_name = {}
9194 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 )
9399
94100 def _add (self , dep : str , platform : Optional [Platform ]):
95101 dep = Deps ._normalize (dep )
@@ -123,50 +129,6 @@ def _add(self, dep: str, platform: Optional[Platform]):
123129 # Add the platform-specific dep
124130 self ._select [platform ].add (dep )
125131
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-
170132 @staticmethod
171133 def _normalize (name : str ) -> str :
172134 return re .sub (r"[-_.]+" , "_" , name ).lower ()
@@ -227,66 +189,40 @@ def _resolve_extras(
227189
228190 return extras
229191
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
234198
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
236203
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
241208
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
257213
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 )
261218 return
262219
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 :
270222 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 )
287223
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 ) )
290226
291227 def build (self ) -> FrozenDeps :
292228 return FrozenDeps (
0 commit comments