Skip to content

Commit 7a4c3ba

Browse files
authored
Merge pull request #11014 from pradyunsg/remove-alternative-progress-bars
Co-authored-by: Pradyun Gedam <[email protected]>
2 parents 0ac0f84 + 2c8e78c commit 7a4c3ba

13 files changed

+9
-737
lines changed

news/progress.vendor.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Remove ``progress`` from vendored dependencies.

src/pip/_internal/cli/cmdoptions.py

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
from pip._vendor.packaging.utils import canonicalize_name
2222

2323
from pip._internal.cli.parser import ConfigOptionParser
24-
from pip._internal.cli.progress_bars import BAR_TYPES
2524
from pip._internal.exceptions import CommandError
2625
from pip._internal.locations import USER_CACHE_DIR, get_src_prefix
2726
from pip._internal.models.format_control import FormatControl
@@ -236,13 +235,9 @@ class PipOption(Option):
236235
"--progress-bar",
237236
dest="progress_bar",
238237
type="choice",
239-
choices=list(BAR_TYPES.keys()),
238+
choices=["on", "off"],
240239
default="on",
241-
help=(
242-
"Specify type of progress to be displayed ["
243-
+ "|".join(BAR_TYPES.keys())
244-
+ "] (default: %default)"
245-
),
240+
help="Specify whether the progress bar should be used [on, off] (default: on)",
246241
)
247242

