verigak/progress

Wrapping bug in connection with terminal size

Opened this issue · 3 comments

Hi,

the following code triggers a wrapping bug in connection with the terminal size:

import time, progress.bar

bar = progress.bar.Bar(
          suffix = '%(index)d of %(max)d (%(percent)d%%)  '
                   'eta: %(eta_td)s  time elapsed: %(elapsed_td)s',
      max = 100)

for index in range(100):
    bar.next()
    time.sleep(0.1)

bar.finish()

This is the output on a 87x40 terminal (the bug "starts" at value 10):

 |###                             | 10 of 100 (10%)  eta: 0:00:09  time elapsed: 0:00:0
 |###                             | 11 of 100 (11%)  eta: 0:00:09  time elapsed: 0:00:0
 |###                             | 12 of 100 (12%)  eta: 0:00:09  time elapsed: 0:00:0
 |####                            | 13 of 100 (13%)  eta: 0:00:09  time elapsed: 0:00:0
 |####                            | 14 of 100 (14%)  eta: 0:00:09  time elapsed: 0:00:0
 |####                            | 15 of 100 (15%)  eta: 0:00:09  time elapsed: 0:00:0
 |#####                           | 16 of 100 (16%)  eta: 0:00:09  time elapsed: 0:00:0
 |#####                           | 17 of 100 (17%)  eta: 0:00:09  time elapsed: 0:00:0
 |#####                           | 18 of 100 (18%)  eta: 0:00:09  time elapsed: 0:00:0
 |######                          | 19 of 100 (19%)  eta: 0:00:09  time elapsed: 0:00:0
 |######                          | 20 of 100 (20%)  eta: 0:00:09  time elapsed: 0:00:0
 |######                          | 21 of 100 (21%)  eta: 0:00:08  time elapsed: 0:00:0
 |#######                         | 22 of 100 (22%)  eta: 0:00:08  time elapsed: 0:00:0
 |#######                         | 23 of 100 (23%)  eta: 0:00:08  time elapsed: 0:00:0
 |#######                         | 24 of 100 (24%)  eta: 0:00:08  time elapsed: 0:00:0
 |########                        | 25 of 100 (25%)  eta: 0:00:08  time elapsed: 0:00:0
 |########                        | 26 of 100 (26%)  eta: 0:00:08  time elapsed: 0:00:0
 |########                        | 27 of 100 (27%)  eta: 0:00:08  time elapsed: 0:00:0
 |########                        | 28 of 100 (28%)  eta: 0:00:08  time elapsed: 0:00:0
 |#########                       | 29 of 100 (28%)  eta: 0:00:08  time elapsed: 0:00:0
 |#########                       | 30 of 100 (30%)  eta: 0:00:08  time elapsed: 0:00:0
 |#########                       | 31 of 100 (31%)  eta: 0:00:07  time elapsed: 0:00:0
3
[...]

This is the output on a maximized terminal:

 |################################| 100 of 100 (100%)  eta: 0:00:00  time elapsed: 0:00:09

So the root cause is how carriage return behaves after the terminal autowraps.

The simple solution I went with was to overload writeln() to wrap the printed line in escapes to disable and then re-enable autowrap:

    print('\x1b[?7l' + line + '\x1b[?7h', end='', file=self.file)

This however had the undesirable side-effect of truncating the line in a non-obvious way (fine as an individual fix, but not for default behaviour).

Options that I'd imagine would be nicer:

  • An 'auto' or max width option which would query terminal width when constructing the line in update() methods and use something like terminal_width - len(''.join([message, self.bar_prefix, self.bar_suffix, suffix])) to set the bar width for that update. This would resulting in fluctuating bar widths though due to changing suffices etc (which is why the original issue only started at the tenth iteration).
  • Changing the line clearing operations to instead save and restore the cursor position although:
    • I'm not sure the impact this would have on the clearing of intermediate lines, and
    • I have no idea how widely supported the save/restore escape sequences are.

@shannonfenn truncating the line sounds better as a default behavior then the terminal going crazy and emitting lots of progress bar lines.

I was investigating the effect this bug has on pip and found it is probably the root cause of issues like pypa/pip#6101. Along with affecting anyone who tries to use pip install on a small terminal :)

Is there some way I can help push this towards a fix?

facing the same issue in Termux (android / smartphone terminal), noticed that depending on the terminal size the "newline" bug appears.