Skip to content

Commit a57530a

Browse files
authored
Merge pull request #235 from rsalmei/escape-codes-hook
ANSI Escape codes support in print hook
2 parents 10cd86c + 2b9ea7c commit a57530a

File tree

6 files changed

+116
-58
lines changed

6 files changed

+116
-58
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
# Changelog
22

33

4+
## 3.1.1 - Apr 08, 2023
5+
- print hook support for ANSI Escape Codes (which avoid sending newlines when not needed)
6+
- typing support in `alive_it`, so the collection type is correctly identified.
7+
8+
49
## 3.1.0 - Mar 23, 2023
510
- new resuming computations support with `skipped` items
611
- new `max_cols` config setting, the number of columns to use if not possible to fetch it, like in jupyter and other platforms which doesn't support size

README.md

Lines changed: 90 additions & 46 deletions
Large diffs are not rendered by default.

alive_progress/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from .core.configuration import config_handler
22
from .core.progress import alive_bar, alive_it
33

4-
VERSION = (3, 1, 0)
4+
VERSION = (3, 1, 1)
55

66
__author__ = 'Rogério Sampaio de Almeida'
77
__email__ = '[email protected]'

alive_progress/core/hook_manager.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ def flush_buffers():
3030

3131
def flush(stream):
3232
if buffers[stream]:
33-
write(stream, '\n')
33+
write(stream, '\n') # when the current index is about to change, send a newline.
3434
stream.flush()
3535

3636
def write(stream, part):
@@ -39,6 +39,9 @@ def write(stream, part):
3939

4040
buffer = buffers[stream]
4141
if part != '\n':
42+
if part.startswith('\x1b'): # if the part starts with ESC, just send it.
43+
stream.write(part)
44+
return
4245
# this will generate a sequence of lines interspersed with None, which will later
4346
# be rendered as the indent filler to align additional lines under the same header.
4447
gen = chain.from_iterable(zip(repeat(None), part.splitlines(True)))

alive_progress/core/progress.py

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import threading
77
import time
88
from contextlib import contextmanager
9+
from typing import Any, Callable, Collection, Iterable, Optional, TypeVar
910

1011
from .calibration import calibrated_fps, custom_fps
1112
from .configuration import config_handler
@@ -16,7 +17,7 @@
1617
gen_simple_exponential_smoothing
1718

1819

19-
def alive_bar(total=None, *, calibrate=None, **options):
20+
def alive_bar(total: Optional[int] = None, *, calibrate: Optional[int] = None, **options: Any):
2021
"""An alive progress bar to keep track of lengthy operations.
2122
It has a spinner indicator, elapsed time, throughput and ETA.
2223
When the operation finishes, a receipt is displayed with statistics.
@@ -178,17 +179,17 @@ def set_title(title=None):
178179

179180
if config.manual:
180181
def bar(percent): # for manual progress modes, regardless of total.
181-
hook_manager.flush_buffers()
182+
hook_manager.flush_buffers() # notify that the current index is about to change.
182183
run.percent = max(0., float(percent))
183184
bar_update_hook()
184185
elif not total:
185186
def bar(count=1): # for unknown progress mode.
186-
hook_manager.flush_buffers()
187+
hook_manager.flush_buffers() # notify that the current index is about to change.
187188
run.count += max(1, int(count))
188189
bar_update_hook()
189190
else:
190191
def bar(count=1, *, skipped=False): # for definite progress mode.
191-
hook_manager.flush_buffers()
192+
hook_manager.flush_buffers() # notify that the current index is about to change.
192193
count = max(1, int(count))
193194
run.count += count
194195
if not skipped:
@@ -289,7 +290,7 @@ def stats_end(f):
289290

290291
if total or config.manual: # we can track progress and therefore eta.
291292
def stats_run(f):
292-
run.rate_text = rate_text(1)
293+
run.rate_text = rate_text(1) # although repeated below,
293294
run.eta_text = eta_text(gen_eta.send((current(), run.rate)))
294295
return f.format(rate=run.rate_text, unit=unit, eta=run.eta_text)
295296

@@ -298,7 +299,7 @@ def stats_run(f):
298299
stats_default = '({eta}, {rate})'
299300
else: # unknown progress.
300301
def stats_run(f):
301-
run.rate_text = rate_text(1)
302+
run.rate_text = rate_text(1) # it won't be calculated if not needed.
302303
return f.format(rate=run.rate_text, eta='?')
303304

304305
bar_repr = bar_repr.unknown
@@ -473,7 +474,12 @@ def _render_title(config, title=None):
473474
return combine_cells(fix_cells(title[:length - 1]), ('…',))
474475

475476

476-
def alive_it(it, total=None, *, finalize=None, calibrate=None, **options):
477+
T = TypeVar('T')
478+
479+
480+
def alive_it(it: Collection[T], total: Optional[int] = None, *,
481+
finalize: Callable[[Any], None] = None,
482+
calibrate: Optional[int] = None, **options: Any) -> Iterable[T]:
477483
"""New iterator adapter in 2.0, which makes it simpler to monitor any processing.
478484
479485
Simply wrap your iterable with `alive_it`, and process your items normally!
@@ -498,7 +504,7 @@ def alive_it(it, total=None, *, finalize=None, calibrate=None, **options):
498504
... items = range(100000)
499505
... bar = alive_it(items)
500506
... for item in bar:
501-
... bar.text(f'Wow, it works! Item: {item}')
507+
... bar.text = f'Wow, it works! Item: {item}'
502508
... # process item.
503509
504510
You can also send a `finalize` function to set the final receipt title and text, and any other
@@ -518,7 +524,7 @@ def alive_it(it, total=None, *, finalize=None, calibrate=None, **options):
518524
DB updated |████████████████████| 100k/100k [100%] in 2.6s (38.7k/s) 100000 entries changed
519525
520526
Args:
521-
it (iterable): the input iterable to be processed
527+
it: the input iterable to be processed
522528
total: same as alive_bar
523529
finalize: a function to be called when the bar is going to finalize
524530
calibrate: same as alive_bar
@@ -546,7 +552,7 @@ def alive_it(it, total=None, *, finalize=None, calibrate=None, **options):
546552
return __AliveBarIteratorAdapter(it, finalize, __alive_bar(config, total, calibrate=calibrate))
547553

548554

549-
class __AliveBarIteratorAdapter:
555+
class __AliveBarIteratorAdapter(Iterable[T]):
550556
def __init__(self, it, finalize, inner_bar):
551557
self._it, self._finalize, self._inner_bar = it, finalize, inner_bar
552558

img/pycharm-terminal.png

6.26 KB
Loading

0 commit comments

Comments
 (0)