Skip to content

Commit

Permalink
Render nested progress bars in the same container in IPython. Fixes r…
Browse files Browse the repository at this point in the history
…endering issues in VSCode. See issue: microsoft/vscode-jupyter#9397.

Also fixes leave=None in IPython. As per the documentation, setting leave=None should leave iff position=0, but currently it is just equivalent to leave=False.
  • Loading branch information
UFO-101 committed Aug 28, 2023
1 parent 4c956c2 commit b2a3c59
Showing 1 changed file with 34 additions and 9 deletions.
43 changes: 34 additions & 9 deletions tqdm/notebook.py
Expand Up @@ -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

Expand Down Expand Up @@ -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}
Expand Down Expand Up @@ -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
Expand All @@ -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.
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand Down

0 comments on commit b2a3c59

Please sign in to comment.