3

I'm using python 3.5.3 with PyQT 5 and I have written GUI with it. This GUI run python code python code with subprocess.run.

In order to leave my GUI active and not frozen during the subprocess operation , i'm running the subprocess in a thread.

In the GUI i have stop button that if the user pressed , I want to terminate the subprocess.

I have no problem to kill the thread by using terminate method of the thread. But that's don't terminate the subprocess.

I've tried to use Popen instead of run but I cant make it to run as subprocess.run does. in addition , I prefer to use the recommended way by Python that's give me also the check_error option

This is how I use subprocess:

class c_run_test_thread(QtCore.QThread):

    def __init__(self,test_file,log_file):
        QtCore.QThread.__init__(self)
        self.test_file = test_file
        self.log_file = log_file

    def __del__(self):
        self.wait()

    def run(self):
        # Thread logic

        try:
            # Run the test with all prints and exceptions go to global log file
            self.test_sub_process = subprocess.run(["python", self.test_file],stdout = self.log_file, stderr = self.log_file,check = True)

    except subprocess.CalledProcessError as error:
        print("Error : {}".format(error))

    # Flush memory to file
    self.log_file.flush(

def stop(self):

    # Flush memory to file
    self.log_file.flush()

And I terminate the thread by

# Stop test thread
self.thread_run_test.terminate()

To sum things up , I want to kill thread while killing its sub process too.

Gil.I
  • 895
  • 12
  • 23

1 Answers1

1

There may be other simpler ways to this, but what I did was to

  1. Use subprocess.Popen to run a sub process, instead of subprocess.run, since the latter will not return before the process is terminated
  2. Check if the process is terminated using Popen.poll
  3. Kill the process using Popen.kill

A sample code would be sth. like the following:

self.test_sub_process = subprocess.Popen(["python", self.test_file],
                                         stdout=self.log_file,
                                         stderr=self.log_file)

Wait for termination:

print("Return code: {}".format(self.test_sub_process.wait()))

Or if you want to do something while waiting:

while self.test_sub_process.poll() is None:
    doSomething()
print("Return code: {}".format(self.test_sub_process.poll()))

Then in thread_run_test.terminate(), you can kill the process

self.test_sub_process.kill()

HTH.

Joey Zhang
  • 348
  • 2
  • 9
  • you didn't change the .run to Popen . does it have the same parameters? the PIPE in .run method its nicer than os.read , can I use Popen and PIPE as today and still use Popen? – Gil.I Jul 30 '17 at 21:15
  • @Gil.I Have changed it to use `Popen`. – Joey Zhang Jul 30 '17 at 22:01
  • when I used your suggestion , some of the stdout is not written to the log file. I dont know why. Instead I used the following : self.test_sub_process = subprocess.Popen(["python", self.test_file], stdout = self.log_file, stderr = self.log_file) while (self.test_sub_process.poll() is None): print ("Test is running") print("Return code: {}".format(self.test_sub_process.poll())) The return code pare is of course outside of the loop and now the log is full without missing any data – Gil.I Jul 31 '17 at 13:05
  • @Gil.I, it is interesting that it may lose some `stdout` messages. Does `self.test_file` write to both `stderr` and `stdout`? I believe they should be handled differently. Anyway, it looks like it is more convenient for you to just use file objects instead of `PIPE`s. I've updated the response to meet your situation better. – Joey Zhang Jul 31 '17 at 17:01
  • I posted a followup question ,to know how to kill the subprocess in orderly fashion , while calling all objects destrcutors https://stackoverflow.com/questions/45422527/how-to-kill-sub-process-in-anytime-while-closing-it-in-orderly-fashion – Gil.I Jul 31 '17 at 18:09