0

i have a python3 module which print a progress bar provided by rich module (./module/script.py)

import sys

from rich.console import Console
from rich.progress import Progress
import time



if __name__ == "__main__":
    for i in range(3):
        print(f"task1 progress {i}   \r", end='', flush=True)
        time.sleep(1)
    print(f"task1 finished {i}     ", flush=True)

    with Progress() as progress:
        task = progress.add_task(f"[red]Progressing ...", total=100)
        
        while not progress.finished:
            progress.update(task, advance=0.5)
            time.sleep(0.02)

If I run the module (python3 -m module.script), everything works fine and progressbar is displayed on the terminal

My problem is that my main program must run the module with subprocess.Popen so, i track the stdout of the process and i want to display it (like a tail bash command)

here is a simplified code of the main program

import sys
import os
import shlex
import subprocess

if __name__ == "__main__":

        launcher_module_name = 'module.script'
        cmdline = f'{sys.executable} -m {launcher_module_name}'
        args_cmdline = shlex.split(cmdline)
        cwd = os.getcwd()
        # run it ##
        my_process = subprocess.Popen(args=args_cmdline, cwd=cwd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)

        line = bytearray()
        while True:
            out = my_process.stdout.read(1)
            if out == b'' and my_process.poll() != None:
                break
            if out != b'':
                if out == b'\r':
                    print(str(line, 'utf-8'), end='\r', flush=True)
                    line.clear()
                elif out == b'\n':
                    print(str(line, 'utf-8'), end='\n', flush=True)
                    line.clear()
                else:
                    line += out

The result is that no progress bar is live displayed, only the last info rendered by progress bar is displayed. So how can i have a live display for progress bar executed by a subprocess.Popen ?

Thanks for your answers.

  • Tangentially, the code you put inside `if __name__ == "__main__":` should be absolutely trivial. The condition is only useful when you `import` this code; if all the useful functionality is excluded when you `import`, you will never want to do that anyway. See also https://stackoverflow.com/a/69778466/874188 – tripleee Jul 22 '22 at 06:50
  • In all cases, the executed command is python3 -m module.script, so the provided code seems to be good. – Nicolas Vaye Jul 24 '22 at 22:15
  • No, if the condition is never useful, don't put it in. The linked answer contains a more detailed exposition and rationale. – tripleee Jul 25 '22 at 04:29

1 Answers1

0

Came across the same issue and submitted a bug report. Turns out it's intentional: https://github.com/Textualize/rich/issues/2326

However there are two workarounds. One is to use a pseudo-terminal (pty), and the other is to add force_terminal=True to the progressbar options.

Hope this helps.

joeyb123
  • 33
  • 5
  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Jun 06 '22 at 13:58