annotate CSP2/CSP2_env/env-d9b9114564458d9d-741b3de822f2aaca6c6caa4325c4afce/lib/python3.8/site-packages/tqdm/notebook.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 IPython/Jupyter Notebook 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.notebook import trange, tqdm
jpayne@68 7 >>> for i in trange(10):
jpayne@68 8 ... ...
jpayne@68 9 """
jpayne@68 10 # import compatibility functions and utilities
jpayne@68 11 import re
jpayne@68 12 import sys
jpayne@68 13 from html import escape
jpayne@68 14 from weakref import proxy
jpayne@68 15
jpayne@68 16 # to inherit from the tqdm class
jpayne@68 17 from .std import tqdm as std_tqdm
jpayne@68 18
jpayne@68 19 if True: # pragma: no cover
jpayne@68 20 # import IPython/Jupyter base widget and display utilities
jpayne@68 21 IPY = 0
jpayne@68 22 try: # IPython 4.x
jpayne@68 23 import ipywidgets
jpayne@68 24 IPY = 4
jpayne@68 25 except ImportError: # IPython 3.x / 2.x
jpayne@68 26 IPY = 32
jpayne@68 27 import warnings
jpayne@68 28 with warnings.catch_warnings():
jpayne@68 29 warnings.filterwarnings(
jpayne@68 30 'ignore', message=".*The `IPython.html` package has been deprecated.*")
jpayne@68 31 try:
jpayne@68 32 import IPython.html.widgets as ipywidgets # NOQA: F401
jpayne@68 33 except ImportError:
jpayne@68 34 pass
jpayne@68 35
jpayne@68 36 try: # IPython 4.x / 3.x
jpayne@68 37 if IPY == 32:
jpayne@68 38 from IPython.html.widgets import HTML
jpayne@68 39 from IPython.html.widgets import FloatProgress as IProgress
jpayne@68 40 from IPython.html.widgets import HBox
jpayne@68 41 IPY = 3
jpayne@68 42 else:
jpayne@68 43 from ipywidgets import HTML
jpayne@68 44 from ipywidgets import FloatProgress as IProgress
jpayne@68 45 from ipywidgets import HBox
jpayne@68 46 except ImportError:
jpayne@68 47 try: # IPython 2.x
jpayne@68 48 from IPython.html.widgets import HTML
jpayne@68 49 from IPython.html.widgets import ContainerWidget as HBox
jpayne@68 50 from IPython.html.widgets import FloatProgressWidget as IProgress
jpayne@68 51 IPY = 2
jpayne@68 52 except ImportError:
jpayne@68 53 IPY = 0
jpayne@68 54 IProgress = None
jpayne@68 55 HBox = object
jpayne@68 56
jpayne@68 57 try:
jpayne@68 58 from IPython.display import display # , clear_output
jpayne@68 59 except ImportError:
jpayne@68 60 pass
jpayne@68 61
jpayne@68 62 __author__ = {"github.com/": ["lrq3000", "casperdcl", "alexanderkuk"]}
jpayne@68 63 __all__ = ['tqdm_notebook', 'tnrange', 'tqdm', 'trange']
jpayne@68 64 WARN_NOIPYW = ("IProgress not found. Please update jupyter and ipywidgets."
jpayne@68 65 " See https://ipywidgets.readthedocs.io/en/stable"
jpayne@68 66 "/user_install.html")
jpayne@68 67
jpayne@68 68
jpayne@68 69 class TqdmHBox(HBox):
jpayne@68 70 """`ipywidgets.HBox` with a pretty representation"""
jpayne@68 71 def _json_(self, pretty=None):
jpayne@68 72 pbar = getattr(self, 'pbar', None)
jpayne@68 73 if pbar is None:
jpayne@68 74 return {}
jpayne@68 75 d = pbar.format_dict
jpayne@68 76 if pretty is not None:
jpayne@68 77 d["ascii"] = not pretty
jpayne@68 78 return d
jpayne@68 79
jpayne@68 80 def __repr__(self, pretty=False):
jpayne@68 81 pbar = getattr(self, 'pbar', None)
jpayne@68 82 if pbar is None:
jpayne@68 83 return super().__repr__()
jpayne@68 84 return pbar.format_meter(**self._json_(pretty))
jpayne@68 85
jpayne@68 86 def _repr_pretty_(self, pp, *_, **__):
jpayne@68 87 pp.text(self.__repr__(True))
jpayne@68 88
jpayne@68 89
jpayne@68 90 class tqdm_notebook(std_tqdm):
jpayne@68 91 """
jpayne@68 92 Experimental IPython/Jupyter Notebook widget using tqdm!
jpayne@68 93 """
jpayne@68 94 @staticmethod
jpayne@68 95 def status_printer(_, total=None, desc=None, ncols=None):
jpayne@68 96 """
jpayne@68 97 Manage the printing of an IPython/Jupyter Notebook progress bar widget.
jpayne@68 98 """
jpayne@68 99 # Fallback to text bar if there's no total
jpayne@68 100 # DEPRECATED: replaced with an 'info' style bar
jpayne@68 101 # if not total:
jpayne@68 102 # return super(tqdm_notebook, tqdm_notebook).status_printer(file)
jpayne@68 103
jpayne@68 104 # fp = file
jpayne@68 105
jpayne@68 106 # Prepare IPython progress bar
jpayne@68 107 if IProgress is None: # #187 #451 #558 #872
jpayne@68 108 raise ImportError(WARN_NOIPYW)
jpayne@68 109 if total:
jpayne@68 110 pbar = IProgress(min=0, max=total)
jpayne@68 111 else: # No total? Show info style bar with no progress tqdm status
jpayne@68 112 pbar = IProgress(min=0, max=1)
jpayne@68 113 pbar.value = 1
jpayne@68 114 pbar.bar_style = 'info'
jpayne@68 115 if ncols is None:
jpayne@68 116 pbar.layout.width = "20px"
jpayne@68 117
jpayne@68 118 ltext = HTML()
jpayne@68 119 rtext = HTML()
jpayne@68 120 if desc:
jpayne@68 121 ltext.value = desc
jpayne@68 122 container = TqdmHBox(children=[ltext, pbar, rtext])
jpayne@68 123 # Prepare layout
jpayne@68 124 if ncols is not None: # use default style of ipywidgets
jpayne@68 125 # ncols could be 100, "100px", "100%"
jpayne@68 126 ncols = str(ncols) # ipywidgets only accepts string
jpayne@68 127 try:
jpayne@68 128 if int(ncols) > 0: # isnumeric and positive
jpayne@68 129 ncols += 'px'
jpayne@68 130 except ValueError:
jpayne@68 131 pass
jpayne@68 132 pbar.layout.flex = '2'
jpayne@68 133 container.layout.width = ncols
jpayne@68 134 container.layout.display = 'inline-flex'
jpayne@68 135 container.layout.flex_flow = 'row wrap'
jpayne@68 136
jpayne@68 137 return container
jpayne@68 138
jpayne@68 139 def display(self, msg=None, pos=None,
jpayne@68 140 # additional signals
jpayne@68 141 close=False, bar_style=None, check_delay=True):
jpayne@68 142 # Note: contrary to native tqdm, msg='' does NOT clear bar
jpayne@68 143 # goal is to keep all infos if error happens so user knows
jpayne@68 144 # at which iteration the loop failed.
jpayne@68 145
jpayne@68 146 # Clear previous output (really necessary?)
jpayne@68 147 # clear_output(wait=1)
jpayne@68 148
jpayne@68 149 if not msg and not close:
jpayne@68 150 d = self.format_dict
jpayne@68 151 # remove {bar}
jpayne@68 152 d['bar_format'] = (d['bar_format'] or "{l_bar}<bar/>{r_bar}").replace(
jpayne@68 153 "{bar}", "<bar/>")
jpayne@68 154 msg = self.format_meter(**d)
jpayne@68 155
jpayne@68 156 ltext, pbar, rtext = self.container.children
jpayne@68 157 pbar.value = self.n
jpayne@68 158
jpayne@68 159 if msg:
jpayne@68 160 msg = msg.replace(' ', u'\u2007') # fix html space padding
jpayne@68 161 # html escape special characters (like '&')
jpayne@68 162 if '<bar/>' in msg:
jpayne@68 163 left, right = map(escape, re.split(r'\|?<bar/>\|?', msg, maxsplit=1))
jpayne@68 164 else:
jpayne@68 165 left, right = '', escape(msg)
jpayne@68 166
jpayne@68 167 # Update description
jpayne@68 168 ltext.value = left
jpayne@68 169 # never clear the bar (signal: msg='')
jpayne@68 170 if right:
jpayne@68 171 rtext.value = right
jpayne@68 172
jpayne@68 173 # Change bar style
jpayne@68 174 if bar_style:
jpayne@68 175 # Hack-ish way to avoid the danger bar_style being overridden by
jpayne@68 176 # success because the bar gets closed after the error...
jpayne@68 177 if pbar.bar_style != 'danger' or bar_style != 'success':
jpayne@68 178 pbar.bar_style = bar_style
jpayne@68 179
jpayne@68 180 # Special signal to close the bar
jpayne@68 181 if close and pbar.bar_style != 'danger': # hide only if no error
jpayne@68 182 try:
jpayne@68 183 self.container.close()
jpayne@68 184 except AttributeError:
jpayne@68 185 self.container.visible = False
jpayne@68 186 self.container.layout.visibility = 'hidden' # IPYW>=8
jpayne@68 187
jpayne@68 188 if check_delay and self.delay > 0 and not self.displayed:
jpayne@68 189 display(self.container)
jpayne@68 190 self.displayed = True
jpayne@68 191
jpayne@68 192 @property
jpayne@68 193 def colour(self):
jpayne@68 194 if hasattr(self, 'container'):
jpayne@68 195 return self.container.children[-2].style.bar_color
jpayne@68 196
jpayne@68 197 @colour.setter
jpayne@68 198 def colour(self, bar_color):
jpayne@68 199 if hasattr(self, 'container'):
jpayne@68 200 self.container.children[-2].style.bar_color = bar_color
jpayne@68 201
jpayne@68 202 def __init__(self, *args, **kwargs):
jpayne@68 203 """
jpayne@68 204 Supports the usual `tqdm.tqdm` parameters as well as those listed below.
jpayne@68 205
jpayne@68 206 Parameters
jpayne@68 207 ----------
jpayne@68 208 display : Whether to call `display(self.container)` immediately
jpayne@68 209 [default: True].
jpayne@68 210 """
jpayne@68 211 kwargs = kwargs.copy()
jpayne@68 212 # Setup default output
jpayne@68 213 file_kwarg = kwargs.get('file', sys.stderr)
jpayne@68 214 if file_kwarg is sys.stderr or file_kwarg is None:
jpayne@68 215 kwargs['file'] = sys.stdout # avoid the red block in IPython
jpayne@68 216
jpayne@68 217 # Initialize parent class + avoid printing by using gui=True
jpayne@68 218 kwargs['gui'] = True
jpayne@68 219 # convert disable = None to False
jpayne@68 220 kwargs['disable'] = bool(kwargs.get('disable', False))
jpayne@68 221 colour = kwargs.pop('colour', None)
jpayne@68 222 display_here = kwargs.pop('display', True)
jpayne@68 223 super().__init__(*args, **kwargs)
jpayne@68 224 if self.disable or not kwargs['gui']:
jpayne@68 225 self.disp = lambda *_, **__: None
jpayne@68 226 return
jpayne@68 227
jpayne@68 228 # Get bar width
jpayne@68 229 self.ncols = '100%' if self.dynamic_ncols else kwargs.get("ncols", None)
jpayne@68 230
jpayne@68 231 # Replace with IPython progress bar display (with correct total)
jpayne@68 232 unit_scale = 1 if self.unit_scale is True else self.unit_scale or 1
jpayne@68 233 total = self.total * unit_scale if self.total else self.total
jpayne@68 234 self.container = self.status_printer(self.fp, total, self.desc, self.ncols)
jpayne@68 235 self.container.pbar = proxy(self)
jpayne@68 236 self.displayed = False
jpayne@68 237 if display_here and self.delay <= 0:
jpayne@68 238 display(self.container)
jpayne@68 239 self.displayed = True
jpayne@68 240 self.disp = self.display
jpayne@68 241 self.colour = colour
jpayne@68 242
jpayne@68 243 # Print initial bar state
jpayne@68 244 if not self.disable:
jpayne@68 245 self.display(check_delay=False)
jpayne@68 246
jpayne@68 247 def __iter__(self):
jpayne@68 248 try:
jpayne@68 249 it = super().__iter__()
jpayne@68 250 for obj in it:
jpayne@68 251 # return super(tqdm...) will not catch exception
jpayne@68 252 yield obj
jpayne@68 253 # NB: except ... [ as ...] breaks IPython async KeyboardInterrupt
jpayne@68 254 except: # NOQA
jpayne@68 255 self.disp(bar_style='danger')
jpayne@68 256 raise
jpayne@68 257 # NB: don't `finally: close()`
jpayne@68 258 # since this could be a shared bar which the user will `reset()`
jpayne@68 259
jpayne@68 260 def update(self, n=1):
jpayne@68 261 try:
jpayne@68 262 return super().update(n=n)
jpayne@68 263 # NB: except ... [ as ...] breaks IPython async KeyboardInterrupt
jpayne@68 264 except: # NOQA
jpayne@68 265 # cannot catch KeyboardInterrupt when using manual tqdm
jpayne@68 266 # as the interrupt will most likely happen on another statement
jpayne@68 267 self.disp(bar_style='danger')
jpayne@68 268 raise
jpayne@68 269 # NB: don't `finally: close()`
jpayne@68 270 # since this could be a shared bar which the user will `reset()`
jpayne@68 271
jpayne@68 272 def close(self):
jpayne@68 273 if self.disable:
jpayne@68 274 return
jpayne@68 275 super().close()
jpayne@68 276 # Try to detect if there was an error or KeyboardInterrupt
jpayne@68 277 # in manual mode: if n < total, things probably got wrong
jpayne@68 278 if self.total and self.n < self.total:
jpayne@68 279 self.disp(bar_style='danger', check_delay=False)
jpayne@68 280 else:
jpayne@68 281 if self.leave:
jpayne@68 282 self.disp(bar_style='success', check_delay=False)
jpayne@68 283 else:
jpayne@68 284 self.disp(close=True, check_delay=False)
jpayne@68 285
jpayne@68 286 def clear(self, *_, **__):
jpayne@68 287 pass
jpayne@68 288
jpayne@68 289 def reset(self, total=None):
jpayne@68 290 """
jpayne@68 291 Resets to 0 iterations for repeated use.
jpayne@68 292
jpayne@68 293 Consider combining with `leave=True`.
jpayne@68 294
jpayne@68 295 Parameters
jpayne@68 296 ----------
jpayne@68 297 total : int or float, optional. Total to use for the new bar.
jpayne@68 298 """
jpayne@68 299 if self.disable:
jpayne@68 300 return super().reset(total=total)
jpayne@68 301 _, pbar, _ = self.container.children
jpayne@68 302 pbar.bar_style = ''
jpayne@68 303 if total is not None:
jpayne@68 304 pbar.max = total
jpayne@68 305 if not self.total and self.ncols is None: # no longer unknown total
jpayne@68 306 pbar.layout.width = None # reset width
jpayne@68 307 return super().reset(total=total)
jpayne@68 308
jpayne@68 309
jpayne@68 310 def tnrange(*args, **kwargs):
jpayne@68 311 """Shortcut for `tqdm.notebook.tqdm(range(*args), **kwargs)`."""
jpayne@68 312 return tqdm_notebook(range(*args), **kwargs)
jpayne@68 313
jpayne@68 314
jpayne@68 315 # Aliases
jpayne@68 316 tqdm = tqdm_notebook
jpayne@68 317 trange = tnrange