Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Show install progress when using --progress-bar=raw #12601

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions news/12601.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Output install progress when 'raw' progress_bar type is in use
45 changes: 38 additions & 7 deletions src/pip/_internal/cli/progress_bars.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
import functools
import sys
from typing import Callable, Generator, Iterable, Iterator, Optional, Tuple
from typing import (
Callable,
Generator,
Iterable,
Iterator,
Optional,
Sized,
Tuple,
TypeVar,
)

from pip._vendor.rich.progress import (
BarColumn,
Expand All @@ -16,9 +25,12 @@
)

from pip._internal.cli.spinners import RateLimiter
from pip._internal.req.req_install import InstallRequirement
from pip._internal.utils.logging import get_indentation

DownloadProgressRenderer = Callable[[Iterable[bytes]], Iterator[bytes]]
P = TypeVar("P")

ProgressRenderer = Callable[[Iterable[P]], Iterator[P]]


def _rich_progress_bar(
Expand Down Expand Up @@ -57,11 +69,15 @@ def _rich_progress_bar(
progress.update(task_id, advance=len(chunk))


T = TypeVar("T", bound=Sized)


def _raw_progress_bar(
iterable: Iterable[bytes],
iterable: Iterable[T],
*,
size: Optional[int],
) -> Generator[bytes, None, None]:
unit_size: int = 0,
) -> Generator[T, None, None]:
def write_progress(current: int, total: int) -> None:
sys.stdout.write("Progress %d of %d\n" % (current, total))
sys.stdout.flush()
Expand All @@ -72,7 +88,7 @@ def write_progress(current: int, total: int) -> None:

write_progress(current, total)
for chunk in iterable:
current += len(chunk)
current += unit_size or len(chunk)
joeyballentine marked this conversation as resolved.
Show resolved Hide resolved
if rate_limiter.ready() or current == total:
write_progress(current, total)
rate_limiter.reset()
Expand All @@ -81,14 +97,29 @@ def write_progress(current: int, total: int) -> None:

def get_download_progress_renderer(
*, bar_type: str, size: Optional[int] = None
) -> DownloadProgressRenderer:
) -> ProgressRenderer[bytes]:
"""Get an object that can be used to render the download progress.

Returns a callable, that takes an iterable to "wrap".
"""
if bar_type == "on":
return functools.partial(_rich_progress_bar, bar_type=bar_type, size=size)
elif bar_type == "raw":
return functools.partial(_raw_progress_bar, size=size)
return functools.partial[Iterator[bytes]](_raw_progress_bar, size=size)
else:
return iter # no-op, when passed an iterator


def get_install_progress_renderer(
*, bar_type: str, total: Optional[int] = None
) -> ProgressRenderer[Tuple[str, InstallRequirement]]:
"""Get an object that can be used to render the install progress.

Returns a callable, that takes an iterable to "wrap".
"""
if bar_type == "raw":
return functools.partial[Iterator[Tuple[str, InstallRequirement]]](
_raw_progress_bar, size=total, unit_size=1
)
else:
return iter # no-op, when passed an iterator
1 change: 1 addition & 0 deletions src/pip/_internal/commands/install.py
Original file line number Diff line number Diff line change
Expand Up @@ -458,6 +458,7 @@ def run(self, options: Values, args: List[str]) -> int:
warn_script_location=warn_script_location,
use_user_site=options.use_user_site,
pycompile=options.compile,
progress_bar=options.progress_bar,
)

lib_locations = get_lib_location_guesses(
Expand Down
13 changes: 12 additions & 1 deletion src/pip/_internal/req/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import logging
from typing import Generator, List, Optional, Sequence, Tuple

from pip._internal.cli.progress_bars import get_install_progress_renderer
from pip._internal.utils.logging import indent_log

from .req_file import parse_requirements
Expand Down Expand Up @@ -43,6 +44,7 @@ def install_given_reqs(
warn_script_location: bool,
use_user_site: bool,
pycompile: bool,
progress_bar: str,
) -> List[InstallationResult]:
"""
Install everything in the given list.
Expand All @@ -59,8 +61,17 @@ def install_given_reqs(

installed = []

show_progress = logger.getEffectiveLevel() <= logging.INFO

items = iter(to_install.items())
if show_progress:
renderer = get_install_progress_renderer(
bar_type=progress_bar, total=len(to_install)
)
items = renderer(items)

with indent_log():
for req_name, requirement in to_install.items():
for req_name, requirement in items:
if requirement.should_reinstall:
logger.info("Attempting uninstall: %s", req_name)
with indent_log():
Expand Down