30

I am trying to write a small app that uses the subprocess module.

My program calls an external Bash command that takes some time to process. During this time, I would like to show the user a series of messages like this:

Processing. Please wait...
The output is foo()

How can I do this using Popen.wait() or Popen.poll(). I have read that I need to use the Popen.returncode, but how I can get it to actively check the state, I don't know.

rypel
  • 4,686
  • 2
  • 25
  • 36
user225312
  • 126,773
  • 69
  • 172
  • 181

2 Answers2

42

Both wait() (with timeout specified) and poll() return None if the process has not yet finished, and something different if the process has finished (I think an integer, the exit code, hopefully 0).

Edit:

wait() and poll() have different behaviors:

  • wait (without the timeout argument) will block and wait for the process to complete.
  • wait with the timeout argument will wait timeout seconds for the process to complete. If it doesn't complete, it will throw the TimeoutExpired exception. If you catch the exception, you're then welcome to go on, or to wait again.
  • poll always returns immediately. It effectively does a wait with a timeout of 0, catches any exception, and returns None if the process hasn't completed.
  • With either wait or poll, if the process has completed, the popen object's returncode will be set (otherwise it's None - you can check for that as easily as calling wait or poll), and the return value from the function will also be the process's return code.

</Edit>

So I think you should do something like:

while myprocess.poll() is None:
    print("Still working...")
    # sleep a while

Be aware that if the bash script creates a lot of output you must use communicate() or something similar to prevent stdout or stderr to become stuffed.

Scott Mermelstein
  • 15,174
  • 4
  • 48
  • 76
extraneon
  • 23,575
  • 2
  • 47
  • 51
  • I am using communicate(). But I don't get it as to how I can return the returncode while the process is being executed. – user225312 Jun 08 '10 at 09:43
  • I solved it by doing this: if process.poll() is None: print 'Working' – user225312 Jun 08 '10 at 09:47
  • If _stdout_ and _stderr_ becoming stuffed is a concern, and/or to pass that info to the user while running, do `for line in myprocess.stdout: print(line)` and `for line in myprocess.stderr: print(line, file=sys.stderr)` (or something similar) once a loop. Careful, though, as the reads are blocking. – CivFan Oct 13 '15 at 22:51
  • As far as I'm aware, as of my edit on May 31 '16, this answer is no longer incorrect. (I still upvoted @onlyone for catching the mistakes.) – Scott Mermelstein May 31 '17 at 16:46
32

@extraneon's answer is a little backwards. Both wait() and poll() return the process's exit code if the process has finished. The poll() method will return None if the process is still running and the wait() method will block until the process exits:

Check out the following page: https://docs.python.org/3.4/library/subprocess.html#popen-objects

Popen.poll()

Check if child process has terminated. Set and return returncode attribute.

Popen.wait()

Wait for child process to terminate. Set and return returncode attribute.

nbro
  • 15,395
  • 32
  • 113
  • 196
onlynone
  • 7,602
  • 3
  • 31
  • 50
  • Anyone coming to experimenting with this `Popen.poll()` for the first time needs to be a bit wary of using "truthy" values: if you do `if popen.poll():` and your child process has returned 0, this will be `False`, i.e. it will look like the child process has not completed when it has. Better to test with `if popen.poll()!=None:`. – mike rodent Apr 04 '21 at 16:18