1

This works:

def letsExecute():
    import subprocess
    subpr = subprocess.Popen("python " + codeFile + spacedout)

This causes the program to not respond (I'm running on windows):

def letsExecute():
    import subprocess
    subprocess.call("python " + codeFile + spacedout)

wait, communicate and basically anything that makes the main process wait for the sub process causes the same. I want the main process to quit when the subprocess finishes successfully.

Also, FYI: this function is hooked to a tkinter Button, and this program uses tkinter GUI and a mainloop(). Dunno if this affects this problem, but letting you know anyway.

Thanks in advance!

Bryan Oakley
  • 370,779
  • 53
  • 539
  • 685
svm96
  • 55
  • 8

2 Answers2

1

There are few issues with your code.

subprocess.call()

Run the command described by args. Wait for command to complete, then return the returncode attribute.

wait() and communicate() are also blocking functions.

Use poll() instead.

subpr = subprocess.Popen(["python", codeFile, spacedout])

while subpr.poll() is None:
    print("Still working...")
    time.sleep(0.1)

Since you want the GUI thread to be responsive you can start the sub-process on a different thread. something like this,

import subprocess
import threading
import time

def letsExecute():
   t = threading.Thread(target=realExec)
   t.run()

def realExec():
   proc = subprocess.Popen(["python", codeFile, spacedout])

   while proc.poll() is None:
       print("Still working...")
       time.sleep(0.1)
Himal
  • 1,351
  • 3
  • 13
  • 28
1

First of all, why you trying to subprocess another python script when you can just import it?

Anyway, you problem stems from the fact that any of call, wait and communicate waits for termination of subprocess if timeout parameter is ommited. Because of this tkinter application unable to refresh itself and mainloop is unreachable for code flow.

If you have something complicated in your mind - take a look at threading, multiprocessing and this topic.

If you want just terminate the main process when the subprocess finishes - take a look at thoose snippets:

test.py:

import time

time.sleep(5)

main.py:

try:
    import tkinter as tk
except ImportError:
    import Tkinter as tk

import subprocess

class App(tk.Tk):
    def __init__(self, *args, **kwargs):
        tk.Tk.__init__(self, *args, **kwargs)

        self.button = tk.Button(self, text='Start', command=self.start_test_process)
        self.button.pack()
        self.process = None

    def continuous_check(self):
        status = self.process.poll()

        if status is None:
            print('busy')
            self.after(500, self.continuous_check)
        elif status == 0:
            print('successfully finished')
            self.destroy()
        else:
            print('something went wrong')

    def start_test_process(self):
        self.process = subprocess.Popen('python test.py')
        self.continuous_check()


app = App()
app.mainloop()

The main idea here in keep mainloop reachable for code with combination of poll and after methods.

CommonSense
  • 4,232
  • 2
  • 14
  • 38