@@ -67,20 +67,17 @@ def _create_whl_repos(
6767 * ,
6868 pip_attr ,
6969 whl_overrides ,
70- simpleapi_cache ,
7170 evaluate_markers = evaluate_markers ,
7271 available_interpreters = INTERPRETER_LABELS ,
73- simpleapi_download = simpleapi_download ):
72+ get_index_urls = None ):
7473 """create all of the whl repositories
7574
7675 Args:
7776 module_ctx: {type}`module_ctx`.
7877 pip_attr: {type}`struct` - the struct that comes from the tag class iteration.
7978 whl_overrides: {type}`dict[str, struct]` - per-wheel overrides.
80- simpleapi_cache: {type}`dict` - an opaque dictionary used for caching the results from calling
81- SimpleAPI evaluating all of the tag class invocations {bzl:obj}`pip.parse`.
8279 evaluate_markers: the function to use to evaluate markers.
83- simpleapi_download: Used for testing overrides
80+ get_index_urls: A function used to get the index URLs
8481 available_interpreters: {type}`dict[str, Label]` The dictionary of available
8582 interpreters that have been registered using the `python` bzlmod extension.
8683 The keys are in the form `python_{snake_case_version}_host`. This is to be
@@ -96,12 +93,9 @@ def _create_whl_repos(
9693 aparent repository names for the hub repo and the values are the
9794 arguments that will be passed to {bzl:obj}`whl_library` repository
9895 rule.
99- is_reproducible: {type}`bool` set to True if does not make calls to the
100- internet to evaluate the requirements files.
10196 """
10297 logger = repo_utils .logger (module_ctx , "pypi:create_whl_repos" )
10398 python_interpreter_target = pip_attr .python_interpreter_target
104- is_reproducible = True
10599
106100 # containers to aggregate outputs from this function
107101 whl_map = {}
@@ -158,26 +152,6 @@ def _create_whl_repos(
158152 whl_group_mapping = {}
159153 requirement_cycles = {}
160154
161- # Create a new wheel library for each of the different whls
162-
163- get_index_urls = None
164- if pip_attr .experimental_index_url :
165- get_index_urls = lambda ctx , distributions : simpleapi_download (
166- ctx ,
167- attr = struct (
168- index_url = pip_attr .experimental_index_url ,
169- extra_index_urls = pip_attr .experimental_extra_index_urls or [],
170- index_url_overrides = pip_attr .experimental_index_url_overrides or {},
171- sources = distributions ,
172- envsubst = pip_attr .envsubst ,
173- # Auth related info
174- netrc = pip_attr .netrc ,
175- auth_patterns = pip_attr .auth_patterns ,
176- ),
177- cache = simpleapi_cache ,
178- parallel_download = pip_attr .parallel_download ,
179- )
180-
181155 requirements_by_platform = parse_requirements (
182156 module_ctx ,
183157 requirements_by_platform = requirements_files_by_platform (
@@ -258,77 +232,27 @@ def _create_whl_repos(
258232 if v != default
259233 })
260234
261- # TODO @aignas 2024-05-26: move to a separate function
262235 for requirement in requirements :
263- dists = requirement .whls
264- if not pip_attr .download_only and requirement .sdist :
265- dists = dists + [requirement .sdist ]
266-
267- for distribution in dists :
268- args = dict (whl_library_args )
269- if pip_attr .netrc :
270- args ["netrc" ] = pip_attr .netrc
271- if pip_attr .auth_patterns :
272- args ["auth_patterns" ] = pip_attr .auth_patterns
273-
274- if not distribution .filename .endswith (".whl" ):
275- # pip is not used to download wheels and the python
276- # `whl_library` helpers are only extracting things, however
277- # for sdists, they will be built by `pip`, so we still
278- # need to pass the extra args there.
279- args ["extra_pip_args" ] = requirement .extra_pip_args
280-
281- # This is no-op because pip is not used to download the wheel.
282- args .pop ("download_only" , None )
283-
284- repo_name = whl_repo_name (pip_name , distribution .filename , distribution .sha256 )
285- args ["requirement" ] = requirement .srcs .requirement
286- args ["urls" ] = [distribution .url ]
287- args ["sha256" ] = distribution .sha256
288- args ["filename" ] = distribution .filename
289- args ["experimental_target_platforms" ] = requirement .target_platforms
290-
291- # Pure python wheels or sdists may need to have a platform here
292- target_platforms = None
293- if distribution .filename .endswith ("-any.whl" ) or not distribution .filename .endswith (".whl" ):
294- if len (requirements ) > 1 :
295- target_platforms = requirement .target_platforms
236+ for repo_name , (args , config_setting ) in _whl_repos (
237+ requirement = requirement ,
238+ whl_library_args = whl_library_args ,
239+ download_only = pip_attr .download_only ,
240+ netrc = pip_attr .netrc ,
241+ auth_patterns = pip_attr .auth_patterns ,
242+ python_version = major_minor ,
243+ multiple_requirements_for_whl = len (requirements ) > 1. ,
244+ ).items ():
245+ repo_name = "{}_{}" .format (pip_name , repo_name )
246+ if repo_name in whl_libraries :
247+ fail ("Attempting to creating a duplicate library {} for {}" .format (
248+ repo_name ,
249+ whl_name ,
250+ ))
296251
297252 whl_libraries [repo_name ] = args
298-
299- whl_map .setdefault (whl_name , {})[whl_config_setting (
300- version = major_minor ,
301- filename = distribution .filename ,
302- target_platforms = target_platforms ,
303- )] = repo_name
304-
305- if dists :
306- is_reproducible = False
307- continue
308-
309- # Fallback to a pip-installed wheel
310- args = dict (whl_library_args ) # make a copy
311- args ["requirement" ] = requirement .srcs .requirement_line
312- if requirement .extra_pip_args :
313- args ["extra_pip_args" ] = requirement .extra_pip_args
314-
315- if pip_attr .download_only :
316- args .setdefault ("experimental_target_platforms" , requirement .target_platforms )
317-
318- target_platforms = requirement .target_platforms if len (requirements ) > 1 else []
319- repo_name = pypi_repo_name (
320- pip_name ,
321- whl_name ,
322- * target_platforms
323- )
324- whl_libraries [repo_name ] = args
325- whl_map .setdefault (whl_name , {})[whl_config_setting (
326- version = major_minor ,
327- target_platforms = target_platforms or None ,
328- )] = repo_name
253+ whl_map .setdefault (whl_name , {})[config_setting ] = repo_name
329254
330255 return struct (
331- is_reproducible = is_reproducible ,
332256 whl_map = whl_map ,
333257 exposed_packages = {
334258 whl_name : None
@@ -339,11 +263,88 @@ def _create_whl_repos(
339263 whl_libraries = whl_libraries ,
340264 )
341265
342- def parse_modules (module_ctx , _fail = fail , ** kwargs ):
266+ def _whl_repos (* , requirement , whl_library_args , download_only , netrc , auth_patterns , multiple_requirements_for_whl = False , python_version ):
267+ ret = {}
268+
269+ dists = requirement .whls
270+ if not download_only and requirement .sdist :
271+ dists = dists + [requirement .sdist ]
272+
273+ for distribution in dists :
274+ args = dict (whl_library_args )
275+ if netrc :
276+ args ["netrc" ] = netrc
277+ if auth_patterns :
278+ args ["auth_patterns" ] = auth_patterns
279+
280+ if not distribution .filename .endswith (".whl" ):
281+ # pip is not used to download wheels and the python
282+ # `whl_library` helpers are only extracting things, however
283+ # for sdists, they will be built by `pip`, so we still
284+ # need to pass the extra args there.
285+ args ["extra_pip_args" ] = requirement .extra_pip_args
286+
287+ # This is no-op because pip is not used to download the wheel.
288+ args .pop ("download_only" , None )
289+
290+ args ["requirement" ] = requirement .srcs .requirement
291+ args ["urls" ] = [distribution .url ]
292+ args ["sha256" ] = distribution .sha256
293+ args ["filename" ] = distribution .filename
294+ args ["experimental_target_platforms" ] = requirement .target_platforms
295+
296+ # Pure python wheels or sdists may need to have a platform here
297+ target_platforms = None
298+ if distribution .filename .endswith ("-any.whl" ) or not distribution .filename .endswith (".whl" ):
299+ if multiple_requirements_for_whl :
300+ target_platforms = requirement .target_platforms
301+
302+ repo_name = whl_repo_name (
303+ distribution .filename ,
304+ distribution .sha256 ,
305+ )
306+ ret [repo_name ] = (
307+ args ,
308+ whl_config_setting (
309+ version = python_version ,
310+ filename = distribution .filename ,
311+ target_platforms = target_platforms ,
312+ ),
313+ )
314+
315+ if ret :
316+ return ret
317+
318+ # Fallback to a pip-installed wheel
319+ args = dict (whl_library_args ) # make a copy
320+ args ["requirement" ] = requirement .srcs .requirement_line
321+ if requirement .extra_pip_args :
322+ args ["extra_pip_args" ] = requirement .extra_pip_args
323+
324+ if download_only :
325+ args .setdefault ("experimental_target_platforms" , requirement .target_platforms )
326+
327+ target_platforms = requirement .target_platforms if multiple_requirements_for_whl else []
328+ repo_name = pypi_repo_name (
329+ normalize_name (requirement .distribution ),
330+ * target_platforms
331+ )
332+ ret [repo_name ] = (
333+ args ,
334+ whl_config_setting (
335+ version = python_version ,
336+ target_platforms = target_platforms or None ,
337+ ),
338+ )
339+
340+ return ret
341+
342+ def parse_modules (module_ctx , _fail = fail , simpleapi_download = simpleapi_download , ** kwargs ):
343343 """Implementation of parsing the tag classes for the extension and return a struct for registering repositories.
344344
345345 Args:
346346 module_ctx: {type}`module_ctx` module context.
347+ simpleapi_download: Used for testing overrides
347348 _fail: {type}`function` the failure function, mainly for testing.
348349 **kwargs: Extra arguments passed to the layers below.
349350
@@ -460,10 +461,29 @@ You cannot use both the additive_build_content and additive_build_content_file a
460461 else :
461462 pip_hub_map [pip_attr .hub_name ].python_versions .append (pip_attr .python_version )
462463
464+ get_index_urls = None
465+ if pip_attr .experimental_index_url :
466+ is_reproducible = False
467+ get_index_urls = lambda ctx , distributions : simpleapi_download (
468+ ctx ,
469+ attr = struct (
470+ index_url = pip_attr .experimental_index_url ,
471+ extra_index_urls = pip_attr .experimental_extra_index_urls or [],
472+ index_url_overrides = pip_attr .experimental_index_url_overrides or {},
473+ sources = distributions ,
474+ envsubst = pip_attr .envsubst ,
475+ # Auth related info
476+ netrc = pip_attr .netrc ,
477+ auth_patterns = pip_attr .auth_patterns ,
478+ ),
479+ cache = simpleapi_cache ,
480+ parallel_download = pip_attr .parallel_download ,
481+ )
482+
463483 out = _create_whl_repos (
464484 module_ctx ,
465485 pip_attr = pip_attr ,
466- simpleapi_cache = simpleapi_cache ,
486+ get_index_urls = get_index_urls ,
467487 whl_overrides = whl_overrides ,
468488 ** kwargs
469489 )
@@ -476,7 +496,6 @@ You cannot use both the additive_build_content and additive_build_content_file a
476496 extra_aliases [hub_name ].setdefault (whl_name , {}).update (aliases )
477497 exposed_packages .setdefault (hub_name , {}).update (out .exposed_packages )
478498 whl_libraries .update (out .whl_libraries )
479- is_reproducible = is_reproducible and out .is_reproducible
480499
481500 # TODO @aignas 2024-04-05: how do we support different requirement
482501 # cycles for different abis/oses? For now we will need the users to
0 commit comments