248243
log: Callable[..., Option] = partial(
Lines changed: 2 additions & 253 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,6 @@
11
import functools
2-
import itertools
3-
import sys
4-
from signal import SIGINT, default_int_handler, signal
5-
from typing import Any, Callable, Iterator, Optional, Tuple
2+
from typing import Callable, Iterator, Optional, Tuple
63

7-
from pip._vendor.progress.bar import Bar, FillingCirclesBar, IncrementalBar
8-
from pip._vendor.progress.spinner import Spinner
94
from pip._vendor.rich.progress import (
105
BarColumn,
116
DownloadColumn,
@@ -19,255 +14,11 @@
1914
TransferSpeedColumn,
2015
)
2116

22-
from pip._internal.utils.compat import WINDOWS
2317
from pip._internal.utils.logging import get_indentation
24-
from pip._internal.utils.misc import format_size
25-
26-
try:
27-
from pip._vendor import colorama
28-
# Lots of different errors can come from this, including SystemError and
29-
# ImportError.
30-
except Exception:
31-
colorama = None
3218

3319
DownloadProgressRenderer = Callable[[Iterator[bytes]], Iterator[bytes]]
3420

3521

36-
def _select_progress_class(preferred: Bar, fallback: Bar) -> Bar:
37-
encoding = getattr(preferred.file, "encoding", None)
38-
39-
# If we don't know what encoding this file is in, then we'll just assume
40-
# that it doesn't support unicode and use the ASCII bar.
41-
if not encoding:
42-
return fallback
43-
44-
# Collect all of the possible characters we want to use with the preferred
45-
# bar.
46-
characters = [
47-
getattr(preferred, "empty_fill", ""),
48-
getattr(preferred, "fill", ""),
49-
]
50-
characters += list(getattr(preferred, "phases", []))
51-
52-
# Try to decode the characters we're using for the bar using the encoding
53-
# of the given file, if this works then we'll assume that we can use the
54-
# fancier bar and if not we'll fall back to the plaintext bar.
55-
try:
56-
"".join(characters).encode(encoding)
57-
except UnicodeEncodeError:
58-
return fallback
59-
else:
60-
return preferred
61-
62-
63-
_BaseBar: Any = _select_progress_class(IncrementalBar, Bar)
64-
65-
66-
class InterruptibleMixin:
67-
"""
68-
Helper to ensure that self.finish() gets called on keyboard interrupt.
69-
70-
This allows downloads to be interrupted without leaving temporary state
71-
(like hidden cursors) behind.
72-
73-
This class is similar to the progress library's existing SigIntMixin
74-
helper, but as of version 1.2, that helper has the following problems:
75-
76-
1. It calls sys.exit().
77-
2. It discards the existing SIGINT handler completely.
78-
3. It leaves its own handler in place even after an uninterrupted finish,
79-
which will have unexpected delayed effects if the user triggers an
80-
unrelated keyboard interrupt some time after a progress-displaying
81-
download has already completed, for example.
82-
"""
83-
84-
def __init__(self, *args: Any, **kwargs: Any) -> None:
85-
"""
86-
Save the original SIGINT handler for later.
87-
"""
88-
# https://github.com/python/mypy/issues/5887
89-
super().__init__(*args, **kwargs)
90-
91-
self.original_handler = signal(SIGINT, self.handle_sigint)
92-
93-
# If signal() returns None, the previous handler was not installed from
94-
# Python, and we cannot restore it. This probably should not happen,
95-
# but if it does, we must restore something sensible instead, at least.
96-
# The least bad option should be Python's default SIGINT handler, which
97-
# just raises KeyboardInterrupt.
98-
if self.original_handler is None:
99-
self.original_handler = default_int_handler
100-
101-
def finish(self) -> None:
102-
"""
103-
Restore the original SIGINT handler after finishing.
104-
105-
This should happen regardless of whether the progress display finishes
106-
normally, or gets interrupted.
107-
"""
108-
super().finish() # type: ignore
109-
signal(SIGINT, self.original_handler)
110-
111-
def handle_sigint(self, signum, frame): # type: ignore
112-
"""
113-
Call self.finish() before delegating to the original SIGINT handler.
114-
115-
This handler should only be in place while the progress display is
116-
active.
117-
"""
118-
self.finish()
119-
self.original_handler(signum, frame)
120-
121-
122-
class SilentBar(Bar):
123-
def update(self) -> None:
124-
pass
125-
126-
127-
class BlueEmojiBar(IncrementalBar):
128-
129-
suffix = "%(percent)d%%"
130-
bar_prefix = " "
131-
bar_suffix = " "
132-
phases = ("\U0001F539", "\U0001F537", "\U0001F535")
133-
134-
135-
class DownloadProgressMixin:
136-
def __init__(self, *args: Any, **kwargs: Any) -> None:
137-
super().__init__(*args, **kwargs)
138-
self.message: str = (" " * (get_indentation() + 2)) + self.message
139-
140-
@property
141-
def downloaded(self) -> str:
142-
return format_size(self.index) # type: ignore
143-
144-
@property
145-
def download_speed(self) -> str:
146-
# Avoid zero division errors...
147-
if self.avg == 0.0: # type: ignore
148-
return "..."
149-
return format_size(1 / self.avg) + "/s" # type: ignore
150-
151-
@property
152-
def pretty_eta(self) -> str:
153-
if self.eta: # type: ignore
154-
return f"eta {self.eta_td}" # type: ignore
155-
return ""
156-
157-
def iter(self, it): # type: ignore
158-
for x in it:
159-
yield x
160-
# B305 is incorrectly raised here
161-
# https://github.com/PyCQA/flake8-bugbear/issues/59
162-
self.next(len(x)) # noqa: B305
163-
self.finish()
164-
165-
166-
class WindowsMixin:
167-
def __init__(self, *args: Any, **kwargs: Any) -> None:
168-
# The Windows terminal does not support the hide/show cursor ANSI codes
169-
# even with colorama. So we'll ensure that hide_cursor is False on
170-
# Windows.
171-
# This call needs to go before the super() call, so that hide_cursor
172-
# is set in time. The base progress bar class writes the "hide cursor"
173-
# code to the terminal in its init, so if we don't set this soon
174-
# enough, we get a "hide" with no corresponding "show"...
175-
if WINDOWS and self.hide_cursor: # type: ignore
176-
self.hide_cursor = False
177-
178-
super().__init__(*args, **kwargs)
179-
180-
# Check if we are running on Windows and we have the colorama module,
181-
# if we do then wrap our file with it.
182-
if WINDOWS and colorama:
183-
self.file = colorama.AnsiToWin32(self.file) # type: ignore
184-
# The progress code expects to be able to call self.file.isatty()
185-
# but the colorama.AnsiToWin32() object doesn't have that, so we'll
186-
# add it.
187-
self.file.isatty = lambda: self.file.wrapped.isatty()
188-
# The progress code expects to be able to call self.file.flush()
189-
# but the colorama.AnsiToWin32() object doesn't have that, so we'll
190-
# add it.
191-
self.file.flush = lambda: self.file.wrapped.flush()
192-
193-
194-
class BaseDownloadProgressBar(WindowsMixin, InterruptibleMixin, DownloadProgressMixin):
195-
196-
file = sys.stdout
197-
message = "%(percent)d%%"
198-
suffix = "%(downloaded)s %(download_speed)s %(pretty_eta)s"
199-
200-
201-
class DefaultDownloadProgressBar(BaseDownloadProgressBar, _BaseBar):
202-
pass
203-
204-
205-
class DownloadSilentBar(BaseDownloadProgressBar, SilentBar):
206-
pass
207-
208-
209-
class DownloadBar(BaseDownloadProgressBar, Bar):
210-
pass
211-
212-
213-
class DownloadFillingCirclesBar(BaseDownloadProgressBar, FillingCirclesBar):
214-
pass
215-
216-
217-
class DownloadBlueEmojiProgressBar(BaseDownloadProgressBar, BlueEmojiBar):
218-
pass
219-
220-
221-
class DownloadProgressSpinner(
222-
WindowsMixin, InterruptibleMixin, DownloadProgressMixin, Spinner
223-
):
224-
225-
file = sys.stdout
226-
suffix = "%(downloaded)s %(download_speed)s"
227-
228-
def next_phase(self) -> str:
229-
if not hasattr(self, "_phaser"):
230-
self._phaser = itertools.cycle(self.phases)
231-
return next(self._phaser)
232-
233-
def update(self) -> None:
234-
message = self.message % self
235-
phase = self.next_phase()
236-
suffix = self.suffix % self
237-
line = "".join(
238-
[
239-
message,
240-
" " if message else "",
241-
phase,
242-
" " if suffix else "",
243-
suffix,
244-
]
245-
)
246-
247-
self.writeln(line)
248-
249-
250-
BAR_TYPES = {
251-
"off": (DownloadSilentBar, DownloadSilentBar),
252-
"on": (DefaultDownloadProgressBar, DownloadProgressSpinner),
253-
"ascii": (DownloadBar, DownloadProgressSpinner),
254-
"pretty": (DownloadFillingCirclesBar, DownloadProgressSpinner),
255-
"emoji": (DownloadBlueEmojiProgressBar, DownloadProgressSpinner),
256-
}
257-
258-
259-
def _legacy_progress_bar(
260-
progress_bar: str, max: Optional[int]
261-
) -> DownloadProgressRenderer:
262-
if max is None or max == 0:
263-
return BAR_TYPES[progress_bar][1]().iter # type: ignore
264-
else:
265-
return BAR_TYPES[progress_bar][0](max=max).iter
266-
267-
268-
#
269-
# Modern replacement, for our legacy progress bars.
270-
#
27122
def _rich_progress_bar(
27223
iterable: Iterator[bytes],
27324
*,
@@ -313,7 +64,5 @@ def get_download_progress_renderer(
31364
"""
31465
if bar_type == "on":
31566
return functools.partial(_rich_progress_bar, bar_type=bar_type, size=size)
316-
elif bar_type == "off":
317-
return iter # no-op, when passed an iterator
31867
else:
319-
return _legacy_progress_bar(bar_type, size)
68+
return iter # no-op, when passed an iterator

src/pip/_internal/cli/req_command.py

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -302,13 +302,6 @@ def make_requirement_preparer(
302302
gone_in="22.1",
303303
)
304304

305-
if options.progress_bar not in {"on", "off"}:
306-
deprecated(
307-
reason="Custom progress bar styles are deprecated",
308-
replacement="to use the default progress bar style.",
309-
gone_in="22.1",
310-
)
311-
312305
return RequirementPreparer(
313306
build_dir=temp_build_dir_path,
314307
src_dir=options.src_dir,

src/pip/_internal/cli/spinners.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@
55
import time
66
from typing import IO, Iterator
77

8-
from pip._vendor.progress import HIDE_CURSOR, SHOW_CURSOR
9-
108
from pip._internal.utils.compat import WINDOWS
119
from pip._internal.utils.logging import get_indentation
1210

@@ -138,6 +136,10 @@ def open_spinner(message: str) -> Iterator[SpinnerInterface]:
138136
spinner.finish("done")
139137

140138

139+
HIDE_CURSOR = "\x1b[?25l"
140+
SHOW_CURSOR = "\x1b[?25h"
141+
142+
141143
@contextlib.contextmanager
142144
def hidden_cursor(file: IO[str]) -> Iterator[None]:
143145
# The Windows terminal does not support the hide/show cursor ANSI codes,

src/pip/_vendor/progress.pyi

Lines changed: 0 additions & 1 deletion
This file was deleted.

src/pip/_vendor/progress/LICENSE

Lines changed: 0 additions & 13 deletions
This file was deleted.

0 commit comments

Comments
 (0)