Qprocess not working on Windows (works fine on Linux and OSX)
-
I am trying to spawn a subprocess from my main programm using the QProcess module. This process should send information to the main programm. My code works fine for Linux and OSX but doesn't work on Windows. It seems like the commands for executing the the process aren't even read since a wrong path does not trigger any Error messages.
I have already asked this question on stackoverflow but so far no suggestion worked out.
link: https://stackoverflow.com/questions/71881833/qprocess-wont-start-process-on-windows-but-works-on-linux-and-osx?noredirect=1#comment127039137_71881833here my code for the main program:
import sys from PyQt5 import QtCore, QtWidgets, QtGui from PyQt5 import uic import pickle class MyGuiApp(QtWidgets.QMainWindow): def __init__(self): QtWidgets.QMainWindow.__init__(self) self.ui = uic.loadUi('process_gui.ui', self) # Set puchButtons self.stop_pB.setEnabled(False) self.start_pB.clicked.connect(self.start_measurement) self.stop_pB.clicked.connect(self.stop_measurement) # Initialising Subprocess self.my_process = QtCore.QProcess() self.my_process.readyReadStandardOutput.connect(self.new_data) def start_measurement(self): self.stop_pB.setEnabled(True) self.start_pB.setEnabled(False) self.my_process.start('python3', ['C:Users/me/desktop/dummyfolder/main_subprocess.py']) def stop_measurement(self): self.stop_pB.setEnabled(False) self.start_pB.setEnabled(True) self.my_process.terminate() def new_data(self): data = self.my_process.readAllStandardOutput() # unpickle data -> string stdout_str = pickle.loads(data) self.label.setText(stdout_str) if __name__=='__main__': app = QtWidgets.QApplication(sys.argv) mainWindow = MyGuiApp() mainWindow.show() sys.exit(app.exec_())
here the code for my subprocess:
import time import sys import pickle index = 0 while True: start = time.time() sys.stdout.buffer.write(pickle.dumps(str(index))) sys.stdout.flush() index = index + 1 time.sleep(0.5-(time.time()-start)) # sets loop runtime to 0.5 secs
and in case someone wants to run the code here the .ui code:
<?xml version="1.0" encoding="UTF-8"?> <ui version="4.0"> <class>MainWindow</class> <widget class="QMainWindow" name="MainWindow"> <property name="geometry"> <rect> <x>0</x> <y>0</y> <width>800</width> <height>600</height> </rect> </property> <property name="windowTitle"> <string>MainWindow</string> </property> <widget class="QWidget" name="centralwidget"> <layout class="QGridLayout" name="gridLayout_2"> <item row="0" column="0"> <widget class="QGroupBox" name="groupBox"> <property name="title"> <string>GroupBox</string> </property> <layout class="QGridLayout" name="gridLayout"> <item row="0" column="0"> <layout class="QVBoxLayout" name="verticalLayout"> <item> <widget class="QPushButton" name="start_pB"> <property name="text"> <string>Start</string> </property> </widget> </item> <item> <widget class="QPushButton" name="stop_pB"> <property name="text"> <string>Stop</string> </property> </widget> </item> <item> <widget class="QLabel" name="label"> <property name="font"> <font> <pointsize>20</pointsize> </font> </property> <property name="text"> <string>DATA</string> </property> </widget> </item> </layout> </item> </layout> </widget> </item> </layout> </widget> <widget class="QMenuBar" name="menubar"> <property name="geometry"> <rect> <x>0</x> <y>0</y> <width>800</width> <height>22</height> </rect> </property> </widget> <widget class="QStatusBar" name="statusbar"/> </widget> <resources/> <connections/> </ui>
-
@Dost said in Qprocess not working on Windows (works fine on Linux and OSX):
'C:Users/me/desktop/dummyfolder/main_subprocess.py'
This is not an absolute path, and doubtless not what you intended, so hardly surprising.
If you had read from the
QProcess
standard error, and checked for an error, as you should always do, you would doubtless have seen the appropriate error message saying "it cannot be found". Before you say it's not the path but something else, connect toQProcess::errorOccurred()
&readyReadStandardError()
; if still unclear, connect tostarted()
,stateChanged()
&finished()
.Put a
print("Reached\n")
instart_measurement()
. And create a file somewhere as the first statement in your.py
subprocess script, so that we know whether it has actually run or not rather than relying on whether you think you see any output from it. -
Thank for your awnser. Sadly i was slopy when editing the path, in my program i am actually using an absolute path. I also did the trick with the file already so i knew that the subprocess didn't even start.
I added what you have suggested now, with the result: error code 0 (The process failed to start. Either the invoked program is missing, or you may have insufficient permissions to invoke the program.)
I double checked the file path so there should be no problem with that. Concerning the insufficient permissions, what to do about that?
updated code:
import sys from PyQt5 import QtCore, QtWidgets from PyQt5 import uic import pickle class MyGuiApp(QtWidgets.QMainWindow): def __init__(self): print('too far') QtWidgets.QMainWindow.__init__(self) self.ui = uic.loadUi('process_gui.ui', self) # Settings pushButtons self.stop_pB.setEnabled(False) self.start_pB.clicked.connect(self.start_measurement) self.stop_pB.clicked.connect(self.stop_measurement) # Initialising Subprocess self.my_process = QtCore.QProcess() self.my_process.readyReadStandardOutput.connect(self.new_data) self.my_process.readyReadStandardError.connect(self.process_error) self.my_process.started.connect(self.started) self.my_process.errorOccurred.connect(self.error) # tried another way, both didn't work self.my_process.setProgram('python3') self.my_process.setArguments([r'C:\Users\Me\Desktop\dummyfolder\main_subprocess.py']) print(str(self.my_process.state()), 'State (init)') def start_measurement(self): self.stop_pB.setEnabled(True) self.start_pB.setEnabled(False) #self.my_process.start('python3', [r'C:\Users\Me\Desktop\dummyfolder\main_subprocess.py']) self.my_process.start() print(str(self.my_process.state()), 'State (start_measurement)') print('reached') def stop_measurement(self): self.stop_pB.setEnabled(False) self.start_pB.setEnabled(True) self.my_process.terminate() def new_data(self): data = self.my_process.readAllStandardOutput() # unpickle data -> string stdout_str = pickle.loads(data) self.label.setText(stdout_str) def process_error(self): error = self.my_process.readAllStandardError() print(error) def started(self): print('process started') def error(self): print('error occurred {}'.format(self.my_process.error())) if __name__ == '__main__': app = QtWidgets.QApplication(sys.argv) mainWindow = MyGuiApp() mainWindow.show() sys.exit(app.exec_())
-
@Dost said in Qprocess not working on Windows (works fine on Linux and OSX):
I added what you have suggested now, with the result: error code 0 (The process failed to start. Either the invoked program is missing, or you may have insufficient permissions to invoke the program.)
Well whatever the reason that seems to be the cause if you are saying that is the error text it reports.
I am not clear from what you write where that message came from? From
process_error()
? Fromerror()
? Did you get any message fromstarted()
?The "invoked program" in this case is
python3
, not your.py
script file argument to it.Let's start by removing the script. I believe that, say,
python3 -V
just reports some stuff and exits. Try that, or something similar. Does it run, do you get its output? Assuming not, we know where we are. Are you surepython3
is in some directory on yourPATH
when invoked from your Qt app? Can it find whatever DLLs it needs correctly from thatPATH
? Where ispython3
, is it a.exe
or a.bat
file? Does it help to give the full path to the desiredpython3.exe
instead of just your plainpython3
to run it?Go find something completely different from
python3
to execute, and verify that does work as expected. -
Again thank you for your answer. As you already assumed the problem was that i had to add the path leading to the python.exe.
The error was triggered by errorConnect and there was no message from started().
A new problem occured as the Qprocess wont stop when terminate() (state stays 2 before and after the call) is called, but it works with kill() for me.
-
@Dost
Good for thePATH
issue. Consider puttingpython3
on yourPATH
rather than having to typing the full path to it.A new problem occured as the Qprocess wont stop when terminate() (state stays 2 before and after the call) is called, but it works with kill() for me.
This is usual for Windows, for any command-line program like
python3
:Console applications on Windows that do not run an event loop, or whose event loop does not handle the WM_CLOSE message, can only be terminated by calling kill().
Really it's naughty to need to use either
terminate()
or particularlykill()
. Presumably your Python script runs forever and does not have a nice means to exit it.