Skip to content

Commit

Permalink
Reposition bars below a closed bar
Browse files Browse the repository at this point in the history
When a bar is closed it is moved to pos 0, which means all the other
bars below it must now be given a new position number to have their
output still go to the same screen line.
  • Loading branch information
mjpieters committed Aug 24, 2023
1 parent 4c956c2 commit 5fa739e
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 31 deletions.
6 changes: 3 additions & 3 deletions tests/tests_tqdm.py
Expand Up @@ -1285,10 +1285,11 @@ def test_position():
'\n\r2.pos1 bar: 0%',
'\n\n\r3.pos2 bar: 0%',
'\r2.pos1 bar: 0%',
'\n\n\r3.pos2 bar: 0%',
'\n\n\r4.pos2 bar: 0%',
'\r1.pos0 bar: 10%',
'\n\n\r3.pos2 bar: 10%',
'\n\r4.pos2 bar: 10%']
'\n\r3.pos2 bar: 10%',
'\n\n\r4.pos2 bar: 10%']
pos_line_diff(res, exres)
t4.close()
t3.close()
Expand Down Expand Up @@ -1895,7 +1896,6 @@ def test_screen_shape():
assert "one" in res
assert "two" in res
assert "three" in res
assert "\n\n" not in res
assert "more hidden" in res
# double-check ncols
assert all(len(i) == 50 for i in get_bar(res)
Expand Down
72 changes: 44 additions & 28 deletions tqdm/std.py
Expand Up @@ -715,6 +715,18 @@ def _decr_instances(cls, instance):
inst = min(instances, key=lambda i: i.pos)
inst.clear(nolock=True)
inst.pos = abs(instance.pos)
else:
# renumber remaining bars with positions below this bar so
# they maintain their positions
apos = abs(instance.pos)
readjust = [
(inst.pos, inst)
for inst in cls._instances
if abs(getattr(inst, "pos", apos)) > apos
]
for pos, inst in sorted(readjust, key=lambda pi: -abs(pi[0])):
inst.pos += 1 if pos < 0 else -1
inst.refresh(nolock=True)

@classmethod
def write(cls, s, file=None, end="\n", nolock=False):
Expand Down Expand Up @@ -1271,41 +1283,45 @@ def close(self):
# Prevent multiple closures
self.disable = True

# decrement instance pos and remove from internal set
# decrement instance pos
pos = abs(self.pos)
self._decr_instances(self)

if self.last_print_t < self.start_t + self.delay:
# haven't ever displayed; nothing to clear
return
try:
if self.last_print_t < self.start_t + self.delay:
# haven't ever displayed; nothing to clear
return

# GUI mode
if getattr(self, 'sp', None) is None:
return
# GUI mode
if getattr(self, 'sp', None) is None:
return

# annoyingly, _supports_unicode isn't good enough
def fp_write(s):
self.fp.write(str(s))
# annoyingly, _supports_unicode isn't good enough
def fp_write(s):
self.fp.write(str(s))

try:
fp_write('')
except ValueError as e:
if 'closed' in str(e):
return
raise # pragma: no cover
try:
fp_write('')
except ValueError as e:
if 'closed' in str(e):
return
raise # pragma: no cover

leave = pos == 0 if self.leave is None else self.leave
leave = pos == 0 if self.leave is None else self.leave

with self._lock:
if leave:
# stats for overall rate (no weighted average)
self._ema_dt = lambda: None
self.display(pos=0)
fp_write('\n')
else:
# clear previous display
if self.display(msg='', pos=pos) and not pos:
fp_write('\r')
with self._lock:
if leave:
# stats for overall rate (no weighted average)
self._ema_dt = lambda: None
self.display(pos=0)
fp_write('\n')
else:
# clear previous display
if self.display(msg='', pos=pos) and not pos:
fp_write('\r')

finally:
# Remove from internal set
self._decr_instances(self)

def clear(self, nolock=False):
"""Clear current bar display."""
Expand Down

0 comments on commit 5fa739e

Please sign in to comment.