Jakub Sowa
Jakub Sowa

Reputation: 103

Cannot redirect Pyinstaller single executable output while running it in subprocess

I've been struggling with this for quite a while. I've managed to write a code that can capture STDOUT of .py files, however when I run the exact same code with executable generated from Pyinstaller (doesn't matter whether it's windowed or not) the readyReadStandardOutput signal doesn't ever come up.

From my tests it occurs that any signal at all is emitted only when the app crashes, however I need a live communication between the GUI and the executable.

Here's my code for reference:

  def start_process(self, program, args=None):
        if args is None:
            args = []

        process = QtCore.QProcess(self)
        process.readyReadStandardOutput.connect(partial(self.onReadyReadStandardOutput, self.number_process_running))

        process.start(program)

and the method that I've connected the signal to:

    def onReadyReadStandardOutput(self, i):
        print("called")
        process = self.sender()
        self.results[i] = process.readAllStandardOutput()
        self.resultsChanged.emit(self.results)

I'm working on a Windows machine


EDIT: Minimal reproducible example

Let's take a small script

import time

if __name__ == "__main__":
    num = 0
    while True:
        num = num + 1
        print(num)
        time.sleep(3)

Let's leave the PyQT processes for now and use simpler Popen. If we run the script in Popen, the stdout will be redirected to the calling process.

if __name__ == '__main__':
    p = Popen([r'python', 'test.py'], stdin=PIPE, stdout=PIPE, stderr=PIPE)
    while p.poll() is None:
        out = p.stdout.readline()
        print(out)

However, if we take the first script and put through PyInstaller single executable generator, the Popen won't capture any output no more, it will just freeze

import os
import sys

import PyInstaller.__main__

file_location = os.path.dirname(os.path.realpath(__file__))

if sys.platform == "win32":
    PyInstaller.__main__.run([
        '--name=%s' % 'test',
        '--onefile',
        '--noconsole',
        '--distpath=%s' % os.path.join(file_location, 'dist'),
        '--workpath=%s' % os.path.join(file_location, 'build'),
        '--specpath=%s' % os.path.join(file_location),
        os.path.join(file_location, 'test.py'),
    ])

So again my question is - am I missing some important part in there? Or maybe it's just pyinstaller's fault.

Upvotes: 2

Views: 976

Answers (1)

eyllanesc
eyllanesc

Reputation: 244252

It seems that when you compile the script you should set the flush of the print to True, so just change it to:

import time

if __name__ == "__main__":
    num = 0
    while True:
        num = num + 1
        print(num, flush=True)
        time.sleep(3)

Upvotes: 3

Related Questions