Skip to content

Commit f42fb29

Browse files
quiet all progress output from -q, and write progress to stderr
1 parent 61acf01 commit f42fb29

File tree

5 files changed

+64
-20
lines changed

5 files changed

+64
-20
lines changed

src/pip/_internal/cli/progress_bars.py

+41-14
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ def _rich_progress_bar(
7979
*,
8080
bar_type: str,
8181
size: int,
82+
quiet: bool,
8283
) -> Generator[bytes, None, None]:
8384
assert bar_type == "on", "This should only be used in the default mode."
8485

@@ -89,7 +90,9 @@ def _rich_progress_bar(
8990
total = size
9091
columns = _known_size_columns()
9192

92-
progress = Progress(*columns, console=Console(stderr=True), refresh_per_second=5)
93+
progress = Progress(
94+
*columns, console=Console(stderr=True, quiet=quiet), refresh_per_second=5
95+
)
9396
task_id = progress.add_task(_progress_task_prefix(), total=total)
9497
with progress:
9598
for chunk in iterable:
@@ -101,12 +104,15 @@ def _raw_progress_bar(
101104
iterable: Iterable[bytes],
102105
*,
103106
size: Optional[int],
107+
quiet: bool,
104108
) -> Generator[bytes, None, None]:
105109
prefix = _progress_task_prefix()
106110

107111
def write_progress(current: int, total: int) -> None:
108-
sys.stdout.write(f"{prefix}Progress {current} of {total}\n")
109-
sys.stdout.flush()
112+
if quiet:
113+
return
114+
sys.stderr.write(f"{prefix}Progress {current} of {total}\n")
115+
sys.stderr.flush()
110116

111117
current = 0
112118
total = size or 0
@@ -122,16 +128,21 @@ def write_progress(current: int, total: int) -> None:
122128

123129

124130
def get_download_progress_renderer(
125-
*, bar_type: str, size: Optional[int] = None
131+
*,
132+
bar_type: str,
133+
size: Optional[int] = None,
134+
quiet: bool = False,
126135
) -> DownloadProgressRenderer:
127136
"""Get an object that can be used to render the download progress.
128137
129138
Returns a callable, that takes an iterable to "wrap".
130139
"""
131140
if bar_type == "on":
132-
return functools.partial(_rich_progress_bar, bar_type=bar_type, size=size)
141+
return functools.partial(
142+
_rich_progress_bar, bar_type=bar_type, size=size, quiet=quiet
143+
)
133144
elif bar_type == "raw":
134-
return functools.partial(_raw_progress_bar, size=size)
145+
return functools.partial(_raw_progress_bar, size=size, quiet=quiet)
135146
else:
136147
return iter # no-op, when passed an iterator
137148

@@ -158,7 +169,10 @@ def __exit__(self, ty: Any, val: Any, tb: Any) -> None: ...
158169
@classmethod
159170
@abc.abstractmethod
160171
def create(
161-
cls, num_tasks: int, known_total_length: Optional[int]
172+
cls,
173+
num_tasks: int,
174+
known_total_length: Optional[int],
175+
quiet: bool,
162176
) -> "BatchedProgress": ...
163177

164178
@classmethod
@@ -191,7 +205,10 @@ def __exit__(self, ty: Any, val: Any, tb: Any) -> None:
191205

192206
@classmethod
193207
def create(
194-
cls, num_tasks: int, known_total_length: Optional[int]
208+
cls,
209+
num_tasks: int,
210+
known_total_length: Optional[int],
211+
quiet: bool,
195212
) -> "BatchedNoOpProgressBar":
196213
return cls()
197214

@@ -201,20 +218,24 @@ def __init__(
201218
self,
202219
total_bytes: Optional[int],
203220
prefix: str,
221+
quiet: bool,
204222
) -> None:
205223
self._total_bytes = total_bytes
206224
self._prefix = prefix
207225
self._total_progress = 0
208226
self._subtasks: List[Tuple[str, Optional[int]]] = []
209227
self._rate_limiter = RateLimiter(0.25)
210-
self._stream = sys.stdout
228+
self._stream = sys.stderr
229+
self._quiet = quiet
211230

212231
def add_subtask(self, description: str, total: Optional[int]) -> TaskID:
213232
task_id = len(self._subtasks)
214233
self._subtasks.append((description, total))
215234
return TaskID(task_id)
216235

217236
def _write_immediate(self, line: str) -> None:
237+
if self._quiet:
238+
return
218239
self._stream.write(f"{self._prefix}{line}\n")
219240
self._stream.flush()
220241

@@ -266,10 +287,10 @@ def __exit__(self, ty: Any, val: Any, tb: Any) -> None:
266287

267288
@classmethod
268289
def create(
269-
cls, num_tasks: int, known_total_length: Optional[int]
290+
cls, num_tasks: int, known_total_length: Optional[int], quiet: bool
270291
) -> "BatchedRawProgressBar":
271292
prefix = _progress_task_prefix()
272-
return cls(known_total_length, prefix)
293+
return cls(known_total_length, prefix, quiet=quiet)
273294

274295

275296
class BatchedRichProgressBar(BatchedProgress):
@@ -279,11 +300,13 @@ def __init__(
279300
total_task_id: TaskID,
280301
progress: Progress,
281302
total_bytes_task_id: TaskID,
303+
quiet: bool,
282304
) -> None:
283305
self._task_progress = task_progress
284306
self._total_task_id = total_task_id
285307
self._progress = progress
286308
self._total_bytes_task_id = total_bytes_task_id
309+
self._quiet = quiet
287310
self._live: Optional[Live] = None
288311

289312
_TRIM_LEN = 20
@@ -328,7 +351,9 @@ def __enter__(self) -> "BatchedRichProgressBar":
328351
padding=(0, 0),
329352
)
330353
)
331-
self._live = Live(table, console=Console(stderr=True), refresh_per_second=5)
354+
self._live = Live(
355+
table, console=Console(stderr=True, quiet=self._quiet), refresh_per_second=5
356+
)
332357
self._task_progress.start_task(self._total_task_id)
333358
self._progress.start_task(self._total_bytes_task_id)
334359
self._live.__enter__()
@@ -340,7 +365,7 @@ def __exit__(self, ty: Any, val: Any, tb: Any) -> None:
340365

