Skip to content

Commit 4f3a184

Browse files
authored
Merge pull request #12586 from arenasys/raw-progress-bar
2 parents 0a6662e + 36825ec commit 4f3a184

File tree

4 files changed

+35
-2
lines changed

4 files changed

+35
-2
lines changed

docs/html/user_guide.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -856,6 +856,12 @@ We are using `freeze`_ here which outputs installed packages in requirements for
856856

857857
reqs = subprocess.check_output([sys.executable, '-m', 'pip', 'freeze'])
858858

859+
To programmatically monitor download progress use the ``--progress-bar=raw`` option.
860+
This will print lines to stdout in the format ``Progress CURRENT of TOTAL``, where
861+
``CURRENT`` and ``TOTAL`` are integers and the unit is bytes.
862+
If the real total is unknown then ``TOTAL`` is set to ``0``. Be aware that the
863+
specific formatting of pip's outputs are *not* guaranteed to be the same in future versions.
864+
859865
If you don't want to use pip's command line functionality, but are rather
860866
trying to implement code that works with Python packages, their metadata, or
861867
PyPI, then you should consider other, supported, packages that offer this type

news/11508.feature.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Add a 'raw' progress_bar type for simple and parsable download progress reports

src/pip/_internal/cli/cmdoptions.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -226,9 +226,9 @@ class PipOption(Option):
226226
"--progress-bar",
227227
dest="progress_bar",
228228
type="choice",
229-
choices=["on", "off"],
229+
choices=["on", "off", "raw"],
230230
default="on",
231-
help="Specify whether the progress bar should be used [on, off] (default: on)",
231+
help="Specify whether the progress bar should be used [on, off, raw] (default: on)",
232232
)
233233

234234
log: Callable[..., Option] = partial(

src/pip/_internal/cli/progress_bars.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import functools
2+
import sys
23
from typing import Callable, Generator, Iterable, Iterator, Optional, Tuple
34

45
from pip._vendor.rich.progress import (
@@ -14,6 +15,7 @@
1415
TransferSpeedColumn,
1516
)
1617

18+
from pip._internal.cli.spinners import RateLimiter
1719
from pip._internal.utils.logging import get_indentation
1820

1921
DownloadProgressRenderer = Callable[[Iterable[bytes]], Iterator[bytes]]
@@ -55,6 +57,28 @@ def _rich_progress_bar(
5557
progress.update(task_id, advance=len(chunk))
5658

5759

60+
def _raw_progress_bar(
61+
iterable: Iterable[bytes],
62+
*,
63+
size: Optional[int],
64+
) -> Generator[bytes, None, None]:
65+
def write_progress(current: int, total: int) -> None:
66+
sys.stdout.write("Progress %d of %d\n" % (current, total))
67+
sys.stdout.flush()
68+
69+
current = 0
70+
total = size or 0
71+
rate_limiter = RateLimiter(0.25)
72+
73+
write_progress(current, total)
74+
for chunk in iterable:
75+
current += len(chunk)
76+
if rate_limiter.ready() or current == total:
77+
write_progress(current, total)
78+
rate_limiter.reset()
79+
yield chunk
80+
81+
5882
def get_download_progress_renderer(
5983
*, bar_type: str, size: Optional[int] = None
6084
) -> DownloadProgressRenderer:
@@ -64,5 +88,7 @@ def get_download_progress_renderer(
6488
"""
6589
if bar_type == "on":
6690
return functools.partial(_rich_progress_bar, bar_type=bar_type, size=size)
91+
elif bar_type == "raw":
92+
return functools.partial(_raw_progress_bar, size=size)
6793
else:
6894
return iter # no-op, when passed an iterator

0 commit comments

Comments
 (0)