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