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): # allow float imprecision (#849)
534 total = None
536 # apply custom scale if necessary
537 if unit_scale and unit_scale not in (True, 1):
538 if total:
539 total *= unit_scale
540 n *= unit_scale
541 if rate:
542 rate *= unit_scale # by default rate = self.avg_dn / self.avg_dt
543 unit_scale = False
545 elapsed_str = tqdm.format_interval(elapsed)
547 # if unspecified, attempt to use rate = average speed
548 # (we allow manual override since predicting time is an arcane art)
549 if rate is None and elapsed:
550 rate = (n - initial) / elapsed
551 inv_rate = 1 / rate if rate else None
552 format_sizeof = tqdm.format_sizeof
553 rate_noinv_fmt = ((format_sizeof(rate) if unit_scale else f'{rate:5.2f}')
554 if rate else '?') + unit + '/s'
555 rate_inv_fmt = (
556 (format_sizeof(inv_rate) if unit_scale else f'{inv_rate:5.2f}')
557 if inv_rate else '?') + 's/' + unit
558 rate_fmt = rate_inv_fmt if inv_rate and inv_rate > 1 else rate_noinv_fmt
560 if unit_scale:
561 n_fmt = format_sizeof(n, divisor=unit_divisor)
562 total_fmt = format_sizeof(total, divisor=unit_divisor) if total is not None else '?'
563 else:
564 n_fmt = str(n)
565 total_fmt = str(total) if total is not None else '?'
567 try:
568 postfix = ', ' + postfix if postfix else ''
569 except TypeError:
570 pass
572 remaining = (total - n) / rate if rate and total else 0
573 remaining_str = tqdm.format_interval(remaining) if rate else '?'
574 try:
575 eta_dt = (datetime.now() + timedelta(seconds=remaining)
576 if rate and total else datetime.fromtimestamp(0, timezone.utc))
577 except OverflowError:
578 eta_dt = datetime.max
580 # format the stats displayed to the left and right sides of the bar
581 if prefix:
582 # old prefix setup work around
583 bool_prefix_colon_already = (prefix[-2:] == ": ")
584 l_bar = prefix if bool_prefix_colon_already else prefix + ": "
585 else:
586 l_bar = ''
588 r_bar = f'| {n_fmt}/{total_fmt} [{elapsed_str}<{remaining_str}, {rate_fmt}{postfix}]'
590 # Custom bar formatting
591 # Populate a dict with all available progress indicators
592 format_dict = {
593 # slight extension of self.format_dict
594 'n': n, 'n_fmt': n_fmt, 'total': total, 'total_fmt': total_fmt,
595 'elapsed': elapsed_str, 'elapsed_s': elapsed,
596 'ncols': ncols, 'desc': prefix or '', 'unit': unit,
597 'rate': inv_rate if inv_rate and inv_rate > 1 else rate,
598 'rate_fmt': rate_fmt, 'rate_noinv': rate,
599 'rate_noinv_fmt': rate_noinv_fmt, 'rate_inv': inv_rate,
600 'rate_inv_fmt': rate_inv_fmt,
601 'postfix': postfix, 'unit_divisor': unit_divisor,
602 'colour': colour,
603 # plus more useful definitions
604 'remaining': remaining_str, 'remaining_s': remaining,
605 'l_bar': l_bar, 'r_bar': r_bar, 'eta': eta_dt,
606 **extra_kwargs}
608 # total is known: we can predict some stats
609 if total:
610 # fractional and percentage progress
611 frac = n / total
612 percentage = frac * 100
614 l_bar += f'{percentage:3.0f}%|'
616 if ncols == 0:
617 return l_bar[:-1] + r_bar[1:]
619 format_dict.update(l_bar=l_bar)
620 if bar_format:
621 format_dict.update(percentage=percentage)
623 # auto-remove colon for empty `{desc}`
624 if not prefix:
625 bar_format = bar_format.replace("{desc}: ", '')
626 else:
627 bar_format = "{l_bar}{bar}{r_bar}"
629 full_bar = FormatReplace()
630 nobar = bar_format.format(bar=full_bar, **format_dict) # no `{bar}`
631 if not full_bar.format_called:
632 return disp_trim(nobar, ncols) if ncols else nobar
634 # Formatting progress bar space available for bar's display
635 full_bar = Bar(frac,
636 max(1, ncols - disp_len(nobar)) if ncols else 10,
637 charset=Bar.ASCII if ascii is True else ascii or Bar.UTF,
638 colour=colour)
639 if not _is_ascii(full_bar.charset) and _is_ascii(bar_format):
640 bar_format = str(bar_format)
641 res = bar_format.format(bar=full_bar, **format_dict)
642 return disp_trim(res, ncols) if ncols else res
644 elif bar_format:
645 # user-specified bar_format but no total
646 l_bar += '|'
647 format_dict.update(l_bar=l_bar, percentage=0)
648 full_bar = FormatReplace()
649 nobar = bar_format.format(bar=full_bar, **format_dict)
650 if not full_bar.format_called:
651 return disp_trim(nobar, ncols) if ncols else nobar
652 full_bar = Bar(0,
653 max(1, ncols - disp_len(nobar)) if ncols else 10,
654 charset=Bar.BLANK, colour=colour)
655 res = bar_format.format(bar=full_bar, **format_dict)
656 return disp_trim(res, ncols) if ncols else res
657 else:
658 # no total: no bar & ETA, just progress stats
659 res = (f'{(prefix + ": ") if prefix else ""}'
660 f'{n_fmt}{unit} [{elapsed_str}, {rate_fmt}{postfix}]')
661 return disp_trim(res, ncols) if ncols else res
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
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))
686 @classmethod
687 def _decr_instances(cls, instance):
688 """
689 Remove from list and reposition another unfixed bar
690 to fill the new gap.
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)
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 if fp is None:
721 return
722 with cls.external_write_mode(file=file, nolock=nolock):
723 # Write the message
724 fp.write(s)
725 fp.write(end)
727 @classmethod
728 @contextmanager
729 def external_write_mode(cls, file=None, nolock=False):
730 """
731 Disable tqdm within context and refresh tqdm when exits.
732 Useful when writing to standard output stream
733 """
734 fp = file if file is not None else sys.stdout
735 if fp is None:
736 yield
737 return
739 try:
740 if not nolock:
741 cls.get_lock().acquire()
742 # Clear all bars
743 inst_cleared = []
744 for inst in getattr(cls, '_instances', []):
745 # Clear instance if in the target output file
746 # or if write output + tqdm output are both either
747 # sys.stdout or sys.stderr (because both are mixed in terminal)
748 if hasattr(inst, "start_t") and (inst.fp == fp or all(
749 f in (sys.stdout, sys.stderr) for f in (fp, inst.fp))):
750 inst.clear(nolock=True)
751 inst_cleared.append(inst)
752 yield
753 # Force refresh display of bars we cleared
754 for inst in inst_cleared:
755 inst.refresh(nolock=True)
756 finally:
757 if not nolock:
758 cls._lock.release()
760 @classmethod
761 def set_lock(cls, lock):
762 """Set the global lock."""
763 cls._lock = lock
765 @classmethod
766 def get_lock(cls):
767 """Get the global lock. Construct it if it does not exist."""
768 if not hasattr(cls, '_lock'):
769 cls._lock = TqdmDefaultWriteLock()
770 return cls._lock
772 @classmethod
773 def pandas(cls, **tqdm_kwargs):
774 """
775 Registers the current `tqdm` class with
776 pandas.core.
777 ( frame.DataFrame
778 | series.Series
779 | groupby.(generic.)DataFrameGroupBy
780 | groupby.(generic.)SeriesGroupBy
781 ).progress_apply
783 A new instance will be created every time `progress_apply` is called,
784 and each instance will automatically `close()` upon completion.
786 Parameters
787 ----------
788 tqdm_kwargs : arguments for the tqdm instance
790 Examples
791 --------
792 >>> import pandas as pd
793 >>> import numpy as np
794 >>> from tqdm import tqdm
795 >>> from tqdm.gui import tqdm as tqdm_gui
796 >>>
797 >>> df = pd.DataFrame(np.random.randint(0, 100, (100000, 6)))
798 >>> tqdm.pandas(ncols=50) # can use tqdm_gui, optional kwargs, etc
799 >>> # Now you can use `progress_apply` instead of `apply`
800 >>> df.groupby(0).progress_apply(lambda x: x**2)
802 References
803 ----------
804 <https://stackoverflow.com/questions/18603270/\
805 progress-indicator-during-pandas-operations-python>
806 """
807 from warnings import catch_warnings, simplefilter
809 from pandas.core.frame import DataFrame
810 from pandas.core.series import Series
811 try:
812 with catch_warnings():
813 simplefilter("ignore", category=FutureWarning)
814 from pandas import Panel
815 except ImportError: # pandas>=1.2.0
816 Panel = None
817 Rolling, Expanding = None, None
818 try: # pandas>=1.0.0
819 from pandas.core.window.rolling import _Rolling_and_Expanding
820 except ImportError:
821 try: # pandas>=0.18.0
822 from pandas.core.window import _Rolling_and_Expanding
823 except ImportError: # pandas>=1.2.0
824 try: # pandas>=1.2.0
825 from pandas.core.window.expanding import Expanding
826 from pandas.core.window.rolling import Rolling
827 _Rolling_and_Expanding = Rolling, Expanding
828 except ImportError: # pragma: no cover
829 _Rolling_and_Expanding = None
830 try: # pandas>=0.25.0
831 from pandas.core.groupby.generic import SeriesGroupBy # , NDFrameGroupBy
832 from pandas.core.groupby.generic import DataFrameGroupBy
833 except ImportError: # pragma: no cover
834 try: # pandas>=0.23.0
835 from pandas.core.groupby.groupby import DataFrameGroupBy, SeriesGroupBy
836 except ImportError:
837 from pandas.core.groupby import DataFrameGroupBy, SeriesGroupBy
838 try: # pandas>=0.23.0
839 from pandas.core.groupby.groupby import GroupBy
840 except ImportError: # pragma: no cover
841 from pandas.core.groupby import GroupBy
843 try: # pandas>=0.23.0
844 from pandas.core.groupby.groupby import PanelGroupBy
845 except ImportError:
846 try:
847 from pandas.core.groupby import PanelGroupBy
848 except ImportError: # pandas>=0.25.0
849 PanelGroupBy = None
851 tqdm_kwargs = tqdm_kwargs.copy()
852 deprecated_t = [tqdm_kwargs.pop('deprecated_t', None)]
854 def inner_generator(df_function='apply'):
855 def inner(df, func, *args, **kwargs):
856 """
857 Parameters
858 ----------
859 df : (DataFrame|Series)[GroupBy]
860 Data (may be grouped).
861 func : function
862 To be applied on the (grouped) data.
863 **kwargs : optional
864 Transmitted to `df.apply()`.
865 """
867 # Precompute total iterations
868 total = tqdm_kwargs.pop("total", getattr(df, 'ngroups', None))
869 if total is None: # not grouped
870 if df_function == 'applymap':
871 total = df.size
872 elif isinstance(df, Series):
873 total = len(df)
874 elif (_Rolling_and_Expanding is None or
875 not isinstance(df, _Rolling_and_Expanding)):
876 # DataFrame or Panel
877 axis = kwargs.get('axis', 0)
878 if axis == 'index':
879 axis = 0
880 elif axis == 'columns':
881 axis = 1
882 # when axis=0, total is shape[axis1]
883 total = df.size // df.shape[axis]
885 # Init bar
886 if deprecated_t[0] is not None:
887 t = deprecated_t[0]
888 deprecated_t[0] = None
889 else:
890 t = cls(total=total, **tqdm_kwargs)
892 if len(args) > 0:
893 # *args intentionally not supported (see #244, #299)
894 TqdmDeprecationWarning(
895 "Except func, normal arguments are intentionally" +
896 " not supported by" +
897 " `(DataFrame|Series|GroupBy).progress_apply`." +
898 " Use keyword arguments instead.",
899 fp_write=getattr(t.fp, 'write', sys.stderr.write))
901 try: # pandas>=1.3.0,<3.0
902 from pandas.core.common import is_builtin_func
903 except ImportError: # pandas<1.3.0
904 is_builtin_func = getattr(df, '_is_builtin_func', lambda f: f)
905 try:
906 func = is_builtin_func(func)
907 except TypeError:
908 pass
910 # Define bar updating wrapper
911 def wrapper(*args, **kwargs):
912 # update tbar correctly
913 # it seems `pandas apply` calls `func` twice
914 # on the first column/row to decide whether it can
915 # take a fast or slow code path; so stop when t.total==t.n
916 t.update(n=1 if not t.total or t.n < t.total else 0)
917 return func(*args, **kwargs)
919 # Apply the provided function (in **kwargs)
920 # on the df using our wrapper (which provides bar updating)
921 try:
922 return getattr(df, df_function)(wrapper, **kwargs)
923 finally:
924 t.close()
926 return inner
928 # Monkeypatch pandas to provide easy methods
929 # Enable custom tqdm progress in pandas!
930 Series.progress_apply = inner_generator()
931 SeriesGroupBy.progress_apply = inner_generator()
932 Series.progress_map = inner_generator('map')
933 SeriesGroupBy.progress_map = inner_generator('map')
935 DataFrame.progress_apply = inner_generator()
936 DataFrameGroupBy.progress_apply = inner_generator()
937 DataFrame.progress_applymap = inner_generator('applymap')
938 DataFrame.progress_map = inner_generator('map')
939 DataFrameGroupBy.progress_map = inner_generator('map')
941 if Panel is not None:
942 Panel.progress_apply = inner_generator()
943 if PanelGroupBy is not None:
944 PanelGroupBy.progress_apply = inner_generator()
946 GroupBy.progress_apply = inner_generator()
947 GroupBy.progress_aggregate = inner_generator('aggregate')
948 GroupBy.progress_transform = inner_generator('transform')
950 if Rolling is not None and Expanding is not None:
951 Rolling.progress_apply = inner_generator()
952 Expanding.progress_apply = inner_generator()
953 elif _Rolling_and_Expanding is not None:
954 _Rolling_and_Expanding.progress_apply = inner_generator()
956 # override defaults via env vars
957 @envwrap("tqdm", is_method=True, types={'total': float, 'ncols': int, 'miniters': float,
958 'position': int, 'nrows': int})
959 def __init__(self, iterable=None, desc=None, total=None, leave=True, file=None,
960 ncols=None, mininterval=0.1, maxinterval=10.0, miniters=None,
961 ascii=None, # pylint: disable=redefined-builtin
962 disable=False, unit='it', unit_scale=False, dynamic_ncols=False, smoothing=0.3,
963 bar_format=None, initial=0, position=None, postfix=None, unit_divisor=1000,
964 write_bytes=False, lock_args=None, nrows=None, colour=None, delay=0.0, gui=False,
965 **kwargs):
966 """see tqdm.tqdm for arguments"""
967 if file is None:
968 file = sys.stderr
970 if write_bytes:
971 # Despite coercing unicode into bytes, py2 sys.std* streams
972 # should have bytes written to them.
973 file = SimpleTextIOWrapper(
974 file, encoding=getattr(file, 'encoding', None) or 'utf-8')
976 file = DisableOnWriteError(file, tqdm_instance=self)
978 if disable is None and hasattr(file, "isatty") and not file.isatty():
979 disable = True
981 if total is None and iterable is not None:
982 try:
983 total = len(iterable)
984 except (TypeError, AttributeError):
985 total = None
986 if total == float("inf"):
987 # Infinite iterations, behave same as unknown
988 total = None
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 self.disable:
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 self.last_print_t < self.start_t + self.delay:
1284 # haven't ever displayed; nothing to clear
1285 return
1287 # GUI mode
1288 if getattr(self, 'sp', None) is None:
1289 return
1291 # annoyingly, _supports_unicode isn't good enough
1292 def fp_write(s):
1293 self.fp.write(str(s))
1295 try:
1296 fp_write('')
1297 except ValueError as e:
1298 if 'closed' in str(e):
1299 return
1300 raise # pragma: no cover
1302 leave = pos == 0 if self.leave is None else self.leave
1304 with self._lock:
1305 if leave:
1306 # stats for overall rate (no weighted average)
1307 self._ema_dt = lambda: None
1308 self.display(pos=0)
1309 fp_write('\n')
1310 else:
1311 # clear previous display
1312 if self.display(msg='', pos=pos) and not pos:
1313 fp_write('\r')
1315 def clear(self, nolock=False):
1316 """Clear current bar display."""
1317 if self.disable:
1318 return
1320 if not nolock:
1321 self._lock.acquire()
1322 pos = abs(self.pos)
1323 if pos < (self.nrows or 20):
1324 self.moveto(pos)
1325 self.sp('')
1326 self.fp.write('\r') # place cursor back at the beginning of line
1327 self.moveto(-pos)
1328 if not nolock:
1329 self._lock.release()
1331 def refresh(self, nolock=False, lock_args=None):
1332 """
1333 Force refresh the display of this bar.
1335 Parameters
1336 ----------
1337 nolock : bool, optional
1338 If `True`, does not lock.
1339 If [default: `False`]: calls `acquire()` on internal lock.
1340 lock_args : tuple, optional
1341 Passed to internal lock's `acquire()`.
1342 If specified, will only `display()` if `acquire()` returns `True`.
1343 """
1344 if self.disable:
1345 return
1347 if not nolock:
1348 if lock_args:
1349 if not self._lock.acquire(*lock_args):
1350 return False
1351 else:
1352 self._lock.acquire()
1353 self.display()
1354 if not nolock:
1355 self._lock.release()
1356 return True
1358 def unpause(self):
1359 """Restart tqdm timer from last print time."""
1360 if self.disable:
1361 return
1362 cur_t = self._time()
1363 self.start_t += cur_t - self.last_print_t
1364 self.last_print_t = cur_t
1366 def reset(self, total=None):
1367 """
1368 Resets to 0 iterations for repeated use.
1370 Consider combining with `leave=True`.
1372 Parameters
1373 ----------
1374 total : int or float, optional. Total to use for the new bar.
1375 """
1376 self.n = 0
1377 if total is not None:
1378 self.total = total
1379 if self.disable:
1380 return
1381 self.last_print_n = 0
1382 self.last_print_t = self.start_t = self._time()
1383 self._ema_dn = EMA(self.smoothing)
1384 self._ema_dt = EMA(self.smoothing)
1385 self._ema_miniters = EMA(self.smoothing)
1386 self.refresh()
1388 def set_description(self, desc=None, refresh=True):
1389 """
1390 Set/modify description of the progress bar.
1392 Parameters
1393 ----------
1394 desc : str, optional
1395 refresh : bool, optional
1396 Forces refresh [default: True].
1397 """
1398 self.desc = desc + ': ' if desc else ''
1399 if refresh:
1400 self.refresh()
1402 def set_description_str(self, desc=None, refresh=True):
1403 """Set/modify description without ': ' appended."""
1404 self.desc = desc or ''
1405 if refresh:
1406 self.refresh()
1408 def set_postfix(self, ordered_dict=None, refresh=True, **kwargs):
1409 """
1410 Set/modify postfix (additional stats)
1411 with automatic formatting based on datatype.
1413 Parameters
1414 ----------
1415 ordered_dict : dict or OrderedDict, optional
1416 refresh : bool, optional
1417 Forces refresh [default: True].
1418 kwargs : dict, optional
1419 """
1420 # Sort in alphabetical order to be more deterministic
1421 postfix = OrderedDict([] if ordered_dict is None else ordered_dict)
1422 for key in sorted(kwargs.keys()):
1423 postfix[key] = kwargs[key]
1424 # Preprocess stats according to datatype
1425 for key in postfix.keys():
1426 # Number: limit the length of the string
1427 if isinstance(postfix[key], Number):
1428 postfix[key] = self.format_num(postfix[key])
1429 # Else for any other type, try to get the string conversion
1430 elif not isinstance(postfix[key], str):
1431 postfix[key] = str(postfix[key])
1432 # Else if it's a string, don't need to preprocess anything
1433 # Stitch together to get the final postfix
1434 self.postfix = ', '.join(key + '=' + postfix[key].strip()
1435 for key in postfix.keys())
1436 if refresh:
1437 self.refresh()
1439 def set_postfix_str(self, s='', refresh=True):
1440 """
1441 Postfix without dictionary expansion, similar to prefix handling.
1442 """
1443 self.postfix = str(s)
1444 if refresh:
1445 self.refresh()
1447 def moveto(self, n):
1448 # TODO: private method
1449 self.fp.write('\n' * n + _term_move_up() * -n)
1450 getattr(self.fp, 'flush', lambda: None)()
1452 @property
1453 def format_dict(self):
1454 """Public API for read-only member access."""
1455 if self.disable and not hasattr(self, 'unit'):
1456 return defaultdict(lambda: None, {
1457 'n': self.n, 'total': self.total, 'elapsed': 0, 'unit': 'it'})
1458 if self.dynamic_ncols:
1459 self.ncols, self.nrows = self.dynamic_ncols(self.fp)
1460 return {
1461 'n': self.n, 'total': self.total,
1462 'elapsed': self._time() - self.start_t if hasattr(self, 'start_t') else 0,
1463 'ncols': self.ncols, 'nrows': self.nrows, 'prefix': self.desc,
1464 'ascii': self.ascii, 'unit': self.unit, 'unit_scale': self.unit_scale,
1465 'rate': self._ema_dn() / self._ema_dt() if self._ema_dt() else None,
1466 'bar_format': self.bar_format, 'postfix': self.postfix,
1467 'unit_divisor': self.unit_divisor, 'initial': self.initial,
1468 'colour': self.colour}
1470 def display(self, msg=None, pos=None):
1471 """
1472 Use `self.sp` to display `msg` in the specified `pos`.
1474 Consider overloading this function when inheriting to use e.g.:
1475 `self.some_frontend(**self.format_dict)` instead of `self.sp`.
1477 Parameters
1478 ----------
1479 msg : str, optional. What to display (default: `repr(self)`).
1480 pos : int, optional. Position to `moveto`
1481 (default: `abs(self.pos)`).
1482 """
1483 if pos is None:
1484 pos = abs(self.pos)
1486 nrows = self.nrows or 20
1487 if pos >= nrows - 1:
1488 if pos >= nrows:
1489 return False
1490 if msg or msg is None: # override at `nrows - 1`
1491 msg = " ... (more hidden) ..."
1493 if not hasattr(self, "sp"):
1494 raise TqdmDeprecationWarning(
1495 "Please use `tqdm.gui.tqdm(...)`"
1496 " instead of `tqdm(..., gui=True)`\n",
1497 fp_write=getattr(self.fp, 'write', sys.stderr.write))
1499 if pos:
1500 self.moveto(pos)
1501 self.sp(self.__str__() if msg is None else msg)
1502 if pos:
1503 self.moveto(-pos)
1504 return True
1506 @classmethod
1507 @contextmanager
1508 def wrapattr(cls, stream, method, total=None, bytes=True, # pylint: disable=redefined-builtin
1509 **tqdm_kwargs):
1510 """
1511 stream : file-like object.
1512 method : str, "read" or "write". The result of `read()` and
1513 the first argument of `write()` should have a `len()`.
1515 >>> with tqdm.wrapattr(file_obj, "read", total=file_obj.size) as fobj:
1516 ... while True:
1517 ... chunk = fobj.read(chunk_size)
1518 ... if not chunk:
1519 ... break
1520 """
1521 with cls(total=total, **tqdm_kwargs) as t:
1522 if bytes:
1523 t.unit = "B"
1524 t.unit_scale = True
1525 t.unit_divisor = 1024
1526 yield CallbackIOWrapper(t.update, stream, method)
1529def trange(*args, **kwargs):
1530 """Shortcut for tqdm(range(*args), **kwargs)."""
1531 return tqdm(range(*args), **kwargs)