13
13
from pip ._vendor .requests .models import Response
14
14
15
15
from pip ._internal .cli .progress_bars import get_download_progress_renderer
16
- from pip ._internal .exceptions import NetworkConnectionError
16
+ from pip ._internal .exceptions import CommandError , NetworkConnectionError
17
17
from pip ._internal .models .index import PyPI
18
18
from pip ._internal .models .link import Link
19
19
from pip ._internal .network .cache import is_from_cache
@@ -226,11 +226,20 @@ def __init__(
226
226
self ,
227
227
session : PipSession ,
228
228
progress_bar : str ,
229
+ max_parallelism : Optional [int ] = None ,
229
230
) -> None :
230
231
self ._session = session
231
232
# FIXME: support progress bar with parallel downloads!
232
233
logger .info ("Ignoring progress bar %s for parallel downloads" , progress_bar )
233
234
235
+ if max_parallelism is None :
236
+ max_parallelism = 1
237
+ if max_parallelism < 1 :
238
+ raise CommandError (
239
+ f"invalid batch download parallelism { max_parallelism } : must be >=1"
240
+ )
241
+ self ._max_parallelism : int = max_parallelism
242
+
234
243
def __call__ (
235
244
self , links : Iterable [Link ], location : Path
236
245
) -> Iterable [Tuple [Link , Tuple [Path , Optional [str ]]]]:
@@ -254,7 +263,7 @@ def __call__(
254
263
q : "Queue[Union[Tuple[Link, Path, Optional[str]], BaseException]]" = Queue ()
255
264
event = Event ()
256
265
# Limit downloads to 10 at a time so we can reuse our connection pool.
257
- semaphore = Semaphore (value = 10 )
266
+ semaphore = Semaphore (value = self . _max_parallelism )
258
267
259
268
# Distribute request i/o across equivalent threads.
260
269
# NB: event-based/async is likely a better model than thread-per-request, but
0 commit comments