A program that runs a bat file which contains instruction for running an executable(longTask) using Qthread but it doesn't work as expected when I create an executable using Pyinstaller with the following command. I gave '--windowed' to do not provide a console window for standard i/o
pyinstaller --onefile --windowed main.py
But the interesting thing is it works as expected when I remove the --windowed argument
pyinstaller --onefile main.py
Here is the code:
from PyQt4.Qt import *
import subprocess
def callSubprocess():
page = QWizardPage()
page.setTitle("Run myLongTask")
runButton = QPushButton("Run")
progressBar = QProgressBar()
procLabel = QLabel()
procLabel1 = QLabel()
progressBar.setRange(0, 1)
layout = QGridLayout()
layout.addWidget(runButton, 0, 0)
layout.addWidget(progressBar, 0, 1)
layout.addWidget(procLabel)
layout.addWidget(procLabel1)
# Calls thread class
myLongTask = TaskThread()
runButton.clicked.connect(lambda: OnStart(myLongTask, progressBar, procLabel1))
myLongTask.taskFinished.connect(lambda: onFinished(progressBar, procLabel))
page.setLayout(layout)
return page
def OnStart(myLongTask, progressBar, procLabel1):
progressBar.setRange(0, 0)
myLongTask.start()
# I am waiting until my subprocess completes
while not myLongTask.isFinished():
QCoreApplication.processEvents()
procLabel1.setText("Hello This is main")
def onFinished(progressBar, procLabel):
# Stop the pulsation
progressBar.setRange(0, 1)
procLabel.setText("longTask finished")
class TaskThread(QThread):
taskFinished = pyqtSignal()
def __init__(self):
QThread.__init__(self)
def run(self):
proc = subprocess.Popen(r'C:\Users\Desktop\runInf.bat', bufsize=0, shell=True, stdout=subprocess.PIPE)
proc.wait()
self.taskFinished.emit()
def __del__(self):
self.wait()
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
wizard = QWizard()
wizard.addPage(callSubprocess())
wizard.setWindowTitle("Example Application")
wizard.show()
sys.exit(wizard.exec_())
When executed the above code in Pycharm it works as expected. But when built with PyInstaller, the main thread doesn't wait until the subprocess completion.
Any idea how to create an executable where threading works as expected. Thanks in advance
The most common reason a PyInstaller package fails is that PyInstaller failed to bundle a required file. Such missing files fall into a few categories: Hidden or missing imports: Sometimes PyInstaller can't detect the import of a package or library, typically because it is imported dynamically.
PyInstaller's bootloader is usually quite fast in one-dir mode, but it can be much slower in one-file mode, because it depacks everything into a temporary directory. On Windows, I/O is very slow, and then you have antiviruses that will want to double check all those DLL files. PyQt itself is a non-issue.
PyInstaller can bundle your script and all its dependencies into a single executable named myscript ( myscript.exe in Windows). The advantage is that your users get something they understand, a single executable to launch.
I just resolved this issue. My findings as follows.
The culprit is subprocess. So I replaced subprocess with some file handling (let's say opening a file 10000 times and write some content) and it works as expected which means the main thread waits until child process completes.
So Pyinstaller does work properly with threading
I added few more arguments
proc = subprocess.Popen(os.getcwd() + r'\runInf.bat',
shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
stdin=subprocess.PIPE,
cwd=os.getcwd(),
env=os.environ)
proc.stdin.close()
This change made the subprocess to run and the main thread also waits until its completion
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With