summaryrefslogtreecommitdiffhomepage
path: root/libs/tqdm/notebook.py
diff options
context:
space:
mode:
Diffstat (limited to 'libs/tqdm/notebook.py')
-rw-r--r--libs/tqdm/notebook.py201
1 files changed, 123 insertions, 78 deletions
diff --git a/libs/tqdm/notebook.py b/libs/tqdm/notebook.py
index 570510370..1f488d25f 100644
--- a/libs/tqdm/notebook.py
+++ b/libs/tqdm/notebook.py
@@ -1,61 +1,62 @@
"""
IPython/Jupyter Notebook progressbar decorator for iterators.
-Includes a default (x)range iterator printing to stderr.
+Includes a default `range` iterator printing to `stderr`.
Usage:
- >>> from tqdm.notebook import trange[, tqdm]
- >>> for i in trange(10): #same as: for i in tqdm(xrange(10))
- ... ...
+>>> from tqdm.notebook import trange, tqdm
+>>> for i in trange(10):
+... ...
"""
# future division is important to divide integers and get as
# a result precise floating numbers (instead of truncated int)
-from __future__ import division, absolute_import
+from __future__ import absolute_import, division
+
# import compatibility functions and utilities
+import re
import sys
-from .utils import _range
+from weakref import proxy
+
# to inherit from the tqdm class
from .std import tqdm as std_tqdm
-
+from .utils import _range
if True: # pragma: no cover
# import IPython/Jupyter base widget and display utilities
IPY = 0
- IPYW = 0
try: # IPython 4.x
import ipywidgets
IPY = 4
- try:
- IPYW = int(ipywidgets.__version__.split('.')[0])
- except AttributeError: # __version__ may not exist in old versions
- pass
except ImportError: # IPython 3.x / 2.x
IPY = 32
import warnings
with warnings.catch_warnings():
warnings.filterwarnings(
- 'ignore',
- message=".*The `IPython.html` package has been deprecated.*")
+ 'ignore', message=".*The `IPython.html` package has been deprecated.*")
try:
- import IPython.html.widgets as ipywidgets
+ import IPython.html.widgets as ipywidgets # NOQA: F401
except ImportError:
pass
try: # IPython 4.x / 3.x
if IPY == 32:
+ from IPython.html.widgets import HTML
from IPython.html.widgets import FloatProgress as IProgress
- from IPython.html.widgets import HBox, HTML
+ from IPython.html.widgets import HBox
IPY = 3
else:
+ from ipywidgets import HTML
from ipywidgets import FloatProgress as IProgress
- from ipywidgets import HBox, HTML
+ from ipywidgets import HBox
except ImportError:
try: # IPython 2.x
- from IPython.html.widgets import FloatProgressWidget as IProgress
- from IPython.html.widgets import ContainerWidget as HBox
from IPython.html.widgets import HTML
+ from IPython.html.widgets import ContainerWidget as HBox
+ from IPython.html.widgets import FloatProgressWidget as IProgress
IPY = 2
except ImportError:
IPY = 0
+ IProgress = None
+ HBox = object
try:
from IPython.display import display # , clear_output
@@ -68,16 +69,35 @@ if True: # pragma: no cover
except ImportError: # Py2
from cgi import escape
-
__author__ = {"github.com/": ["lrq3000", "casperdcl", "alexanderkuk"]}
__all__ = ['tqdm_notebook', 'tnrange', 'tqdm', 'trange']
+class TqdmHBox(HBox):
+ """`ipywidgets.HBox` with a pretty representation"""
+ def _repr_json_(self, pretty=None):
+ pbar = getattr(self, 'pbar', None)
+ if pbar is None:
+ return {}
+ d = pbar.format_dict
+ if pretty is not None:
+ d["ascii"] = not pretty
+ return d
+
+ def __repr__(self, pretty=False):
+ pbar = getattr(self, 'pbar', None)
+ if pbar is None:
+ return super(TqdmHBox, self).__repr__()
+ return pbar.format_meter(**self._repr_json_(pretty))
+
+ def _repr_pretty_(self, pp, *_, **__):
+ pp.text(self.__repr__(True))
+
+
class tqdm_notebook(std_tqdm):
"""
Experimental IPython/Jupyter Notebook widget using tqdm!
"""
-
@staticmethod
def status_printer(_, total=None, desc=None, ncols=None):
"""
@@ -91,28 +111,25 @@ class tqdm_notebook(std_tqdm):
# fp = file
# Prepare IPython progress bar
- try:
- if total:
- pbar = IProgress(min=0, max=total)
- else: # No total? Show info style bar with no progress tqdm status
- pbar = IProgress(min=0, max=1)
- pbar.value = 1
- pbar.bar_style = 'info'
- except NameError:
- # #187 #451 #558
+ if IProgress is None: # #187 #451 #558 #872
raise ImportError(
- "FloatProgress not found. Please update jupyter and ipywidgets."
+ "IProgress not found. Please update jupyter and ipywidgets."
" See https://ipywidgets.readthedocs.io/en/stable"
"/user_install.html")
-
+ if total:
+ pbar = IProgress(min=0, max=total)
+ else: # No total? Show info style bar with no progress tqdm status
+ pbar = IProgress(min=0, max=1)
+ pbar.value = 1
+ pbar.bar_style = 'info'
+ if ncols is None:
+ pbar.layout.width = "20px"
+
+ ltext = HTML()
+ rtext = HTML()
if desc:
- pbar.description = desc
- if IPYW >= 7:
- pbar.style.description_width = 'initial'
- # Prepare status text
- ptext = HTML()
- # Only way to place text to the right of the bar is to use a container
- container = HBox(children=[pbar, ptext])
+ ltext.value = desc
+ container = TqdmHBox(children=[ltext, pbar, rtext])
# Prepare layout
if ncols is not None: # use default style of ipywidgets
# ncols could be 100, "100px", "100%"
@@ -126,13 +143,12 @@ class tqdm_notebook(std_tqdm):
container.layout.width = ncols
container.layout.display = 'inline-flex'
container.layout.flex_flow = 'row wrap'
- display(container)
return container
def display(self, msg=None, pos=None,
# additional signals
- close=False, bar_style=None):
+ close=False, bar_style=None, check_delay=True):
# Note: contrary to native tqdm, msg='' does NOT clear bar
# goal is to keep all infos if error happens so user knows
# at which iteration the loop failed.
@@ -141,38 +157,33 @@ class tqdm_notebook(std_tqdm):
# clear_output(wait=1)
if not msg and not close:
- msg = self.__repr__()
+ d = self.format_dict
+ # remove {bar}
+ d['bar_format'] = (d['bar_format'] or "{l_bar}<bar/>{r_bar}").replace(
+ "{bar}", "<bar/>")
+ msg = self.format_meter(**d)
- pbar, ptext = self.container.children
+ ltext, pbar, rtext = self.container.children
pbar.value = self.n
if msg:
# html escape special characters (like '&')
if '<bar/>' in msg:
- left, right = map(escape, msg.split('<bar/>', 1))
+ left, right = map(escape, re.split(r'\|?<bar/>\|?', msg, 1))
else:
left, right = '', escape(msg)
- # remove inesthetical pipes
- if left and left[-1] == '|':
- left = left[:-1]
- if right and right[0] == '|':
- right = right[1:]
-
# Update description
- pbar.description = left
- if IPYW >= 7:
- pbar.style.description_width = 'initial'
-
+ ltext.value = left
# never clear the bar (signal: msg='')
if right:
- ptext.value = right
+ rtext.value = right
# Change bar style
if bar_style:
# Hack-ish way to avoid the danger bar_style being overridden by
# success because the bar gets closed after the error...
- if not (pbar.bar_style == 'danger' and bar_style == 'success'):
+ if pbar.bar_style != 'danger' or bar_style != 'success':
pbar.bar_style = bar_style
# Special signal to close the bar
@@ -182,7 +193,30 @@ class tqdm_notebook(std_tqdm):
except AttributeError:
self.container.visible = False
+ if check_delay and self.delay > 0 and not self.displayed:
+ display(self.container)
+ self.displayed = True
+
+ @property
+ def colour(self):
+ if hasattr(self, 'container'):
+ return self.container.children[-2].style.bar_color
+
+ @colour.setter
+ def colour(self, bar_color):
+ if hasattr(self, 'container'):
+ self.container.children[-2].style.bar_color = bar_color
+
def __init__(self, *args, **kwargs):
+ """
+ Supports the usual `tqdm.tqdm` parameters as well as those listed below.
+
+ Parameters
+ ----------
+ display : Whether to call `display(self.container)` immediately
+ [default: True].
+ """
+ kwargs = kwargs.copy()
# Setup default output
file_kwarg = kwargs.get('file', sys.stderr)
if file_kwarg is sys.stderr or file_kwarg is None:
@@ -190,13 +224,13 @@ class tqdm_notebook(std_tqdm):
# Initialize parent class + avoid printing by using gui=True
kwargs['gui'] = True
- kwargs.setdefault('bar_format', '{l_bar}{bar}{r_bar}')
- kwargs['bar_format'] = kwargs['bar_format'].replace('{bar}', '<bar/>')
# convert disable = None to False
kwargs['disable'] = bool(kwargs.get('disable', False))
+ colour = kwargs.pop('colour', None)
+ display_here = kwargs.pop('display', True)
super(tqdm_notebook, self).__init__(*args, **kwargs)
if self.disable or not kwargs['gui']:
- self.sp = lambda *_, **__: None
+ self.disp = lambda *_, **__: None
return
# Get bar width
@@ -205,53 +239,59 @@ class tqdm_notebook(std_tqdm):
# Replace with IPython progress bar display (with correct total)
unit_scale = 1 if self.unit_scale is True else self.unit_scale or 1
total = self.total * unit_scale if self.total else self.total
- self.container = self.status_printer(
- self.fp, total, self.desc, self.ncols)
- self.sp = self.display
+ self.container = self.status_printer(self.fp, total, self.desc, self.ncols)
+ self.container.pbar = proxy(self)
+ self.displayed = False
+ if display_here and self.delay <= 0:
+ display(self.container)
+ self.displayed = True
+ self.disp = self.display
+ self.colour = colour
# Print initial bar state
if not self.disable:
- self.display()
+ self.display(check_delay=False)
- def __iter__(self, *args, **kwargs):
+ def __iter__(self):
try:
- for obj in super(tqdm_notebook, self).__iter__(*args, **kwargs):
+ for obj in super(tqdm_notebook, self).__iter__():
# return super(tqdm...) will not catch exception
yield obj
# NB: except ... [ as ...] breaks IPython async KeyboardInterrupt
except: # NOQA
- self.sp(bar_style='danger')
+ self.disp(bar_style='danger')
raise
# NB: don't `finally: close()`
# since this could be a shared bar which the user will `reset()`
- def update(self, *args, **kwargs):
+ def update(self, n=1):
try:
- super(tqdm_notebook, self).update(*args, **kwargs)
+ return super(tqdm_notebook, self).update(n=n)
# NB: except ... [ as ...] breaks IPython async KeyboardInterrupt
except: # NOQA
# cannot catch KeyboardInterrupt when using manual tqdm
# as the interrupt will most likely happen on another statement
- self.sp(bar_style='danger')
+ self.disp(bar_style='danger')
raise
# NB: don't `finally: close()`
# since this could be a shared bar which the user will `reset()`
- def close(self, *args, **kwargs):
- super(tqdm_notebook, self).close(*args, **kwargs)
+ def close(self):
+ if self.disable:
+ return
+ super(tqdm_notebook, self).close()
# Try to detect if there was an error or KeyboardInterrupt
# in manual mode: if n < total, things probably got wrong
if self.total and self.n < self.total:
- self.sp(bar_style='danger')
+ self.disp(bar_style='danger', check_delay=False)
else:
if self.leave:
- self.sp(bar_style='success')
+ self.disp(bar_style='success', check_delay=False)
else:
- self.sp(close=True)
+ self.disp(close=True, check_delay=False)
- def moveto(self, *args, **kwargs):
- # void -> avoid extraneous `\n` in IPython output cell
- return
+ def clear(self, *_, **__):
+ pass
def reset(self, total=None):
"""
@@ -263,9 +303,14 @@ class tqdm_notebook(std_tqdm):
----------
total : int or float, optional. Total to use for the new bar.
"""
+ if self.disable:
+ return super(tqdm_notebook, self).reset(total=total)
+ _, pbar, _ = self.container.children
+ pbar.bar_style = ''
if total is not None:
- pbar, _ = self.container.children
pbar.max = total
+ if not self.total and self.ncols is None: # no longer unknown total
+ pbar.layout.width = None # reset width
return super(tqdm_notebook, self).reset(total=total)