8

I would like to get the output (print statements) and return status from a python subprocess along with displaying logging info. I am using Python 2.5 on Windows XP. How do I get the return code as well? Here in this extract, I am reading output so that I can redirect it to display in a wxPython TextCtrl in a separate thread.

self.myproc.poll()                      
if self.myproc.returncode is None:             
    # Still running so check stdout
    txt = self.myproc.stdout.read(self._readblock)     
    if txt:        
        # Add to UI's update queue
        self._parent.AppendUpdate(txt)        
    else:   
        break     
jro
  • 9,300
  • 2
  • 32
  • 37
user974168
  • 227
  • 4
  • 11

1 Answers1

7

The returncode gets returned by the poll call, and is also (once poll did not return None) accessible via the returncode attribute. You are already using this in your code, so I'm not sure what your problem with that is.

When you want to update your control while your process is running, use readline instead of read: the latter will wait for the entire output to be present, while the former will wait on a newline character. To give a full example using your variable names:

from subprocess import Popen, PIPE
self.myproc = Popen('dir /s', shell=True, stdout=PIPE, stderr=PIPE)
while self.myproc.poll() == None:
    self._parent.AppendUpdate(self.myproc.stdout.readline())
self._parent.AppendUpdate('Return code was ' + self.myproc.returncode)

Note that you might want to .strip() the readline result as it will contain the newline character.

Edit: To address your confusion between the script output and its return code, the following. First, a Python script at module level cannot return a value: that would yield a syntax error. So what you should differentiate between is the output of the script, and the return code it gives.

The script's output is in the above example read by using the self.myproc.stdout.readline method. Every time the external process has produced a line of outputted text, calling that function would retrieve it.

The return code however (or exit status) is an integer that gets passed from a child process to the parent (your) process, indicating the state in which the child process exited. In Python, you do this with the sys.exit function. Most commonly, when this value is zero it indicates success; a non-zero value depicts some kind of error.

Say your child process script looks like this:

import sys
# Do some stuff
print 'pass'    # Gets to stdout
sys.exit(0)     # Return code

Executing this external file (let's call it test.py) with the Popen class, we will get pass when we read out self.myproc.stdout, and 0 when we read out self.myproc.poll (or self.myproc.returncode after the first poll).

The purpose of this return code is that you do not have to parse all of the child process' output to determine if it succeeded in its job: you are free to define your own exit codes. For example, you could consider 0 to be a success, 1 to be a failure, 2 to be some kind of invalid input given, 9 an unknown error, and so on. That way, you can just keep polling the process, and based on the exit code returned by that poll you directly know if it was successful. Note that this is a bit less applicable to your case as you need the output of the child process anyway, but still it is easier to parse a number than a string to determine success.

jro
  • 9,300
  • 2
  • 32
  • 37
  • the command in my process is a python file and returns a value for example a string like 'Pass' or 'Fail'. I was just getting return values like 0 or 1 – user974168 Nov 09 '11 at 12:22
  • Ah, then you just need to analyse the last line of `stdout`. The return code is an indication of the exit condition of the program, and is an integer. – jro Nov 09 '11 at 12:29
  • I am sorry I did'nt understand your comment. For argument's sake the called process is like this def main(): a= 5 b= 6 c= a+b print c return 'PASS' if __name__ == '__main__': main() How will get return value 'PASS' here ? – user974168 Nov 09 '11 at 12:47
  • @user974168: as the comment field was a bit small, I updated the answer to be able to better explain it. – jro Nov 09 '11 at 13:39
  • I was confused by this question where the questioner states that" return value (a list) prints to stdout, but isn't captured [4460475,4406612,4379510] " http://stackoverflow.com/questions/6246061/getting-the-return-value-of-a-python-subprocess – user974168 Nov 09 '11 at 15:51
  • @user974168: True... the devil is in the details, to quote that question: _"The return value (a list) prints to stdout, but isn't captured"_. Note that the two concepts are mixed there ("return value", and "prints to stdout"). Does the updated answer resolve your issue? – jro Nov 09 '11 at 16:03