Mercurial > repos > rliterman > csp2
comparison CSP2/CSP2_env/env-d9b9114564458d9d-741b3de822f2aaca6c6caa4325c4afce/lib/python3.8/site-packages/tqdm/std.py @ 68:5028fdace37b
planemo upload commit 2e9511a184a1ca667c7be0c6321a36dc4e3d116d
author | jpayne |
---|---|
date | Tue, 18 Mar 2025 16:23:26 -0400 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
67:0e9998148a16 | 68:5028fdace37b |
---|---|
1 """ | |
2 Customisable progressbar decorator for iterators. | |
3 Includes a default `range` iterator printing to `stderr`. | |
4 | |
5 Usage: | |
6 >>> from tqdm import trange, tqdm | |
7 >>> for i in trange(10): | |
8 ... ... | |
9 """ | |
10 import sys | |
11 from collections import OrderedDict, defaultdict | |
12 from contextlib import contextmanager | |
13 from datetime import datetime, timedelta, timezone | |
14 from numbers import Number | |
15 from time import time | |
16 from warnings import warn | |
17 from weakref import WeakSet | |
18 | |
19 from ._monitor import TMonitor | |
20 from .utils import ( | |
21 CallbackIOWrapper, Comparable, DisableOnWriteError, FormatReplace, SimpleTextIOWrapper, | |
22 _is_ascii, _screen_shape_wrapper, _supports_unicode, _term_move_up, disp_len, disp_trim, | |
23 envwrap) | |
24 | |
25 __author__ = "https://github.com/tqdm/tqdm#contributions" | |
26 __all__ = ['tqdm', 'trange', | |
27 'TqdmTypeError', 'TqdmKeyError', 'TqdmWarning', | |
28 'TqdmExperimentalWarning', 'TqdmDeprecationWarning', | |
29 'TqdmMonitorWarning'] | |
30 | |
31 | |
32 class TqdmTypeError(TypeError): | |
33 pass | |
34 | |
35 | |
36 class TqdmKeyError(KeyError): | |
37 pass | |
38 | |
39 | |
40 class TqdmWarning(Warning): | |
41 """base class for all tqdm warnings. | |
42 | |
43 Used for non-external-code-breaking errors, such as garbled printing. | |
44 """ | |
45 def __init__(self, msg, fp_write=None, *a, **k): | |
46 if fp_write is not None: | |
47 fp_write("\n" + self.__class__.__name__ + ": " + str(msg).rstrip() + '\n') | |
48 else: | |
49 super().__init__(msg, *a, **k) | |
50 | |
51 | |
52 class TqdmExperimentalWarning(TqdmWarning, FutureWarning): | |
53 """beta feature, unstable API and behaviour""" | |
54 pass | |
55 | |
56 | |
57 class TqdmDeprecationWarning(TqdmWarning, DeprecationWarning): | |
58 # not suppressed if raised | |
59 pass | |
60 | |
61 | |
62 class TqdmMonitorWarning(TqdmWarning, RuntimeWarning): | |
63 """tqdm monitor errors which do not affect external functionality""" | |
64 pass | |
65 | |
66 | |
67 def TRLock(*args, **kwargs): | |
68 """threading RLock""" | |
69 try: | |
70 from threading import RLock | |
71 return RLock(*args, **kwargs) | |
72 except (ImportError, OSError): # pragma: no cover | |
73 pass | |
74 | |
75 | |
76 class TqdmDefaultWriteLock(object): | |
77 """ | |
78 Provide a default write lock for thread and multiprocessing safety. | |
79 Works only on platforms supporting `fork` (so Windows is excluded). | |
80 You must initialise a `tqdm` or `TqdmDefaultWriteLock` instance | |
81 before forking in order for the write lock to work. | |
82 On Windows, you need to supply the lock from the parent to the children as | |
83 an argument to joblib or the parallelism lib you use. | |
84 """ | |
85 # global thread lock so no setup required for multithreading. | |
86 # NB: Do not create multiprocessing lock as it sets the multiprocessing | |
87 # context, disallowing `spawn()`/`forkserver()` | |
88 th_lock = TRLock() | |
89 | |
90 def __init__(self): | |
91 # Create global parallelism locks to avoid racing issues with parallel | |
92 # bars works only if fork available (Linux/MacOSX, but not Windows) | |
93 cls = type(self) | |
94 root_lock = cls.th_lock | |
95 if root_lock is not None: | |
96 root_lock.acquire() | |
97 cls.create_mp_lock() | |
98 self.locks = [lk for lk in [cls.mp_lock, cls.th_lock] if lk is not None] | |
99 if root_lock is not None: | |
100 root_lock.release() | |
101 | |
102 def acquire(self, *a, **k): | |
103 for lock in self.locks: | |
104 lock.acquire(*a, **k) | |
105 | |
106 def release(self): | |
107 for lock in self.locks[::-1]: # Release in inverse order of acquisition | |
108 lock.release() | |
109 | |
110 def __enter__(self): | |
111 self.acquire() | |
112 | |
113 def __exit__(self, *exc): | |
114 self.release() | |
115 | |
116 @classmethod | |
117 def create_mp_lock(cls): | |
118 if not hasattr(cls, 'mp_lock'): | |
119 try: | |
120 from multiprocessing import RLock | |
121 cls.mp_lock = RLock() | |
122 except (ImportError, OSError): # pragma: no cover | |
123 cls.mp_lock = None | |
124 | |
125 @classmethod | |
126 def create_th_lock(cls): | |
127 assert hasattr(cls, 'th_lock') | |
128 warn("create_th_lock not needed anymore", TqdmDeprecationWarning, stacklevel=2) | |
129 | |
130 | |
131 class Bar(object): | |
132 """ | |
133 `str.format`-able bar with format specifiers: `[width][type]` | |
134 | |
135 - `width` | |
136 + unspecified (default): use `self.default_len` | |
137 + `int >= 0`: overrides `self.default_len` | |
138 + `int < 0`: subtract from `self.default_len` | |
139 - `type` | |
140 + `a`: ascii (`charset=self.ASCII` override) | |
141 + `u`: unicode (`charset=self.UTF` override) | |
142 + `b`: blank (`charset=" "` override) | |
143 """ | |
144 ASCII = " 123456789#" | |
145 UTF = u" " + u''.join(map(chr, range(0x258F, 0x2587, -1))) | |
146 BLANK = " " | |
147 COLOUR_RESET = '\x1b[0m' | |
148 COLOUR_RGB = '\x1b[38;2;%d;%d;%dm' | |
149 COLOURS = {'BLACK': '\x1b[30m', 'RED': '\x1b[31m', 'GREEN': '\x1b[32m', | |
150 'YELLOW': '\x1b[33m', 'BLUE': '\x1b[34m', 'MAGENTA': '\x1b[35m', | |
151 'CYAN': '\x1b[36m', 'WHITE': '\x1b[37m'} | |
152 | |
153 def __init__(self, frac, default_len=10, charset=UTF, colour=None): | |
154 if not 0 <= frac <= 1: | |
155 warn("clamping frac to range [0, 1]", TqdmWarning, stacklevel=2) | |
156 frac = max(0, min(1, frac)) | |
157 assert default_len > 0 | |
158 self.frac = frac | |
159 self.default_len = default_len | |
160 self.charset = charset | |
161 self.colour = colour | |
162 | |
163 @property | |
164 def colour(self): | |
165 return self._colour | |
166 | |
167 @colour.setter | |
168 def colour(self, value): | |
169 if not value: | |
170 self._colour = None | |
171 return | |
172 try: | |
173 if value.upper() in self.COLOURS: | |
174 self._colour = self.COLOURS[value.upper()] | |
175 elif value[0] == '#' and len(value) == 7: | |
176 self._colour = self.COLOUR_RGB % tuple( | |
177 int(i, 16) for i in (value[1:3], value[3:5], value[5:7])) | |
178 else: | |
179 raise KeyError | |
180 except (KeyError, AttributeError): | |
181 warn("Unknown colour (%s); valid choices: [hex (#00ff00), %s]" % ( | |
182 value, ", ".join(self.COLOURS)), | |
183 TqdmWarning, stacklevel=2) | |
184 self._colour = None | |
185 | |
186 def __format__(self, format_spec): | |
187 if format_spec: | |
188 _type = format_spec[-1].lower() | |
189 try: | |
190 charset = {'a': self.ASCII, 'u': self.UTF, 'b': self.BLANK}[_type] | |
191 except KeyError: | |
192 charset = self.charset | |
193 else: | |
194 format_spec = format_spec[:-1] | |
195 if format_spec: | |
196 N_BARS = int(format_spec) | |
197 if N_BARS < 0: | |
198 N_BARS += self.default_len | |
199 else: | |
200 N_BARS = self.default_len | |
201 else: | |
202 charset = self.charset | |
203 N_BARS = self.default_len | |
204 | |
205 nsyms = len(charset) - 1 | |
206 bar_length, frac_bar_length = divmod(int(self.frac * N_BARS * nsyms), nsyms) | |
207 | |
208 res = charset[-1] * bar_length | |
209 if bar_length < N_BARS: # whitespace padding | |
210 res = res + charset[frac_bar_length] + charset[0] * (N_BARS - bar_length - 1) | |
211 return self.colour + res + self.COLOUR_RESET if self.colour else res | |
212 | |
213 | |
214 class EMA(object): | |
215 """ | |
216 Exponential moving average: smoothing to give progressively lower | |
217 weights to older values. | |
218 | |
219 Parameters | |
220 ---------- | |
221 smoothing : float, optional | |
222 Smoothing factor in range [0, 1], [default: 0.3]. | |
223 Increase to give more weight to recent values. | |
224 Ranges from 0 (yields old value) to 1 (yields new value). | |
225 """ | |
226 def __init__(self, smoothing=0.3): | |
227 self.alpha = smoothing | |
228 self.last = 0 | |
229 self.calls = 0 | |
230 | |
231 def __call__(self, x=None): | |
232 """ | |
233 Parameters | |
234 ---------- | |
235 x : float | |
236 New value to include in EMA. | |
237 """ | |
238 beta = 1 - self.alpha | |
239 if x is not None: | |
240 self.last = self.alpha * x + beta * self.last | |
241 self.calls += 1 | |
242 return self.last / (1 - beta ** self.calls) if self.calls else self.last | |
243 | |
244 | |
245 class tqdm(Comparable): | |
246 """ | |
247 Decorate an iterable object, returning an iterator which acts exactly | |
248 like the original iterable, but prints a dynamically updating | |
249 progressbar every time a value is requested. | |
250 | |
251 Parameters | |
252 ---------- | |
253 iterable : iterable, optional | |
254 Iterable to decorate with a progressbar. | |
255 Leave blank to manually manage the updates. | |
256 desc : str, optional | |
257 Prefix for the progressbar. | |
258 total : int or float, optional | |
259 The number of expected iterations. If unspecified, | |
260 len(iterable) is used if possible. If float("inf") or as a last | |
261 resort, only basic progress statistics are displayed | |
262 (no ETA, no progressbar). | |
263 If `gui` is True and this parameter needs subsequent updating, | |
264 specify an initial arbitrary large positive number, | |
265 e.g. 9e9. | |
266 leave : bool, optional | |
267 If [default: True], keeps all traces of the progressbar | |
268 upon termination of iteration. | |
269 If `None`, will leave only if `position` is `0`. | |
270 file : `io.TextIOWrapper` or `io.StringIO`, optional | |
271 Specifies where to output the progress messages | |
272 (default: sys.stderr). Uses `file.write(str)` and `file.flush()` | |
273 methods. For encoding, see `write_bytes`. | |
274 ncols : int, optional | |
275 The width of the entire output message. If specified, | |
276 dynamically resizes the progressbar to stay within this bound. | |
277 If unspecified, attempts to use environment width. The | |
278 fallback is a meter width of 10 and no limit for the counter and | |
279 statistics. If 0, will not print any meter (only stats). | |
280 mininterval : float, optional | |
281 Minimum progress display update interval [default: 0.1] seconds. | |
282 maxinterval : float, optional | |
283 Maximum progress display update interval [default: 10] seconds. | |
284 Automatically adjusts `miniters` to correspond to `mininterval` | |
285 after long display update lag. Only works if `dynamic_miniters` | |
286 or monitor thread is enabled. | |
287 miniters : int or float, optional | |
288 Minimum progress display update interval, in iterations. | |
289 If 0 and `dynamic_miniters`, will automatically adjust to equal | |
290 `mininterval` (more CPU efficient, good for tight loops). | |
291 If > 0, will skip display of specified number of iterations. | |
292 Tweak this and `mininterval` to get very efficient loops. | |
293 If your progress is erratic with both fast and slow iterations | |
294 (network, skipping items, etc) you should set miniters=1. | |
295 ascii : bool or str, optional | |
296 If unspecified or False, use unicode (smooth blocks) to fill | |
297 the meter. The fallback is to use ASCII characters " 123456789#". | |
298 disable : bool, optional | |
299 Whether to disable the entire progressbar wrapper | |
300 [default: False]. If set to None, disable on non-TTY. | |
301 unit : str, optional | |
302 String that will be used to define the unit of each iteration | |
303 [default: it]. | |
304 unit_scale : bool or int or float, optional | |
305 If 1 or True, the number of iterations will be reduced/scaled | |
306 automatically and a metric prefix following the | |
307 International System of Units standard will be added | |
308 (kilo, mega, etc.) [default: False]. If any other non-zero | |
309 number, will scale `total` and `n`. | |
310 dynamic_ncols : bool, optional | |
311 If set, constantly alters `ncols` and `nrows` to the | |
312 environment (allowing for window resizes) [default: False]. | |
313 smoothing : float, optional | |
314 Exponential moving average smoothing factor for speed estimates | |
315 (ignored in GUI mode). Ranges from 0 (average speed) to 1 | |
316 (current/instantaneous speed) [default: 0.3]. | |
317 bar_format : str, optional | |
318 Specify a custom bar string formatting. May impact performance. | |
319 [default: '{l_bar}{bar}{r_bar}'], where | |
320 l_bar='{desc}: {percentage:3.0f}%|' and | |
321 r_bar='| {n_fmt}/{total_fmt} [{elapsed}<{remaining}, ' | |
322 '{rate_fmt}{postfix}]' | |
323 Possible vars: l_bar, bar, r_bar, n, n_fmt, total, total_fmt, | |
324 percentage, elapsed, elapsed_s, ncols, nrows, desc, unit, | |
325 rate, rate_fmt, rate_noinv, rate_noinv_fmt, | |
326 rate_inv, rate_inv_fmt, postfix, unit_divisor, | |
327 remaining, remaining_s, eta. | |
328 Note that a trailing ": " is automatically removed after {desc} | |
329 if the latter is empty. | |
330 initial : int or float, optional | |
331 The initial counter value. Useful when restarting a progress | |
332 bar [default: 0]. If using float, consider specifying `{n:.3f}` | |
333 or similar in `bar_format`, or specifying `unit_scale`. | |
334 position : int, optional | |
335 Specify the line offset to print this bar (starting from 0) | |
336 Automatic if unspecified. | |
337 Useful to manage multiple bars at once (eg, from threads). | |
338 postfix : dict or *, optional | |
339 Specify additional stats to display at the end of the bar. | |
340 Calls `set_postfix(**postfix)` if possible (dict). | |
341 unit_divisor : float, optional | |
342 [default: 1000], ignored unless `unit_scale` is True. | |
343 write_bytes : bool, optional | |
344 Whether to write bytes. If (default: False) will write unicode. | |
345 lock_args : tuple, optional | |
346 Passed to `refresh` for intermediate output | |
347 (initialisation, iterating, and updating). | |
348 nrows : int, optional | |
349 The screen height. If specified, hides nested bars outside this | |
350 bound. If unspecified, attempts to use environment height. | |
351 The fallback is 20. | |
352 colour : str, optional | |
353 Bar colour (e.g. 'green', '#00ff00'). | |
354 delay : float, optional | |
355 Don't display until [default: 0] seconds have elapsed. | |
356 gui : bool, optional | |
357 WARNING: internal parameter - do not use. | |
358 Use tqdm.gui.tqdm(...) instead. If set, will attempt to use | |
359 matplotlib animations for a graphical output [default: False]. | |
360 | |
361 Returns | |
362 ------- | |
363 out : decorated iterator. | |
364 """ | |
365 | |
366 monitor_interval = 10 # set to 0 to disable the thread | |
367 monitor = None | |
368 _instances = WeakSet() | |
369 | |
370 @staticmethod | |
371 def format_sizeof(num, suffix='', divisor=1000): | |
372 """ | |
373 Formats a number (greater than unity) with SI Order of Magnitude | |
374 prefixes. | |
375 | |
376 Parameters | |
377 ---------- | |
378 num : float | |
379 Number ( >= 1) to format. | |
380 suffix : str, optional | |
381 Post-postfix [default: '']. | |
382 divisor : float, optional | |
383 Divisor between prefixes [default: 1000]. | |
384 | |
385 Returns | |
386 ------- | |
387 out : str | |
388 Number with Order of Magnitude SI unit postfix. | |
389 """ | |
390 for unit in ['', 'k', 'M', 'G', 'T', 'P', 'E', 'Z']: | |
391 if abs(num) < 999.5: | |
392 if abs(num) < 99.95: | |
393 if abs(num) < 9.995: | |
394 return f'{num:1.2f}{unit}{suffix}' | |
395 return f'{num:2.1f}{unit}{suffix}' | |
396 return f'{num:3.0f}{unit}{suffix}' | |
397 num /= divisor | |
398 return f'{num:3.1f}Y{suffix}' | |
399 | |
400 @staticmethod | |
401 def format_interval(t): | |
402 """ | |
403 Formats a number of seconds as a clock time, [H:]MM:SS | |
404 | |
405 Parameters | |
406 ---------- | |
407 t : int | |
408 Number of seconds. | |
409 | |
410 Returns | |
411 ------- | |
412 out : str | |
413 [H:]MM:SS | |
414 """ | |
415 mins, s = divmod(int(t), 60) | |
416 h, m = divmod(mins, 60) | |
417 return f'{h:d}:{m:02d}:{s:02d}' if h else f'{m:02d}:{s:02d}' | |
418 | |
419 @staticmethod | |
420 def format_num(n): | |
421 """ | |
422 Intelligent scientific notation (.3g). | |
423 | |
424 Parameters | |
425 ---------- | |
426 n : int or float or Numeric | |
427 A Number. | |
428 | |
429 Returns | |
430 ------- | |
431 out : str | |
432 Formatted number. | |
433 """ | |
434 f = f'{n:.3g}'.replace('e+0', 'e+').replace('e-0', 'e-') | |
435 n = str(n) | |
436 return f if len(f) < len(n) else n | |
437 | |
438 @staticmethod | |
439 def status_printer(file): | |
440 """ | |
441 Manage the printing and in-place updating of a line of characters. | |
442 Note that if the string is longer than a line, then in-place | |
443 updating may not work (it will print a new line at each refresh). | |
444 """ | |
445 fp = file | |
446 fp_flush = getattr(fp, 'flush', lambda: None) # pragma: no cover | |
447 if fp in (sys.stderr, sys.stdout): | |
448 getattr(sys.stderr, 'flush', lambda: None)() | |
449 getattr(sys.stdout, 'flush', lambda: None)() | |
450 | |
451 def fp_write(s): | |
452 fp.write(str(s)) | |
453 fp_flush() | |
454 | |
455 last_len = [0] | |
456 | |
457 def print_status(s): | |
458 len_s = disp_len(s) | |
459 fp_write('\r' + s + (' ' * max(last_len[0] - len_s, 0))) | |
460 last_len[0] = len_s | |
461 | |
462 return print_status | |
463 | |
464 @staticmethod | |
465 def format_meter(n, total, elapsed, ncols=None, prefix='', ascii=False, unit='it', | |
466 unit_scale=False, rate=None, bar_format=None, postfix=None, | |
467 unit_divisor=1000, initial=0, colour=None, **extra_kwargs): | |
468 """ | |
469 Return a string-based progress bar given some parameters | |
470 | |
471 Parameters | |
472 ---------- | |
473 n : int or float | |
474 Number of finished iterations. | |
475 total : int or float | |
476 The expected total number of iterations. If meaningless (None), | |
477 only basic progress statistics are displayed (no ETA). | |
478 elapsed : float | |
479 Number of seconds passed since start. | |
480 ncols : int, optional | |
481 The width of the entire output message. If specified, | |
482 dynamically resizes `{bar}` to stay within this bound | |
483 [default: None]. If `0`, will not print any bar (only stats). | |
484 The fallback is `{bar:10}`. | |
485 prefix : str, optional | |
486 Prefix message (included in total width) [default: '']. | |
487 Use as {desc} in bar_format string. | |
488 ascii : bool, optional or str, optional | |
489 If not set, use unicode (smooth blocks) to fill the meter | |
490 [default: False]. The fallback is to use ASCII characters | |
491 " 123456789#". | |
492 unit : str, optional | |
493 The iteration unit [default: 'it']. | |
494 unit_scale : bool or int or float, optional | |
495 If 1 or True, the number of iterations will be printed with an | |
496 appropriate SI metric prefix (k = 10^3, M = 10^6, etc.) | |
497 [default: False]. If any other non-zero number, will scale | |
498 `total` and `n`. | |
499 rate : float, optional | |
500 Manual override for iteration rate. | |
501 If [default: None], uses n/elapsed. | |
502 bar_format : str, optional | |
503 Specify a custom bar string formatting. May impact performance. | |
504 [default: '{l_bar}{bar}{r_bar}'], where | |
505 l_bar='{desc}: {percentage:3.0f}%|' and | |
506 r_bar='| {n_fmt}/{total_fmt} [{elapsed}<{remaining}, ' | |
507 '{rate_fmt}{postfix}]' | |
508 Possible vars: l_bar, bar, r_bar, n, n_fmt, total, total_fmt, | |
509 percentage, elapsed, elapsed_s, ncols, nrows, desc, unit, | |
510 rate, rate_fmt, rate_noinv, rate_noinv_fmt, | |
511 rate_inv, rate_inv_fmt, postfix, unit_divisor, | |
512 remaining, remaining_s, eta. | |
513 Note that a trailing ": " is automatically removed after {desc} | |
514 if the latter is empty. | |
515 postfix : *, optional | |
516 Similar to `prefix`, but placed at the end | |
517 (e.g. for additional stats). | |
518 Note: postfix is usually a string (not a dict) for this method, | |
519 and will if possible be set to postfix = ', ' + postfix. | |
520 However other types are supported (#382). | |
521 unit_divisor : float, optional | |
522 [default: 1000], ignored unless `unit_scale` is True. | |
523 initial : int or float, optional | |
524 The initial counter value [default: 0]. | |
525 colour : str, optional | |
526 Bar colour (e.g. 'green', '#00ff00'). | |
527 | |
528 Returns | |
529 ------- | |
530 out : Formatted meter and stats, ready to display. | |
531 """ | |
532 | |
533 # sanity check: total | |
534 if total and n >= (total + 0.5): # allow float imprecision (#849) | |
535 total = None | |
536 | |
537 # apply custom scale if necessary | |
538 if unit_scale and unit_scale not in (True, 1): | |
539 if total: | |
540 total *= unit_scale | |
541 n *= unit_scale | |
542 if rate: | |
543 rate *= unit_scale # by default rate = self.avg_dn / self.avg_dt | |
544 unit_scale = False | |
545 | |
546 elapsed_str = tqdm.format_interval(elapsed) | |
547 | |
548 # if unspecified, attempt to use rate = average speed | |
549 # (we allow manual override since predicting time is an arcane art) | |
550 if rate is None and elapsed: | |
551 rate = (n - initial) / elapsed | |
552 inv_rate = 1 / rate if rate else None | |
553 format_sizeof = tqdm.format_sizeof | |
554 rate_noinv_fmt = ((format_sizeof(rate) if unit_scale else f'{rate:5.2f}') | |
555 if rate else '?') + unit + '/s' | |
556 rate_inv_fmt = ( | |
557 (format_sizeof(inv_rate) if unit_scale else f'{inv_rate:5.2f}') | |
558 if inv_rate else '?') + 's/' + unit | |
559 rate_fmt = rate_inv_fmt if inv_rate and inv_rate > 1 else rate_noinv_fmt | |
560 | |
561 if unit_scale: | |
562 n_fmt = format_sizeof(n, divisor=unit_divisor) | |
563 total_fmt = format_sizeof(total, divisor=unit_divisor) if total is not None else '?' | |
564 else: | |
565 n_fmt = str(n) | |
566 total_fmt = str(total) if total is not None else '?' | |
567 | |
568 try: | |
569 postfix = ', ' + postfix if postfix else '' | |
570 except TypeError: | |
571 pass | |
572 | |
573 remaining = (total - n) / rate if rate and total else 0 | |
574 remaining_str = tqdm.format_interval(remaining) if rate else '?' | |
575 try: | |
576 eta_dt = (datetime.now() + timedelta(seconds=remaining) | |
577 if rate and total else datetime.fromtimestamp(0, timezone.utc)) | |
578 except OverflowError: | |
579 eta_dt = datetime.max | |
580 | |
581 # format the stats displayed to the left and right sides of the bar | |
582 if prefix: | |
583 # old prefix setup work around | |
584 bool_prefix_colon_already = (prefix[-2:] == ": ") | |
585 l_bar = prefix if bool_prefix_colon_already else prefix + ": " | |
586 else: | |
587 l_bar = '' | |
588 | |
589 r_bar = f'| {n_fmt}/{total_fmt} [{elapsed_str}<{remaining_str}, {rate_fmt}{postfix}]' | |
590 | |
591 # Custom bar formatting | |
592 # Populate a dict with all available progress indicators | |
593 format_dict = { | |
594 # slight extension of self.format_dict | |
595 'n': n, 'n_fmt': n_fmt, 'total': total, 'total_fmt': total_fmt, | |
596 'elapsed': elapsed_str, 'elapsed_s': elapsed, | |
597 'ncols': ncols, 'desc': prefix or '', 'unit': unit, | |
598 'rate': inv_rate if inv_rate and inv_rate > 1 else rate, | |
599 'rate_fmt': rate_fmt, 'rate_noinv': rate, | |
600 'rate_noinv_fmt': rate_noinv_fmt, 'rate_inv': inv_rate, | |
601 'rate_inv_fmt': rate_inv_fmt, | |
602 'postfix': postfix, 'unit_divisor': unit_divisor, | |
603 'colour': colour, | |
604 # plus more useful definitions | |
605 'remaining': remaining_str, 'remaining_s': remaining, | |
606 'l_bar': l_bar, 'r_bar': r_bar, 'eta': eta_dt, | |
607 **extra_kwargs} | |
608 | |
609 # total is known: we can predict some stats | |
610 if total: | |
611 # fractional and percentage progress | |
612 frac = n / total | |
613 percentage = frac * 100 | |
614 | |
615 l_bar += f'{percentage:3.0f}%|' | |
616 | |
617 if ncols == 0: | |
618 return l_bar[:-1] + r_bar[1:] | |
619 | |
620 format_dict.update(l_bar=l_bar) | |
621 if bar_format: | |
622 format_dict.update(percentage=percentage) | |
623 | |
624 # auto-remove colon for empty `{desc}` | |
625 if not prefix: | |
626 bar_format = bar_format.replace("{desc}: ", '') | |
627 else: | |
628 bar_format = "{l_bar}{bar}{r_bar}" | |
629 | |
630 full_bar = FormatReplace() | |
631 nobar = bar_format.format(bar=full_bar, **format_dict) | |
632 if not full_bar.format_called: | |
633 return nobar # no `{bar}`; nothing else to do | |
634 | |
635 # Formatting progress bar space available for bar's display | |
636 full_bar = Bar(frac, | |
637 max(1, ncols - disp_len(nobar)) if ncols else 10, | |
638 charset=Bar.ASCII if ascii is True else ascii or Bar.UTF, | |
639 colour=colour) | |
640 if not _is_ascii(full_bar.charset) and _is_ascii(bar_format): | |
641 bar_format = str(bar_format) | |
642 res = bar_format.format(bar=full_bar, **format_dict) | |
643 return disp_trim(res, ncols) if ncols else res | |
644 | |
645 elif bar_format: | |
646 # user-specified bar_format but no total | |
647 l_bar += '|' | |
648 format_dict.update(l_bar=l_bar, percentage=0) | |
649 full_bar = FormatReplace() | |
650 nobar = bar_format.format(bar=full_bar, **format_dict) | |
651 if not full_bar.format_called: | |
652 return nobar | |
653 full_bar = Bar(0, | |
654 max(1, ncols - disp_len(nobar)) if ncols else 10, | |
655 charset=Bar.BLANK, colour=colour) | |
656 res = bar_format.format(bar=full_bar, **format_dict) | |
657 return disp_trim(res, ncols) if ncols else res | |
658 else: | |
659 # no total: no progressbar, ETA, just progress stats | |
660 return (f'{(prefix + ": ") if prefix else ""}' | |
661 f'{n_fmt}{unit} [{elapsed_str}, {rate_fmt}{postfix}]') | |
662 | |
663 def __new__(cls, *_, **__): | |
664 instance = object.__new__(cls) | |
665 with cls.get_lock(): # also constructs lock if non-existent | |
666 cls._instances.add(instance) | |
667 # create monitoring thread | |
668 if cls.monitor_interval and (cls.monitor is None | |
669 or not cls.monitor.report()): | |
670 try: | |
671 cls.monitor = TMonitor(cls, cls.monitor_interval) | |
672 except Exception as e: # pragma: nocover | |
673 warn("tqdm:disabling monitor support" | |
674 " (monitor_interval = 0) due to:\n" + str(e), | |
675 TqdmMonitorWarning, stacklevel=2) | |
676 cls.monitor_interval = 0 | |
677 return instance | |
678 | |
679 @classmethod | |
680 def _get_free_pos(cls, instance=None): | |
681 """Skips specified instance.""" | |
682 positions = {abs(inst.pos) for inst in cls._instances | |
683 if inst is not instance and hasattr(inst, "pos")} | |
684 return min(set(range(len(positions) + 1)).difference(positions)) | |
685 | |
686 @classmethod | |
687 def _decr_instances(cls, instance): | |
688 """ | |
689 Remove from list and reposition another unfixed bar | |
690 to fill the new gap. | |
691 | |
692 This means that by default (where all nested bars are unfixed), | |
693 order is not maintained but screen flicker/blank space is minimised. | |
694 (tqdm<=4.44.1 moved ALL subsequent unfixed bars up.) | |
695 """ | |
696 with cls._lock: | |
697 try: | |
698 cls._instances.remove(instance) | |
699 except KeyError: | |
700 # if not instance.gui: # pragma: no cover | |
701 # raise | |
702 pass # py2: maybe magically removed already | |
703 # else: | |
704 if not instance.gui: | |
705 last = (instance.nrows or 20) - 1 | |
706 # find unfixed (`pos >= 0`) overflow (`pos >= nrows - 1`) | |
707 instances = list(filter( | |
708 lambda i: hasattr(i, "pos") and last <= i.pos, | |
709 cls._instances)) | |
710 # set first found to current `pos` | |
711 if instances: | |
712 inst = min(instances, key=lambda i: i.pos) | |
713 inst.clear(nolock=True) | |
714 inst.pos = abs(instance.pos) | |
715 | |
716 @classmethod | |
717 def write(cls, s, file=None, end="\n", nolock=False): | |
718 """Print a message via tqdm (without overlap with bars).""" | |
719 fp = file if file is not None else sys.stdout | |
720 with cls.external_write_mode(file=file, nolock=nolock): | |
721 # Write the message | |
722 fp.write(s) | |
723 fp.write(end) | |
724 | |
725 @classmethod | |
726 @contextmanager | |
727 def external_write_mode(cls, file=None, nolock=False): | |
728 """ | |
729 Disable tqdm within context and refresh tqdm when exits. | |
730 Useful when writing to standard output stream | |
731 """ | |
732 fp = file if file is not None else sys.stdout | |
733 | |
734 try: | |
735 if not nolock: | |
736 cls.get_lock().acquire() | |
737 # Clear all bars | |
738 inst_cleared = [] | |
739 for inst in getattr(cls, '_instances', []): | |
740 # Clear instance if in the target output file | |
741 # or if write output + tqdm output are both either | |
742 # sys.stdout or sys.stderr (because both are mixed in terminal) | |
743 if hasattr(inst, "start_t") and (inst.fp == fp or all( | |
744 f in (sys.stdout, sys.stderr) for f in (fp, inst.fp))): | |
745 inst.clear(nolock=True) | |
746 inst_cleared.append(inst) | |
747 yield | |
748 # Force refresh display of bars we cleared | |
749 for inst in inst_cleared: | |
750 inst.refresh(nolock=True) | |
751 finally: | |
752 if not nolock: | |
753 cls._lock.release() | |
754 | |
755 @classmethod | |
756 def set_lock(cls, lock): | |
757 """Set the global lock.""" | |
758 cls._lock = lock | |
759 | |
760 @classmethod | |
761 def get_lock(cls): | |
762 """Get the global lock. Construct it if it does not exist.""" | |
763 if not hasattr(cls, '_lock'): | |
764 cls._lock = TqdmDefaultWriteLock() | |
765 return cls._lock | |
766 | |
767 @classmethod | |
768 def pandas(cls, **tqdm_kwargs): | |
769 """ | |
770 Registers the current `tqdm` class with | |
771 pandas.core. | |
772 ( frame.DataFrame | |
773 | series.Series | |
774 | groupby.(generic.)DataFrameGroupBy | |
775 | groupby.(generic.)SeriesGroupBy | |
776 ).progress_apply | |
777 | |
778 A new instance will be created every time `progress_apply` is called, | |
779 and each instance will automatically `close()` upon completion. | |
780 | |
781 Parameters | |
782 ---------- | |
783 tqdm_kwargs : arguments for the tqdm instance | |
784 | |
785 Examples | |
786 -------- | |
787 >>> import pandas as pd | |
788 >>> import numpy as np | |
789 >>> from tqdm import tqdm | |
790 >>> from tqdm.gui import tqdm as tqdm_gui | |
791 >>> | |
792 >>> df = pd.DataFrame(np.random.randint(0, 100, (100000, 6))) | |
793 >>> tqdm.pandas(ncols=50) # can use tqdm_gui, optional kwargs, etc | |
794 >>> # Now you can use `progress_apply` instead of `apply` | |
795 >>> df.groupby(0).progress_apply(lambda x: x**2) | |
796 | |
797 References | |
798 ---------- | |
799 <https://stackoverflow.com/questions/18603270/\ | |
800 progress-indicator-during-pandas-operations-python> | |
801 """ | |
802 from warnings import catch_warnings, simplefilter | |
803 | |
804 from pandas.core.frame import DataFrame | |
805 from pandas.core.series import Series | |
806 try: | |
807 with catch_warnings(): | |
808 simplefilter("ignore", category=FutureWarning) | |
809 from pandas import Panel | |
810 except ImportError: # pandas>=1.2.0 | |
811 Panel = None | |
812 Rolling, Expanding = None, None | |
813 try: # pandas>=1.0.0 | |
814 from pandas.core.window.rolling import _Rolling_and_Expanding | |
815 except ImportError: | |
816 try: # pandas>=0.18.0 | |
817 from pandas.core.window import _Rolling_and_Expanding | |
818 except ImportError: # pandas>=1.2.0 | |
819 try: # pandas>=1.2.0 | |
820 from pandas.core.window.expanding import Expanding | |
821 from pandas.core.window.rolling import Rolling | |
822 _Rolling_and_Expanding = Rolling, Expanding | |
823 except ImportError: # pragma: no cover | |
824 _Rolling_and_Expanding = None | |
825 try: # pandas>=0.25.0 | |
826 from pandas.core.groupby.generic import SeriesGroupBy # , NDFrameGroupBy | |
827 from pandas.core.groupby.generic import DataFrameGroupBy | |
828 except ImportError: # pragma: no cover | |
829 try: # pandas>=0.23.0 | |
830 from pandas.core.groupby.groupby import DataFrameGroupBy, SeriesGroupBy | |
831 except ImportError: | |
832 from pandas.core.groupby import DataFrameGroupBy, SeriesGroupBy | |
833 try: # pandas>=0.23.0 | |
834 from pandas.core.groupby.groupby import GroupBy | |
835 except ImportError: # pragma: no cover | |
836 from pandas.core.groupby import GroupBy | |
837 | |
838 try: # pandas>=0.23.0 | |
839 from pandas.core.groupby.groupby import PanelGroupBy | |
840 except ImportError: | |
841 try: | |
842 from pandas.core.groupby import PanelGroupBy | |
843 except ImportError: # pandas>=0.25.0 | |
844 PanelGroupBy = None | |
845 | |
846 tqdm_kwargs = tqdm_kwargs.copy() | |
847 deprecated_t = [tqdm_kwargs.pop('deprecated_t', None)] | |
848 | |
849 def inner_generator(df_function='apply'): | |
850 def inner(df, func, *args, **kwargs): | |
851 """ | |
852 Parameters | |
853 ---------- | |
854 df : (DataFrame|Series)[GroupBy] | |
855 Data (may be grouped). | |
856 func : function | |
857 To be applied on the (grouped) data. | |
858 **kwargs : optional | |
859 Transmitted to `df.apply()`. | |
860 """ | |
861 | |
862 # Precompute total iterations | |
863 total = tqdm_kwargs.pop("total", getattr(df, 'ngroups', None)) | |
864 if total is None: # not grouped | |
865 if df_function == 'applymap': | |
866 total = df.size | |
867 elif isinstance(df, Series): | |
868 total = len(df) | |
869 elif (_Rolling_and_Expanding is None or | |
870 not isinstance(df, _Rolling_and_Expanding)): | |
871 # DataFrame or Panel | |
872 axis = kwargs.get('axis', 0) | |
873 if axis == 'index': | |
874 axis = 0 | |
875 elif axis == 'columns': | |
876 axis = 1 | |
877 # when axis=0, total is shape[axis1] | |
878 total = df.size // df.shape[axis] | |
879 | |
880 # Init bar | |
881 if deprecated_t[0] is not None: | |
882 t = deprecated_t[0] | |
883 deprecated_t[0] = None | |
884 else: | |
885 t = cls(total=total, **tqdm_kwargs) | |
886 | |
887 if len(args) > 0: | |
888 # *args intentionally not supported (see #244, #299) | |
889 TqdmDeprecationWarning( | |
890 "Except func, normal arguments are intentionally" + | |
891 " not supported by" + | |
892 " `(DataFrame|Series|GroupBy).progress_apply`." + | |
893 " Use keyword arguments instead.", | |
894 fp_write=getattr(t.fp, 'write', sys.stderr.write)) | |
895 | |
896 try: # pandas>=1.3.0 | |
897 from pandas.core.common import is_builtin_func | |
898 except ImportError: | |
899 is_builtin_func = df._is_builtin_func | |
900 try: | |
901 func = is_builtin_func(func) | |
902 except TypeError: | |
903 pass | |
904 | |
905 # Define bar updating wrapper | |
906 def wrapper(*args, **kwargs): | |
907 # update tbar correctly | |
908 # it seems `pandas apply` calls `func` twice | |
909 # on the first column/row to decide whether it can | |
910 # take a fast or slow code path; so stop when t.total==t.n | |
911 t.update(n=1 if not t.total or t.n < t.total else 0) | |
912 return func(*args, **kwargs) | |
913 | |
914 # Apply the provided function (in **kwargs) | |
915 # on the df using our wrapper (which provides bar updating) | |
916 try: | |
917 return getattr(df, df_function)(wrapper, **kwargs) | |
918 finally: | |
919 t.close() | |
920 | |
921 return inner | |
922 | |
923 # Monkeypatch pandas to provide easy methods | |
924 # Enable custom tqdm progress in pandas! | |
925 Series.progress_apply = inner_generator() | |
926 SeriesGroupBy.progress_apply = inner_generator() | |
927 Series.progress_map = inner_generator('map') | |
928 SeriesGroupBy.progress_map = inner_generator('map') | |
929 | |
930 DataFrame.progress_apply = inner_generator() | |
931 DataFrameGroupBy.progress_apply = inner_generator() | |
932 DataFrame.progress_applymap = inner_generator('applymap') | |
933 DataFrame.progress_map = inner_generator('map') | |
934 DataFrameGroupBy.progress_map = inner_generator('map') | |
935 | |
936 if Panel is not None: | |
937 Panel.progress_apply = inner_generator() | |
938 if PanelGroupBy is not None: | |
939 PanelGroupBy.progress_apply = inner_generator() | |
940 | |
941 GroupBy.progress_apply = inner_generator() | |
942 GroupBy.progress_aggregate = inner_generator('aggregate') | |
943 GroupBy.progress_transform = inner_generator('transform') | |
944 | |
945 if Rolling is not None and Expanding is not None: | |
946 Rolling.progress_apply = inner_generator() | |
947 Expanding.progress_apply = inner_generator() | |
948 elif _Rolling_and_Expanding is not None: | |
949 _Rolling_and_Expanding.progress_apply = inner_generator() | |
950 | |
951 # override defaults via env vars | |
952 @envwrap("TQDM_", is_method=True, types={'total': float, 'ncols': int, 'miniters': float, | |
953 'position': int, 'nrows': int}) | |
954 def __init__(self, iterable=None, desc=None, total=None, leave=True, file=None, | |
955 ncols=None, mininterval=0.1, maxinterval=10.0, miniters=None, | |
956 ascii=None, disable=False, unit='it', unit_scale=False, | |
957 dynamic_ncols=False, smoothing=0.3, bar_format=None, initial=0, | |
958 position=None, postfix=None, unit_divisor=1000, write_bytes=False, | |
959 lock_args=None, nrows=None, colour=None, delay=0.0, gui=False, | |
960 **kwargs): | |
961 """see tqdm.tqdm for arguments""" | |
962 if file is None: | |
963 file = sys.stderr | |
964 | |
965 if write_bytes: | |
966 # Despite coercing unicode into bytes, py2 sys.std* streams | |
967 # should have bytes written to them. | |
968 file = SimpleTextIOWrapper( | |
969 file, encoding=getattr(file, 'encoding', None) or 'utf-8') | |
970 | |
971 file = DisableOnWriteError(file, tqdm_instance=self) | |
972 | |
973 if disable is None and hasattr(file, "isatty") and not file.isatty(): | |
974 disable = True | |
975 | |
976 if total is None and iterable is not None: | |
977 try: | |
978 total = len(iterable) | |
979 except (TypeError, AttributeError): | |
980 total = None | |
981 if total == float("inf"): | |
982 # Infinite iterations, behave same as unknown | |
983 total = None | |
984 | |
985 if disable: | |
986 self.iterable = iterable | |
987 self.disable = disable | |
988 with self._lock: | |
989 self.pos = self._get_free_pos(self) | |
990 self._instances.remove(self) | |
991 self.n = initial | |
992 self.total = total | |
993 self.leave = leave | |
994 return | |
995 | |
996 if kwargs: | |
997 self.disable = True | |
998 with self._lock: | |
999 self.pos = self._get_free_pos(self) | |
1000 self._instances.remove(self) | |
1001 raise ( | |
1002 TqdmDeprecationWarning( | |
1003 "`nested` is deprecated and automated.\n" | |
1004 "Use `position` instead for manual control.\n", | |
1005 fp_write=getattr(file, 'write', sys.stderr.write)) | |
1006 if "nested" in kwargs else | |
1007 TqdmKeyError("Unknown argument(s): " + str(kwargs))) | |
1008 | |
1009 # Preprocess the arguments | |
1010 if ( | |
1011 (ncols is None or nrows is None) and (file in (sys.stderr, sys.stdout)) | |
1012 ) or dynamic_ncols: # pragma: no cover | |
1013 if dynamic_ncols: | |
1014 dynamic_ncols = _screen_shape_wrapper() | |
1015 if dynamic_ncols: | |
1016 ncols, nrows = dynamic_ncols(file) | |
1017 else: | |
1018 _dynamic_ncols = _screen_shape_wrapper() | |
1019 if _dynamic_ncols: | |
1020 _ncols, _nrows = _dynamic_ncols(file) | |
1021 if ncols is None: | |
1022 ncols = _ncols | |
1023 if nrows is None: | |
1024 nrows = _nrows | |
1025 | |
1026 if miniters is None: | |
1027 miniters = 0 | |
1028 dynamic_miniters = True | |
1029 else: | |
1030 dynamic_miniters = False | |
1031 | |
1032 if mininterval is None: | |
1033 mininterval = 0 | |
1034 | |
1035 if maxinterval is None: | |
1036 maxinterval = 0 | |
1037 | |
1038 if ascii is None: | |
1039 ascii = not _supports_unicode(file) | |
1040 | |
1041 if bar_format and ascii is not True and not _is_ascii(ascii): | |
1042 # Convert bar format into unicode since terminal uses unicode | |
1043 bar_format = str(bar_format) | |
1044 | |
1045 if smoothing is None: | |
1046 smoothing = 0 | |
1047 | |
1048 # Store the arguments | |
1049 self.iterable = iterable | |
1050 self.desc = desc or '' | |
1051 self.total = total | |
1052 self.leave = leave | |
1053 self.fp = file | |
1054 self.ncols = ncols | |
1055 self.nrows = nrows | |
1056 self.mininterval = mininterval | |
1057 self.maxinterval = maxinterval | |
1058 self.miniters = miniters | |
1059 self.dynamic_miniters = dynamic_miniters | |
1060 self.ascii = ascii | |
1061 self.disable = disable | |
1062 self.unit = unit | |
1063 self.unit_scale = unit_scale | |
1064 self.unit_divisor = unit_divisor | |
1065 self.initial = initial | |
1066 self.lock_args = lock_args | |
1067 self.delay = delay | |
1068 self.gui = gui | |
1069 self.dynamic_ncols = dynamic_ncols | |
1070 self.smoothing = smoothing | |
1071 self._ema_dn = EMA(smoothing) | |
1072 self._ema_dt = EMA(smoothing) | |
1073 self._ema_miniters = EMA(smoothing) | |
1074 self.bar_format = bar_format | |
1075 self.postfix = None | |
1076 self.colour = colour | |
1077 self._time = time | |
1078 if postfix: | |
1079 try: | |
1080 self.set_postfix(refresh=False, **postfix) | |
1081 except TypeError: | |
1082 self.postfix = postfix | |
1083 | |
1084 # Init the iterations counters | |
1085 self.last_print_n = initial | |
1086 self.n = initial | |
1087 | |
1088 # if nested, at initial sp() call we replace '\r' by '\n' to | |
1089 # not overwrite the outer progress bar | |
1090 with self._lock: | |
1091 # mark fixed positions as negative | |
1092 self.pos = self._get_free_pos(self) if position is None else -position | |
1093 | |
1094 if not gui: | |
1095 # Initialize the screen printer | |
1096 self.sp = self.status_printer(self.fp) | |
1097 if delay <= 0: | |
1098 self.refresh(lock_args=self.lock_args) | |
1099 | |
1100 # Init the time counter | |
1101 self.last_print_t = self._time() | |
1102 # NB: Avoid race conditions by setting start_t at the very end of init | |
1103 self.start_t = self.last_print_t | |
1104 | |
1105 def __bool__(self): | |
1106 if self.total is not None: | |
1107 return self.total > 0 | |
1108 if self.iterable is None: | |
1109 raise TypeError('bool() undefined when iterable == total == None') | |
1110 return bool(self.iterable) | |
1111 | |
1112 def __len__(self): | |
1113 return ( | |
1114 self.total if self.iterable is None | |
1115 else self.iterable.shape[0] if hasattr(self.iterable, "shape") | |
1116 else len(self.iterable) if hasattr(self.iterable, "__len__") | |
1117 else self.iterable.__length_hint__() if hasattr(self.iterable, "__length_hint__") | |
1118 else getattr(self, "total", None)) | |
1119 | |
1120 def __reversed__(self): | |
1121 try: | |
1122 orig = self.iterable | |
1123 except AttributeError: | |
1124 raise TypeError("'tqdm' object is not reversible") | |
1125 else: | |
1126 self.iterable = reversed(self.iterable) | |
1127 return self.__iter__() | |
1128 finally: | |
1129 self.iterable = orig | |
1130 | |
1131 def __contains__(self, item): | |
1132 contains = getattr(self.iterable, '__contains__', None) | |
1133 return contains(item) if contains is not None else item in self.__iter__() | |
1134 | |
1135 def __enter__(self): | |
1136 return self | |
1137 | |
1138 def __exit__(self, exc_type, exc_value, traceback): | |
1139 try: | |
1140 self.close() | |
1141 except AttributeError: | |
1142 # maybe eager thread cleanup upon external error | |
1143 if (exc_type, exc_value, traceback) == (None, None, None): | |
1144 raise | |
1145 warn("AttributeError ignored", TqdmWarning, stacklevel=2) | |
1146 | |
1147 def __del__(self): | |
1148 self.close() | |
1149 | |
1150 def __str__(self): | |
1151 return self.format_meter(**self.format_dict) | |
1152 | |
1153 @property | |
1154 def _comparable(self): | |
1155 return abs(getattr(self, "pos", 1 << 31)) | |
1156 | |
1157 def __hash__(self): | |
1158 return id(self) | |
1159 | |
1160 def __iter__(self): | |
1161 """Backward-compatibility to use: for x in tqdm(iterable)""" | |
1162 | |
1163 # Inlining instance variables as locals (speed optimisation) | |
1164 iterable = self.iterable | |
1165 | |
1166 # If the bar is disabled, then just walk the iterable | |
1167 # (note: keep this check outside the loop for performance) | |
1168 if self.disable: | |
1169 for obj in iterable: | |
1170 yield obj | |
1171 return | |
1172 | |
1173 mininterval = self.mininterval | |
1174 last_print_t = self.last_print_t | |
1175 last_print_n = self.last_print_n | |
1176 min_start_t = self.start_t + self.delay | |
1177 n = self.n | |
1178 time = self._time | |
1179 | |
1180 try: | |
1181 for obj in iterable: | |
1182 yield obj | |
1183 # Update and possibly print the progressbar. | |
1184 # Note: does not call self.update(1) for speed optimisation. | |
1185 n += 1 | |
1186 | |
1187 if n - last_print_n >= self.miniters: | |
1188 cur_t = time() | |
1189 dt = cur_t - last_print_t | |
1190 if dt >= mininterval and cur_t >= min_start_t: | |
1191 self.update(n - last_print_n) | |
1192 last_print_n = self.last_print_n | |
1193 last_print_t = self.last_print_t | |
1194 finally: | |
1195 self.n = n | |
1196 self.close() | |
1197 | |
1198 def update(self, n=1): | |
1199 """ | |
1200 Manually update the progress bar, useful for streams | |
1201 such as reading files. | |
1202 E.g.: | |
1203 >>> t = tqdm(total=filesize) # Initialise | |
1204 >>> for current_buffer in stream: | |
1205 ... ... | |
1206 ... t.update(len(current_buffer)) | |
1207 >>> t.close() | |
1208 The last line is highly recommended, but possibly not necessary if | |
1209 `t.update()` will be called in such a way that `filesize` will be | |
1210 exactly reached and printed. | |
1211 | |
1212 Parameters | |
1213 ---------- | |
1214 n : int or float, optional | |
1215 Increment to add to the internal counter of iterations | |
1216 [default: 1]. If using float, consider specifying `{n:.3f}` | |
1217 or similar in `bar_format`, or specifying `unit_scale`. | |
1218 | |
1219 Returns | |
1220 ------- | |
1221 out : bool or None | |
1222 True if a `display()` was triggered. | |
1223 """ | |
1224 if self.disable: | |
1225 return | |
1226 | |
1227 if n < 0: | |
1228 self.last_print_n += n # for auto-refresh logic to work | |
1229 self.n += n | |
1230 | |
1231 # check counter first to reduce calls to time() | |
1232 if self.n - self.last_print_n >= self.miniters: | |
1233 cur_t = self._time() | |
1234 dt = cur_t - self.last_print_t | |
1235 if dt >= self.mininterval and cur_t >= self.start_t + self.delay: | |
1236 cur_t = self._time() | |
1237 dn = self.n - self.last_print_n # >= n | |
1238 if self.smoothing and dt and dn: | |
1239 # EMA (not just overall average) | |
1240 self._ema_dn(dn) | |
1241 self._ema_dt(dt) | |
1242 self.refresh(lock_args=self.lock_args) | |
1243 if self.dynamic_miniters: | |
1244 # If no `miniters` was specified, adjust automatically to the | |
1245 # maximum iteration rate seen so far between two prints. | |
1246 # e.g.: After running `tqdm.update(5)`, subsequent | |
1247 # calls to `tqdm.update()` will only cause an update after | |
1248 # at least 5 more iterations. | |
1249 if self.maxinterval and dt >= self.maxinterval: | |
1250 self.miniters = dn * (self.mininterval or self.maxinterval) / dt | |
1251 elif self.smoothing: | |
1252 # EMA miniters update | |
1253 self.miniters = self._ema_miniters( | |
1254 dn * (self.mininterval / dt if self.mininterval and dt | |
1255 else 1)) | |
1256 else: | |
1257 # max iters between two prints | |
1258 self.miniters = max(self.miniters, dn) | |
1259 | |
1260 # Store old values for next call | |
1261 self.last_print_n = self.n | |
1262 self.last_print_t = cur_t | |
1263 return True | |
1264 | |
1265 def close(self): | |
1266 """Cleanup and (if leave=False) close the progressbar.""" | |
1267 if self.disable: | |
1268 return | |
1269 | |
1270 # Prevent multiple closures | |
1271 self.disable = True | |
1272 | |
1273 # decrement instance pos and remove from internal set | |
1274 pos = abs(self.pos) | |
1275 self._decr_instances(self) | |
1276 | |
1277 if self.last_print_t < self.start_t + self.delay: | |
1278 # haven't ever displayed; nothing to clear | |
1279 return | |
1280 | |
1281 # GUI mode | |
1282 if getattr(self, 'sp', None) is None: | |
1283 return | |
1284 | |
1285 # annoyingly, _supports_unicode isn't good enough | |
1286 def fp_write(s): | |
1287 self.fp.write(str(s)) | |
1288 | |
1289 try: | |
1290 fp_write('') | |
1291 except ValueError as e: | |
1292 if 'closed' in str(e): | |
1293 return | |
1294 raise # pragma: no cover | |
1295 | |
1296 leave = pos == 0 if self.leave is None else self.leave | |
1297 | |
1298 with self._lock: | |
1299 if leave: | |
1300 # stats for overall rate (no weighted average) | |
1301 self._ema_dt = lambda: None | |
1302 self.display(pos=0) | |
1303 fp_write('\n') | |
1304 else: | |
1305 # clear previous display | |
1306 if self.display(msg='', pos=pos) and not pos: | |
1307 fp_write('\r') | |
1308 | |
1309 def clear(self, nolock=False): | |
1310 """Clear current bar display.""" | |
1311 if self.disable: | |
1312 return | |
1313 | |
1314 if not nolock: | |
1315 self._lock.acquire() | |
1316 pos = abs(self.pos) | |
1317 if pos < (self.nrows or 20): | |
1318 self.moveto(pos) | |
1319 self.sp('') | |
1320 self.fp.write('\r') # place cursor back at the beginning of line | |
1321 self.moveto(-pos) | |
1322 if not nolock: | |
1323 self._lock.release() | |
1324 | |
1325 def refresh(self, nolock=False, lock_args=None): | |
1326 """ | |
1327 Force refresh the display of this bar. | |
1328 | |
1329 Parameters | |
1330 ---------- | |
1331 nolock : bool, optional | |
1332 If `True`, does not lock. | |
1333 If [default: `False`]: calls `acquire()` on internal lock. | |
1334 lock_args : tuple, optional | |
1335 Passed to internal lock's `acquire()`. | |
1336 If specified, will only `display()` if `acquire()` returns `True`. | |
1337 """ | |
1338 if self.disable: | |
1339 return | |
1340 | |
1341 if not nolock: | |
1342 if lock_args: | |
1343 if not self._lock.acquire(*lock_args): | |
1344 return False | |
1345 else: | |
1346 self._lock.acquire() | |
1347 self.display() | |
1348 if not nolock: | |
1349 self._lock.release() | |
1350 return True | |
1351 | |
1352 def unpause(self): | |
1353 """Restart tqdm timer from last print time.""" | |
1354 if self.disable: | |
1355 return | |
1356 cur_t = self._time() | |
1357 self.start_t += cur_t - self.last_print_t | |
1358 self.last_print_t = cur_t | |
1359 | |
1360 def reset(self, total=None): | |
1361 """ | |
1362 Resets to 0 iterations for repeated use. | |
1363 | |
1364 Consider combining with `leave=True`. | |
1365 | |
1366 Parameters | |
1367 ---------- | |
1368 total : int or float, optional. Total to use for the new bar. | |
1369 """ | |
1370 self.n = 0 | |
1371 if total is not None: | |
1372 self.total = total | |
1373 if self.disable: | |
1374 return | |
1375 self.last_print_n = 0 | |
1376 self.last_print_t = self.start_t = self._time() | |
1377 self._ema_dn = EMA(self.smoothing) | |
1378 self._ema_dt = EMA(self.smoothing) | |
1379 self._ema_miniters = EMA(self.smoothing) | |
1380 self.refresh() | |
1381 | |
1382 def set_description(self, desc=None, refresh=True): | |
1383 """ | |
1384 Set/modify description of the progress bar. | |
1385 | |
1386 Parameters | |
1387 ---------- | |
1388 desc : str, optional | |
1389 refresh : bool, optional | |
1390 Forces refresh [default: True]. | |
1391 """ | |
1392 self.desc = desc + ': ' if desc else '' | |
1393 if refresh: | |
1394 self.refresh() | |
1395 | |
1396 def set_description_str(self, desc=None, refresh=True): | |
1397 """Set/modify description without ': ' appended.""" | |
1398 self.desc = desc or '' | |
1399 if refresh: | |
1400 self.refresh() | |
1401 | |
1402 def set_postfix(self, ordered_dict=None, refresh=True, **kwargs): | |
1403 """ | |
1404 Set/modify postfix (additional stats) | |
1405 with automatic formatting based on datatype. | |
1406 | |
1407 Parameters | |
1408 ---------- | |
1409 ordered_dict : dict or OrderedDict, optional | |
1410 refresh : bool, optional | |
1411 Forces refresh [default: True]. | |
1412 kwargs : dict, optional | |
1413 """ | |
1414 # Sort in alphabetical order to be more deterministic | |
1415 postfix = OrderedDict([] if ordered_dict is None else ordered_dict) | |
1416 for key in sorted(kwargs.keys()): | |
1417 postfix[key] = kwargs[key] | |
1418 # Preprocess stats according to datatype | |
1419 for key in postfix.keys(): | |
1420 # Number: limit the length of the string | |
1421 if isinstance(postfix[key], Number): | |
1422 postfix[key] = self.format_num(postfix[key]) | |
1423 # Else for any other type, try to get the string conversion | |
1424 elif not isinstance(postfix[key], str): | |
1425 postfix[key] = str(postfix[key]) | |
1426 # Else if it's a string, don't need to preprocess anything | |
1427 # Stitch together to get the final postfix | |
1428 self.postfix = ', '.join(key + '=' + postfix[key].strip() | |
1429 for key in postfix.keys()) | |
1430 if refresh: | |
1431 self.refresh() | |
1432 | |
1433 def set_postfix_str(self, s='', refresh=True): | |
1434 """ | |
1435 Postfix without dictionary expansion, similar to prefix handling. | |
1436 """ | |
1437 self.postfix = str(s) | |
1438 if refresh: | |
1439 self.refresh() | |
1440 | |
1441 def moveto(self, n): | |
1442 # TODO: private method | |
1443 self.fp.write('\n' * n + _term_move_up() * -n) | |
1444 getattr(self.fp, 'flush', lambda: None)() | |
1445 | |
1446 @property | |
1447 def format_dict(self): | |
1448 """Public API for read-only member access.""" | |
1449 if self.disable and not hasattr(self, 'unit'): | |
1450 return defaultdict(lambda: None, { | |
1451 'n': self.n, 'total': self.total, 'elapsed': 0, 'unit': 'it'}) | |
1452 if self.dynamic_ncols: | |
1453 self.ncols, self.nrows = self.dynamic_ncols(self.fp) | |
1454 return { | |
1455 'n': self.n, 'total': self.total, | |
1456 'elapsed': self._time() - self.start_t if hasattr(self, 'start_t') else 0, | |
1457 'ncols': self.ncols, 'nrows': self.nrows, 'prefix': self.desc, | |
1458 'ascii': self.ascii, 'unit': self.unit, 'unit_scale': self.unit_scale, | |
1459 'rate': self._ema_dn() / self._ema_dt() if self._ema_dt() else None, | |
1460 'bar_format': self.bar_format, 'postfix': self.postfix, | |
1461 'unit_divisor': self.unit_divisor, 'initial': self.initial, | |
1462 'colour': self.colour} | |
1463 | |
1464 def display(self, msg=None, pos=None): | |
1465 """ | |
1466 Use `self.sp` to display `msg` in the specified `pos`. | |
1467 | |
1468 Consider overloading this function when inheriting to use e.g.: | |
1469 `self.some_frontend(**self.format_dict)` instead of `self.sp`. | |
1470 | |
1471 Parameters | |
1472 ---------- | |
1473 msg : str, optional. What to display (default: `repr(self)`). | |
1474 pos : int, optional. Position to `moveto` | |
1475 (default: `abs(self.pos)`). | |
1476 """ | |
1477 if pos is None: | |
1478 pos = abs(self.pos) | |
1479 | |
1480 nrows = self.nrows or 20 | |
1481 if pos >= nrows - 1: | |
1482 if pos >= nrows: | |
1483 return False | |
1484 if msg or msg is None: # override at `nrows - 1` | |
1485 msg = " ... (more hidden) ..." | |
1486 | |
1487 if not hasattr(self, "sp"): | |
1488 raise TqdmDeprecationWarning( | |
1489 "Please use `tqdm.gui.tqdm(...)`" | |
1490 " instead of `tqdm(..., gui=True)`\n", | |
1491 fp_write=getattr(self.fp, 'write', sys.stderr.write)) | |
1492 | |
1493 if pos: | |
1494 self.moveto(pos) | |
1495 self.sp(self.__str__() if msg is None else msg) | |
1496 if pos: | |
1497 self.moveto(-pos) | |
1498 return True | |
1499 | |
1500 @classmethod | |
1501 @contextmanager | |
1502 def wrapattr(cls, stream, method, total=None, bytes=True, **tqdm_kwargs): | |
1503 """ | |
1504 stream : file-like object. | |
1505 method : str, "read" or "write". The result of `read()` and | |
1506 the first argument of `write()` should have a `len()`. | |
1507 | |
1508 >>> with tqdm.wrapattr(file_obj, "read", total=file_obj.size) as fobj: | |
1509 ... while True: | |
1510 ... chunk = fobj.read(chunk_size) | |
1511 ... if not chunk: | |
1512 ... break | |
1513 """ | |
1514 with cls(total=total, **tqdm_kwargs) as t: | |
1515 if bytes: | |
1516 t.unit = "B" | |
1517 t.unit_scale = True | |
1518 t.unit_divisor = 1024 | |
1519 yield CallbackIOWrapper(t.update, stream, method) | |
1520 | |
1521 | |
1522 def trange(*args, **kwargs): | |
1523 """Shortcut for tqdm(range(*args), **kwargs).""" | |
1524 return tqdm(range(*args), **kwargs) |