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:
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
Create GUI Applications with Python & Qt5 by Martin Fitzpatrick — (PyQt5 Edition) The hands-on guide to making apps with Python — Over 10,000 copies sold!
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.
PyQt6 Crash Course — a new tutorial in your Inbox every day
Beginner-focused crash course explaining the basics with hands-on examples.