Skip to content

Commit 07ac08a

Browse files
committed
Address progress review cleanup issues
1 parent aab0a08 commit 07ac08a

6 files changed

Lines changed: 89 additions & 4 deletions

File tree

progressbar/bar.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1166,7 +1166,8 @@ def start(
11661166
StdRedirectMixin.finish(self, end='')
11671167
with contextlib.suppress(Exception):
11681168
ResizableMixin.finish(self)
1169-
ProgressBarBase.finish(self)
1169+
with contextlib.suppress(Exception):
1170+
ProgressBarBase.finish(self)
11701171
raise
11711172

11721173
return self

progressbar/utils.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -342,7 +342,7 @@ def wrap_logging(self) -> None:
342342

343343
seen: set[int] = set()
344344
for logger_ in self._iter_loggers():
345-
for handler in logger_.handlers:
345+
for handler in tuple(logger_.handlers):
346346
if id(handler) in seen:
347347
continue
348348
seen.add(id(handler))

progressbar/widgets.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1266,7 +1266,9 @@ def __init__(
12661266

12671267
def __call__(self, progress: ProgressBarMixinBase, data: Data) -> str:
12681268
value = data['variables'].get(self.name)
1269-
if not value:
1269+
if value is None or (
1270+
isinstance(value, (str, dict, list, set, tuple)) and not value
1271+
):
12701272
return ''
12711273
if isinstance(value, str):
12721274
rendered = value

tests/test_progressbar.py

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,10 @@
1111
import pytest
1212

1313
import progressbar
14-
from progressbar import utils
14+
from progressbar import (
15+
bar as bar_module,
16+
utils,
17+
)
1518

1619
# Import hack to allow for parallel Tox
1720
try:
@@ -262,6 +265,23 @@ def test_start_cleans_stream_listener_when_validation_fails() -> None:
262265
assert bar not in utils.streams.listeners
263266

264267

268+
def test_start_preserves_original_error_when_base_cleanup_fails(
269+
monkeypatch,
270+
) -> None:
271+
def fail_start(self, max_value=None):
272+
raise ValueError('resize start failed')
273+
274+
def fail_finish(self):
275+
raise RuntimeError('base cleanup failed')
276+
277+
monkeypatch.setattr(bar_module.ResizableMixin, 'start', fail_start)
278+
monkeypatch.setattr(bar_module.ProgressBarBase, 'finish', fail_finish)
279+
280+
bar = progressbar.ProgressBar(max_value=5, fd=io.StringIO())
281+
with pytest.raises(ValueError, match='resize start failed'):
282+
bar.start()
283+
284+
265285
@pytest.mark.skipif(os.name == 'nt', reason='SIGWINCH is POSIX-only')
266286
def test_sigwinch_restored_with_overlapping_bars() -> None:
267287
# Regression: A5 - with two live bars, finishing them in creation

tests/test_stream.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,48 @@ def setStream(self, stream): # noqa: N802
240240
logger.handlers = []
241241

242242

243+
def test_wrap_logging_uses_handler_snapshot(monkeypatch) -> None:
244+
reset_wrapped_streams()
245+
246+
stream = io.StringIO()
247+
monkeypatch.setattr(sys, 'stderr', stream)
248+
monkeypatch.setattr(progressbar.streams, 'original_stderr', stream)
249+
monkeypatch.setattr(progressbar.streams, 'stderr', stream)
250+
251+
logger = logging.getLogger('progressbar-test-mutating-handlers')
252+
logger.handlers = []
253+
logger.propagate = False
254+
first_handler = logging.StreamHandler(sys.stderr)
255+
late_handler = logging.StreamHandler(sys.stderr)
256+
logger.addHandler(first_handler)
257+
258+
wrapped_handlers: list[logging.StreamHandler] = []
259+
original_wrap_handler = progressbar.streams._wrap_logging_handler
260+
261+
def mutating_wrap_handler(handler, wrapped_streams, restore_streams):
262+
wrapped_handlers.append(handler)
263+
if handler is first_handler:
264+
logger.addHandler(late_handler)
265+
original_wrap_handler(handler, wrapped_streams, restore_streams)
266+
267+
monkeypatch.setattr(
268+
progressbar.streams,
269+
'_wrap_logging_handler',
270+
mutating_wrap_handler,
271+
)
272+
273+
progressbar.streams.wrap_stderr()
274+
try:
275+
progressbar.streams.wrap_logging()
276+
assert first_handler in wrapped_handlers
277+
assert late_handler not in wrapped_handlers
278+
assert late_handler.stream is stream
279+
finally:
280+
progressbar.streams.unwrap_logging()
281+
progressbar.streams.unwrap(stderr=True)
282+
logger.handlers = []
283+
284+
243285
def test_unwrap_logging_ignores_dynamic_stderr_handler(monkeypatch) -> None:
244286
reset_wrapped_streams()
245287

tests/test_widgets.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,26 @@ def test_postfix_widget_renders_other_values() -> None:
101101
assert output == ' 3'
102102

103103

104+
@pytest.mark.parametrize(
105+
('value', 'expected'),
106+
[
107+
(0, ' 0'),
108+
(0.0, ' 0.0'),
109+
(False, ' False'),
110+
],
111+
)
112+
def test_postfix_widget_renders_falsy_values(value, expected) -> None:
113+
bar = progressbar.ProgressBar(
114+
widgets=[progressbar.Postfix()],
115+
variables={'postfix': value},
116+
fd=io.StringIO(),
117+
term_width=80,
118+
)
119+
bar.start()
120+
output = ''.join(bar._format_widgets())
121+
assert output == expected
122+
123+
104124
def test_postfix_widget_omits_empty_values() -> None:
105125
bar = progressbar.ProgressBar(
106126
widgets=[progressbar.Postfix()],

0 commit comments

Comments
 (0)