annotate CSP2/CSP2_env/env-d9b9114564458d9d-741b3de822f2aaca6c6caa4325c4afce/lib/python3.8/site-packages/tqdm/std.py @ 68:5028fdace37b

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