Updating Whiptail gauge (Progress bar) with Python

I spent last week writing a Python script to create an installer for some services, and I wanted to show the installation progress using a gauge. So I used the whiptail utility which comes with most linux distros as it was easier to use for this particular task. However, there was one caveat, that it reads the progress value from the standard input. It was a bit tricky and took me bit of a time to figure it out...but this is how to do it.

It's mentioned in the manual.

--gauge text height width percent
              A gauge box displays a meter along the bottom of the box.  The meter indicates a percentage.  New percentages are read from standard input, one
              integer  per  line.  The meter is updated to reflect each new percentage.  If stdin is XXX, the first following line is a percentage and subse‐
              quent lines up to another XXX are used for a new prompt.  The gauge exits when EOF is reached on stdin.

Whiptail is a bash utility so we have to call the bash command within our python script. I used subprocess module to do that. Since we have to input the progress values to the command using the standard input, we have to set it's stdin to subprocess.PIPE. Whiptail will print to the stdout, so we don't really have anything to do there (means, it will read from the stdin and display the progress accordingly.)

#!/usr/bin/env python

import subprocess
import time

process = subprocess.Popen(["whiptail", "--title", "Progress", "--gauge", "", "6", "50", "0"], stdin=subprocess.PIPE)

for i in range(0,101, 10):
    time.sleep(1)
    process.stdin.write(b'{}\n'.format(i))
    process.stdin.flush()


So this is it. If you run this script, you will see the progress bar updates and reflects the new progress nicely.


Updating Whiptail gauge (Progress bar) with Python


One thing to note here is that you may have seen in many places that they don't recommend to use stdin.write directly due to deadlocks etc, and ask to use communicate(input="") method. But it's not definitely going to work here as the communicate(input="") method is going to write to the stdin and waits for the process to exit. That way we won't be able to keep updating the progress bar. That was from my understanding, but I might be wrong. If you know any better way to do this, or to use communicate(input="") instead of stdin.write(), feel free to leave a comment and let me know.