verigak / progress

Easy to use progress bars for Python
ISC License
1.41k stars 179 forks source link

Wrapping bug in connection with terminal size #40

Open thorstenkampe opened 7 years ago

thorstenkampe commented 7 years ago

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
shannonfenn commented 7 years ago

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:

thomasjm commented 5 years ago

@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 https://github.com/pypa/pip/issues/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?

arigit commented 5 months ago

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