diff --git a/tqdm/notebook.py b/tqdm/notebook.py index 0f531ab94..8e81d886d 100644 --- a/tqdm/notebook.py +++ b/tqdm/notebook.py @@ -37,25 +37,28 @@ if IPY == 32: from IPython.html.widgets import HTML from IPython.html.widgets import FloatProgress as IProgress - from IPython.html.widgets import HBox + from IPython.html.widgets import HBox, VBox IPY = 3 else: from ipywidgets import HTML from ipywidgets import FloatProgress as IProgress - from ipywidgets import HBox + from ipywidgets import HBox, VBox except ImportError: try: # IPython 2.x from IPython.html.widgets import HTML from IPython.html.widgets import ContainerWidget as HBox + from IPython.html.widgets import ContainerWidget as VBox from IPython.html.widgets import FloatProgressWidget as IProgress IPY = 2 except ImportError: IPY = 0 IProgress = None HBox = object + VBox = object try: - from IPython.display import display # , clear_output + from IPython.display import clear_output, display + clear_output(wait=False) # Necessary when rerunning cells except ImportError: pass @@ -143,9 +146,6 @@ def display(self, msg=None, pos=None, # goal is to keep all infos if error happens so user knows # at which iteration the loop failed. - # Clear previous output (really necessary?) - # clear_output(wait=1) - if not msg and not close: d = self.format_dict # remove {bar} @@ -178,14 +178,21 @@ def display(self, msg=None, pos=None, # Special signal to close the bar if close and pbar.bar_style != 'danger': # hide only if no error + # Remove self.container from the list of children of outer_container + tqdm_notebook.outer_container.children = tuple( + c for c in tqdm_notebook.outer_container.children if c is not self.container) try: self.container.close() + if abs(self.pos) == 0: + tqdm_notebook.outer_container.close() except AttributeError: self.container.visible = False self.container.layout.visibility = 'hidden' # IPYW>=8 if check_delay and self.delay > 0 and not self.displayed: - display(self.container) + tqdm_notebook.outer_container.children += (self.container,) + if abs(self.pos) == 0: + display(tqdm_notebook.outer_container) self.displayed = True @property @@ -198,6 +205,15 @@ def colour(self, bar_color): if hasattr(self, 'container'): self.container.children[-2].style.bar_color = bar_color + @classmethod + def get_first_inst(cls, instance): + for inst in cls._instances: + if inst.pos == 0: + return inst + # return min(cls._instances, key=lambda x: getattr(x, 'pos', float('inf'))) + + outer_container = None + def __init__(self, *args, **kwargs): """ Supports the usual `tqdm.tqdm` parameters as well as those listed below. @@ -230,11 +246,18 @@ def __init__(self, *args, **kwargs): # 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 + + if abs(self.pos) == 0: + tqdm_notebook.outer_container = VBox() + 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) + tqdm_notebook.outer_container.children += (self.container,) + if abs(self.pos) == 0: + display(tqdm_notebook.outer_container) self.displayed = True self.disp = self.display self.colour = colour @@ -274,10 +297,12 @@ def close(self): 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 + pos = abs(self.pos) + leave = pos == 0 if self.leave is None else self.leave if self.total and self.n < self.total: self.disp(bar_style='danger', check_delay=False) else: - if self.leave: + if leave: self.disp(bar_style='success', check_delay=False) else: self.disp(close=True, check_delay=False)