341366
@classmethod
342367
def create(
343-
cls, num_tasks: int, known_total_length: Optional[int]
368+
cls, num_tasks: int, known_total_length: Optional[int], quiet: bool
344369
) -> "BatchedRichProgressBar":
345370
task_columns = _task_columns()
346371
task_progress = Progress(*task_columns)
@@ -365,4 +390,6 @@ def create(
365390
total=total,
366391
)
367392

368-
return cls(task_progress, total_task_id, progress, total_bytes_task_id)
393+
return cls(
394+
task_progress, total_task_id, progress, total_bytes_task_id, quiet=quiet
395+
)

src/pip/_internal/cli/req_command.py

+1
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,7 @@ def make_requirement_preparer(
142142
use_user_site=use_user_site,
143143
lazy_wheel=lazy_wheel,
144144
verbosity=verbosity,
145+
quietness=options.quiet,
145146
batch_download_parallelism=batch_download_parallelism,
146147
legacy_resolver=legacy_resolver,
147148
)

src/pip/_internal/network/download.py

+14-3
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ def _prepare_download(
6464
resp: Response,
6565
link: Link,
6666
progress_bar: str,
67+
quiet: bool = False,
6768
) -> Iterable[bytes]:
6869
total_length = _get_http_response_size(resp)
6970

@@ -85,7 +86,9 @@ def _prepare_download(
8586
if not show_progress:
8687
return chunks
8788

88-
renderer = get_download_progress_renderer(bar_type=progress_bar, size=total_length)
89+
renderer = get_download_progress_renderer(
90+
bar_type=progress_bar, size=total_length, quiet=quiet
91+
)
8992
return renderer(chunks)
9093

9194

@@ -163,9 +166,11 @@ def __init__(
163166
self,
164167
session: PipSession,
165168
progress_bar: str,
169+
quiet: bool = False,
166170
) -> None:
167171
self._session = session
168172
self._progress_bar = progress_bar
173+
self._quiet = quiet
169174

170175
def __call__(self, link: Link, location: str) -> Tuple[str, str]:
171176
"""Download the file given by link into location."""
@@ -181,7 +186,7 @@ def __call__(self, link: Link, location: str) -> Tuple[str, str]:
181186
filename = _get_http_response_filename(resp.headers, resp.url, link)
182187
filepath = os.path.join(location, filename)
183188

184-
chunks = _prepare_download(resp, link, self._progress_bar)
189+
chunks = _prepare_download(resp, link, self._progress_bar, self._quiet)
185190
with open(filepath, "wb") as content_file:
186191
for chunk in chunks:
187192
content_file.write(chunk)
@@ -291,10 +296,12 @@ def __init__(
291296
self,
292297
session: PipSession,
293298
progress_bar: str,
299+
quiet: bool = False,
294300
max_parallelism: Optional[int] = None,
295301
) -> None:
296302
self._session = session
297303
self._progress_bar = progress_bar
304+
self._quiet = quiet
298305

299306
if max_parallelism is None:
300307
max_parallelism = 1
@@ -331,7 +338,11 @@ def __call__(
331338
semaphore = Semaphore(value=self._max_parallelism)
332339
batched_progress = BatchedProgress.select_progress_bar(
333340
self._progress_bar
334-
).create(num_tasks=total_downloads, known_total_length=total_length)
341+
).create(
342+
num_tasks=total_downloads,
343+
known_total_length=total_length,
344+
quiet=self._quiet,
345+
)
335346

336347
# Distribute request i/o across equivalent threads.
337348
# NB: event-based/async is likely a better model than thread-per-request, but

src/pip/_internal/operations/prepare.py

+7-3
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ def _check_download_dir(
215215
class RequirementPreparer:
216216
"""Prepares a Requirement"""
217217

218-
def __init__(
218+
def __init__( # noqa: PLR0913
219219
self,
220220
build_dir: str,
221221
download_dir: Optional[str],
@@ -230,6 +230,7 @@ def __init__(
230230
use_user_site: bool,
231231
lazy_wheel: bool,
232232
verbosity: int,
233+
quietness: int,
233234
batch_download_parallelism: Optional[int],
234235
legacy_resolver: bool,
235236
) -> None:
@@ -239,9 +240,12 @@ def __init__(
239240
self.build_dir = build_dir
240241
self.build_tracker = build_tracker
241242
self._session = session
242-
self._download = Downloader(session, progress_bar)
243+
self._download = Downloader(session, progress_bar, quiet=quietness > 0)
243244
self._batch_download = BatchDownloader(
244-
session, progress_bar, max_parallelism=batch_download_parallelism
245+
session,
246+
progress_bar,
247+
quiet=quietness > 0,
248+
max_parallelism=batch_download_parallelism,
245249
)
246250
self.finder = finder
247251

tests/unit/test_req.py

+1
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ def _basic_resolver(
106106
use_user_site=False,
107107
lazy_wheel=False,
108108
verbosity=0,
109+
quietness=0,
109110
batch_download_parallelism=None,
110111
legacy_resolver=True,
111112
)

0 commit comments

Comments
 (0)