Constantly print Subprocess output while process is running

Heads up! You've already completed this tutorial.

Cody_Jackson | 2021-04-26 20:21:54 UTC | #1

I have to call a legacy Bash program and output the results to a Qt window. The problem is the subprocess the Bash command is executed in doesn't return each output line as they happen; the subprocess waits until the entire Bash command is finished, then it dumps everything to the window. Thus, if the Bash command takes a long time, the user may think the system is frozen.

I can get the subprocess to print each line via a print(output.readlin()) to a normal terminal. But I can't do it within Qt. I have tried a number of different examples and either they don't work or continue to dump the results at the end of the process.

I don't know if this a problem that an unknown Qt module might help me with or if it's just something with how Python deals w/ subprocess calls to Bash commands, like it's running a batch job and only returning results once the batch is done.

Here is the trouble code I'm working with:

python
self.console = OutputConsole()

out = subprocess.run(["bash", "-c", f"source  path_to_setup_file -r && cd parent_directory && build_project_command"], stderr=subprocess.STDOUT, stdout=subprocess.PIPE)

self.console.on_update_text(out.stdout.decode())


class OutputConsole(QWidget):
        """Collects output data (sys.stdout) from subprocess calls to ocpidev. Prints the output to the console view."""
        process: QTextEdit

    def __init__(self, process: QTextEdit) -> None:
        """Create the process that manages text editing on the console"""
        super().__init__()

        sys.stdout = Stream()
        self.process = process
        self.process.moveCursor(QTextCursor.Start)
        self.process.ensureCursorVisible()
        self.process.setLineWrapColumnOrWidth(1000)
        self.process.setLineWrapMode(QTextEdit.FixedPixelWidth)

    def on_update_text(self, text: str) -> None:
        """Add new text to the console as stdout gets more data"""
        cursor: QTextCursor = self.process.textCursor()
        cursor.movePosition(QTextCursor.End)
        cursor.insertText(text)
        self.process.setTextCursor(cursor)
        self.process.ensureCursorVisible()

    def __del__(self) -> None:
        """Reset sys.stdout to normal functionality"""
        sys.stdout = sys.__stdout__

mike2750 | 2021-04-29 22:55:02 UTC | #2

I would an approach like this where you can poll for the new line vs waiting for the entire subprocess to complete https://stackoverflow.com/questions/12523044/how-can-i-tail-a-log-file-in-python

The complete guide to packaging Python GUI applications with PyInstaller.
[[ discount.discount_pc ]]% OFF for the next [[ discount.duration ]] [[discount.description ]] with the code [[ discount.coupon_code ]]

Purchasing Power Parity

Developers in [[ country ]] get [[ discount.discount_pc ]]% OFF on all books & courses with code [[ discount.coupon_code ]]

i know your running a script and not tailing a log but the output results and intended results would be equivalent in what your looking to do.


Packaging Python Applications with PyInstaller by Martin Fitzpatrick — This step-by-step guide walks you through packaging your own Python applications from simple examples to complete installers and signed executables.

More info Get the book

Well done, you've finished this tutorial! Mark As Complete
[[ user.completed.length ]] completed [[ user.streak+1 ]] day streak

Constantly print Subprocess output while process is running was written by Martin Fitzpatrick .

Martin Fitzpatrick has been developing Python/Qt apps for 8 years. Building desktop applications to make data-analysis tools more user-friendly, Python was the obvious choice. Starting with Tk, later moving to wxWidgets and finally adopting PyQt.