@@ -86,6 +86,7 @@ def parse_requirements(
8686 return _parse_uv_lock (
8787 uv_lock = uv_lock ,
8888 all_platforms = _get_all_platforms (requirements_by_platform ) if requirements_by_platform else sorted (platforms .keys ()),
89+ platforms = platforms ,
8990 extra_pip_args = extra_pip_args ,
9091 logger = logger ,
9192 )
@@ -108,12 +109,13 @@ def _get_all_platforms(requirements_by_platform):
108109 all_platforms [p ] = None
109110 return sorted (all_platforms )
110111
111- def _parse_uv_lock (uv_lock , all_platforms , logger , extra_pip_args = None ):
112+ def _parse_uv_lock (uv_lock , all_platforms , platforms , logger , extra_pip_args = None ):
112113 """Parse decoded uv.lock TOML dict and build the same return structs as parse_requirements.
113114
114115 Args:
115116 uv_lock: {type}`dict` A decoded dictionary representing the uv.lock contents.
116117 all_platforms: {type}`list[str]` The list of all platform names.
118+ platforms: {type}`dict` The target platform descriptions.
117119 logger: {type}`struct` A logger for diagnostic messages.
118120 extra_pip_args: {type}`list[str] | None` Extra pip arguments to pass through.
119121
@@ -122,6 +124,22 @@ def _parse_uv_lock(uv_lock, all_platforms, logger, extra_pip_args = None):
122124 """
123125 uv_packages = {}
124126 for pkg in uv_lock .get ("package" , []):
127+ valid_platforms = []
128+ if all_platforms :
129+ markers = pkg .get ("resolution-markers" , [])
130+ for plat_name in all_platforms :
131+ plat_env = platforms .get (plat_name )
132+ if not markers or not plat_env :
133+ valid_platforms .append (plat_name )
134+ else :
135+ for m in markers :
136+ if evaluate (m , env = plat_env .env ):
137+ valid_platforms .append (plat_name )
138+ break
139+
140+ if not valid_platforms :
141+ continue
142+
125143 name = pkg ["name" ]
126144 version = pkg ["version" ]
127145 norm_name = normalize_name (name )
@@ -140,40 +158,79 @@ def _parse_uv_lock(uv_lock, all_platforms, logger, extra_pip_args = None):
140158 if extra not in entry ["extras" ]:
141159 entry ["extras" ][extra ] = None
142160
143- seen = {}
161+ wheels = []
144162 for wheel in pkg .get ("wheels" , []):
145163 sha256 = wheel .get ("hash" , "" ).removeprefix ("sha256:" )
146164 url = wheel ["url" ]
147165 _ , _ , filename = url .rpartition ("/" )
148- key = (filename , sha256 )
149- if key not in seen :
150- seen [key ] = None
166+ wheels .append (struct (
167+ filename = filename ,
168+ sha256 = sha256 ,
169+ url = url ,
170+ target_platforms = [],
171+ ))
172+
173+ matched_by_any = {}
174+ if all_platforms :
175+ for plat_name in valid_platforms :
176+ plat_env = platforms .get (plat_name )
177+ if not plat_env or not getattr (plat_env , "whl_platform_tags" , None ):
178+ for w in wheels :
179+ if plat_name not in w .target_platforms :
180+ w .target_platforms .append (plat_name )
181+ matched_by_any [plat_name ] = None
182+ elif wheels :
183+ selected = select_whl (
184+ whls = wheels ,
185+ python_version = plat_env .env ["python_full_version" ],
186+ implementation_name = plat_env .env .get ("implementation_name" , "cpython" ),
187+ whl_abi_tags = plat_env .whl_abi_tags ,
188+ whl_platform_tags = plat_env .whl_platform_tags ,
189+ logger = logger ,
190+ )
191+ if selected :
192+ if plat_name not in selected .target_platforms :
193+ selected .target_platforms .append (plat_name )
194+ matched_by_any [plat_name ] = None
195+
196+ seen = {}
197+ for w in wheels :
198+ if not all_platforms or w .target_platforms :
199+ key = (w .filename , w .sha256 )
200+ if key not in seen :
201+ seen [key ] = None
202+ entry ["src_entries" ].append (struct (
203+ version = version ,
204+ sha256 = w .sha256 ,
205+ url = w .url ,
206+ filename = w .filename ,
207+ # NOTE @aignas 2026-05-17: we don't know if it is yanked because we are not
208+ # checking the SimpleAPI, maybe we should?
209+ yanked = None ,
210+ target_platforms = w .target_platforms ,
211+ ))
212+
213+ fallback_platforms = [p for p in valid_platforms if p not in matched_by_any ] if all_platforms else []
214+ sdist = pkg .get ("sdist" , None )
215+ if sdist :
216+ if not all_platforms or fallback_platforms :
217+ sha256 = sdist .get ("hash" , "" ).removeprefix ("sha256:" )
218+ url = sdist ["url" ]
219+ _ , _ , filename = url .rpartition ("/" )
151220 entry ["src_entries" ].append (struct (
152221 version = version ,
153222 sha256 = sha256 ,
154223 url = url ,
155224 filename = filename ,
156- # NOTE @aignas 2026-05-17: we don't know if it is yanked because we are not
157- # checking the SimpleAPI, maybe we should?
158225 yanked = None ,
226+ target_platforms = fallback_platforms ,
159227 ))
160-
161- sdist = pkg .get ("sdist" , None )
162- if sdist :
163- sha256 = sdist .get ("hash" , "" ).removeprefix ("sha256:" )
164- url = sdist ["url" ]
165- _ , _ , filename = url .rpartition ("/" )
166- entry ["src_entries" ].append (struct (
167- version = version ,
168- sha256 = sha256 ,
169- url = url ,
170- filename = filename ,
171- yanked = None ,
172- ))
173228 elif pkg .get ("source" , {}).get ("git" ):
174- _add_vcs_entry (entry , version , pkg ["source" ])
229+ if not all_platforms or fallback_platforms :
230+ _add_vcs_entry (entry , version , pkg ["source" ], fallback_platforms )
175231 elif pkg .get ("source" , {}).get ("url" ):
176- _add_direct_url_entry (entry , version , pkg ["source" ])
232+ if not all_platforms or fallback_platforms :
233+ _add_direct_url_entry (entry , version , pkg ["source" ], fallback_platforms )
177234
178235 ret = []
179236 for norm_name , info in sorted (uv_packages .items ()):
@@ -192,7 +249,7 @@ def _parse_uv_lock(uv_lock, all_platforms, logger, extra_pip_args = None):
192249 distribution = info ["distribution" ],
193250 extra_pip_args = extra_pip_args or [],
194251 requirement_line = requirement_line ,
195- target_platforms = list ( all_platforms ) ,
252+ target_platforms = src_entry . target_platforms ,
196253 filename = src_entry .filename ,
197254 sha256 = src_entry .sha256 ,
198255 url = src_entry .url ,
@@ -214,13 +271,14 @@ def _parse_uv_lock(uv_lock, all_platforms, logger, extra_pip_args = None):
214271 logger .debug (lambda : "Parsed {} packages from uv.lock" .format (len (ret )))
215272 return ret
216273
217- def _add_vcs_entry (entry , version , source ):
274+ def _add_vcs_entry (entry , version , source , valid_platforms ):
218275 """Add a VCS entry from a uv.lock source.
219276
220277 Args:
221278 entry: {type}`dict` The package entry being built.
222279 version: {type}`str` The package version.
223280 source: {type}`dict` The source dict from uv.lock (e.g. {"git": url}).
281+ valid_platforms: {type}`list[str]` Valid target platforms.
224282 """
225283 url = source ["git" ]
226284 _ , _ , filename = url .rpartition ("/" )
@@ -230,15 +288,17 @@ def _add_vcs_entry(entry, version, source):
230288 url = url ,
231289 filename = filename ,
232290 yanked = None ,
291+ target_platforms = valid_platforms ,
233292 ))
234293
235- def _add_direct_url_entry (entry , version , source ):
294+ def _add_direct_url_entry (entry , version , source , valid_platforms ):
236295 """Add a direct URL entry from a uv.lock source.
237296
238297 Args:
239298 entry: {type}`dict` The package entry being built.
240299 version: {type}`str` The package version.
241300 source: {type}`dict` The source dict from uv.lock (e.g. {"url": url}).
301+ valid_platforms: {type}`list[str]` Valid target platforms.
242302 """
243303 url = source ["url" ]
244304 _ , _ , filename = url .rpartition ("/" )
@@ -248,6 +308,7 @@ def _add_direct_url_entry(entry, version, source):
248308 url = url ,
249309 filename = filename ,
250310 yanked = None ,
311+ target_platforms = valid_platforms ,
251312 ))
252313
253314def _parse_requirements_from_req_files (
0 commit comments