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