Gianni Spear
Gianni Spear

Reputation: 8010

fixing a Python progress bar in Command Prompt

i have wrote the following code (reviewed in code review) in order to print a progress bar in python 2.7 (PS: I know there is a progressbar module in Python)

from __future__ import division
import sys

class Progress(object):
    def __init__(self, maxval):
        self._pct = 0
        self.maxval = maxval

    def update(self, value):
        pct = int((value / self.maxval) * 100.0)
        if self._pct != pct:
            self._pct = pct
            self.display()

    def start(self):
        self.update(0)

    def finish(self):
        self.update(self.maxval)

    def display(self):
        sys.stdout.write("|%-100s| %d%%" % ('#' *self._pct, self._pct) + '\n')
        sys.stdout.flush()

# test
import time

toolbar_width = 300
pbar = Progress(toolbar_width)
pbar.start()
for i in xrange(toolbar_width):
    time.sleep(0.1) # do real work here
    pbar.update(i)
pbar.finish()

i wish to use this progress bar in my IDE (ex: Pyscripet, PyCharm , etc) and with Command Prompt. When i run with command prompt i have the following two problem that i cannot understand how i can fix.

enter image description here

  1. first, the progress bar prints out the limit (i used 100s)
  2. second, the progressbar print all bar one after the other. I wish to have only one bar that increase during the loop

Upvotes: 0

Views: 4147

Answers (3)

chmullig
chmullig

Reputation: 13436

1. It may be wrapping due to line length, that terminal looks narrower than 100 characters wide. If you want to assume 80 characters (what most consoles default to), I think you've got 7 characters of other stuff, so use a width of 73 characters for the progress bar.

    sys.stdout.write("|%-73s| %3d%%" % ('#' * int(self._pct*.73), self._pct) + '\n')

2. To stay on the same line, use sys.stdout.write and don't include a newline at the end. Then add a \r to the beginning of each line to return to the beginning.

        sys.stdout.write("\r|%-73s| %3d%%" % ('#' * int(self._pct*.73), self._pct))

You can also use %3d%% to pad the percentage, so it stays right aligned consistently.

Upvotes: 1

Colin O'Coal
Colin O'Coal

Reputation: 1427

Problem 2: If you want to display an increasing progression console bar in one line, you have to reset the cursor position, what can be done by writing an carriage return sign into the stdout.

import sys, time

for x in range(10):
    sys.stdout.write((x+1) * '#')
    time.sleep(1)
    sys.stdout.write("\r") # !!! carriage return sign under Windows !!!

print("Fine")

But I'm sorry to say: mostly that won't work in IDE stdout encapsulated environments

Eclipse, PyCharm, etc. are reading out the stdout pipe and printing changes raw into the console views.

Upvotes: 1

Adrien Plisson
Adrien Plisson

Reputation: 23313

problem 1:

your terminal window is less than 100 characters in width, that's why your progress bar seems to print out of the limit, whereas it is simply wrapping the output at 80 characters (which is the standard and console width on windows).

to avoid wrapping, try:

sys.stdout.write("|%-50s| %d%%" % ('#' *int(self._pct/2), self._pct) + '\n')

Upvotes: 2

Related Questions