Contact
CoCalc Logo Icon
StoreFeaturesDocsShareSupport News AboutSign UpSign In
| Download
Views: 658
1
"""
2
IPython/Jupyter Notebook progressbar decorator for iterators.
3
Includes a default (x)range iterator printing to stderr.
4
5
Usage:
6
>>> from tqdm_notebook import tnrange[, tqdm_notebook]
7
>>> for i in tnrange(10): #same as: for i in tqdm_notebook(xrange(10))
8
... ...
9
"""
10
# future division is important to divide integers and get as
11
# a result precise floating numbers (instead of truncated int)
12
from __future__ import division, absolute_import
13
# import compatibility functions and utilities
14
import sys
15
from ._utils import _range
16
# to inherit from the tqdm class
17
from ._tqdm import tqdm
18
19
20
if True: # pragma: no cover
21
# import IPython/Jupyter base widget and display utilities
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
ipy_deprecation_msg = "The `IPython.html` package" \
30
" has been deprecated"
31
warnings.filterwarnings('error',
32
message=".*" + ipy_deprecation_msg + ".*")
33
try:
34
import IPython.html.widgets as ipywidgets
35
except Warning as e:
36
if ipy_deprecation_msg not in str(e):
37
raise
38
warnings.simplefilter('ignore')
39
try:
40
import IPython.html.widgets as ipywidgets # NOQA
41
except ImportError:
42
pass
43
except ImportError:
44
pass
45
46
try: # IPython 4.x / 3.x
47
if IPY == 32:
48
from IPython.html.widgets import IntProgress, HBox, HTML
49
IPY = 3
50
else:
51
from ipywidgets import IntProgress, HBox, HTML
52
except ImportError:
53
try: # IPython 2.x
54
from IPython.html.widgets import IntProgressWidget as IntProgress
55
from IPython.html.widgets import ContainerWidget as HBox
56
from IPython.html.widgets import HTML
57
IPY = 2
58
except ImportError:
59
IPY = 0
60
61
try:
62
from IPython.display import display # , clear_output
63
except ImportError:
64
pass
65
66
# HTML encoding
67
try: # Py3
68
from html import escape
69
except ImportError: # Py2
70
from cgi import escape
71
72
73
__author__ = {"github.com/": ["lrq3000", "casperdcl", "alexanderkuk"]}
74
__all__ = ['tqdm_notebook', 'tnrange']
75
76
77
class tqdm_notebook(tqdm):
78
"""
79
Experimental IPython/Jupyter Notebook widget using tqdm!
80
"""
81
82
@staticmethod
83
def status_printer(_, total=None, desc=None):
84
"""
85
Manage the printing of an IPython/Jupyter Notebook progress bar widget.
86
"""
87
# Fallback to text bar if there's no total
88
# DEPRECATED: replaced with an 'info' style bar
89
# if not total:
90
# return super(tqdm_notebook, tqdm_notebook).status_printer(file)
91
92
# fp = file
93
94
# Prepare IPython progress bar
95
if total:
96
pbar = IntProgress(min=0, max=total)
97
else: # No total? Show info style bar with no progress tqdm status
98
pbar = IntProgress(min=0, max=1)
99
pbar.value = 1
100
pbar.bar_style = 'info'
101
if desc:
102
pbar.description = desc
103
# Prepare status text
104
ptext = HTML()
105
# Only way to place text to the right of the bar is to use a container
106
container = HBox(children=[pbar, ptext])
107
display(container)
108
109
def print_status(s='', close=False, bar_style=None):
110
# Note: contrary to native tqdm, s='' does NOT clear bar
111
# goal is to keep all infos if error happens so user knows
112
# at which iteration the loop failed.
113
114
# Clear previous output (really necessary?)
115
# clear_output(wait=1)
116
117
# Get current iteration value from format_meter string
118
if total:
119
n = None
120
if s:
121
npos = s.find(r'/|/') # cause we use bar_format=r'{n}|...'
122
# Check that n can be found in s (else n > total)
123
if npos >= 0:
124
n = int(s[:npos]) # get n from string
125
s = s[npos + 3:] # remove from string
126
127
# Update bar with current n value
128
if n is not None:
129
pbar.value = n
130
131
# Print stats
132
if s: # never clear the bar (signal: s='')
133
s = s.replace('||', '') # remove inesthetical pipes
134
s = escape(s) # html escape special characters (like '?')
135
ptext.value = s
136
137
# Change bar style
138
if bar_style:
139
# Hack-ish way to avoid the danger bar_style being overriden by
140
# success because the bar gets closed after the error...
141
if not (pbar.bar_style == 'danger' and bar_style == 'success'):
142
pbar.bar_style = bar_style
143
144
# Special signal to close the bar
145
if close and pbar.bar_style != 'danger': # hide only if no error
146
container.visible = False
147
148
return print_status
149
150
@classmethod
151
def write(cls, s, file=sys.stdout, end="\n"):
152
"""
153
Print a message via tqdm_notebook (just an alias for print)
154
"""
155
# Just an alias for print because overlap is impossible with ipywidgets
156
file.write(s)
157
file.write(end)
158
159
def __init__(self, *args, **kwargs):
160
# Setup default output
161
if kwargs.get('file', sys.stderr) is sys.stderr:
162
kwargs['file'] = sys.stdout # avoid the red block in IPython
163
164
# Remove the bar from the printed string, only print stats
165
if not kwargs.get('bar_format', None):
166
kwargs['bar_format'] = r'{n}/|/{l_bar}{r_bar}'
167
168
# Initialize parent class + avoid printing by using gui=True
169
kwargs['gui'] = True
170
super(tqdm_notebook, self).__init__(*args, **kwargs)
171
if self.disable or not kwargs['gui']:
172
return
173
174
# Delete first pbar generated from super() (wrong total and text)
175
# DEPRECATED by using gui=True
176
# self.sp('', close=True)
177
# Replace with IPython progress bar display (with correct total)
178
self.sp = self.status_printer(self.fp, self.total, self.desc)
179
self.desc = None # trick to place description before the bar
180
181
# Print initial bar state
182
if not self.disable:
183
self.sp(self.__repr__()) # same as self.refresh without clearing
184
185
def __iter__(self, *args, **kwargs):
186
try:
187
for obj in super(tqdm_notebook, self).__iter__(*args, **kwargs):
188
# return super(tqdm...) will not catch exception
189
yield obj
190
# NB: except ... [ as ...] breaks IPython async KeyboardInterrupt
191
except:
192
self.sp(bar_style='danger')
193
raise
194
195
def update(self, *args, **kwargs):
196
try:
197
super(tqdm_notebook, self).update(*args, **kwargs)
198
except Exception as exc:
199
# cannot catch KeyboardInterrupt when using manual tqdm
200
# as the interrupt will most likely happen on another statement
201
self.sp(bar_style='danger')
202
raise exc
203
204
def close(self, *args, **kwargs):
205
super(tqdm_notebook, self).close(*args, **kwargs)
206
# Try to detect if there was an error or KeyboardInterrupt
207
# in manual mode: if n < total, things probably got wrong
208
if self.total and self.n < self.total:
209
self.sp(bar_style='danger')
210
else:
211
if self.leave:
212
self.sp(bar_style='success')
213
else:
214
self.sp(close=True)
215
216
def moveto(*args, **kwargs):
217
# void -> avoid extraneous `\n` in IPython output cell
218
return
219
220
221
def tnrange(*args, **kwargs):
222
"""
223
A shortcut for tqdm_notebook(xrange(*args), **kwargs).
224
On Python3+ range is used instead of xrange.
225
"""
226
return tqdm_notebook(_range(*args), **kwargs)
227
228