5

I am using Python subprocess to run external scripts on Windows 7. I am trying to get the exit code.


In case 1, I run a python script test1.py.

test1.py

import sys
sys.exit(24)   <--exit code

myscript1.py

import subprocess
process = subprocess.Popen(["python", "C:\\path\\to\\test1.py"], stdout=subprocess.PIPE)
process.wait()
print process.returncode

In Windows command prompt, when I run the script, I get the following output:

>python test1.py
>
>echo %errorlevel%
>24
>
>python myscript1.py
>24

So, you can see that subprocess is able to get the correct exit code in this case.


In case 2, I run a batch file test2.cmd.

test2.cmd

EXIT /B 56   <--exit code

myscript2.py

import subprocess
process = subprocess.Popen(["C:\\path\\to\\test2.cmd"], stdout=subprocess.PIPE)
process.wait()
print process.returncode

In Windows command prompt, when I run the script, I get the following output:

>test2.cmd
>
>echo %errorlevel%
>56
>
>python myscript2.py
>56

So, you can see that subprocess is also able to get the correct exit code in this case.


In case 3, I run a SikuliX script.

test3.sikuli

xxx xxx (sikuli script here)
xxx xxx
...
exit(16)   <--exit code

myscript3.py

import subprocess
process = subprocess.Popen(["C:\\path\\to\\runsikuli.cmd", "-r", "C:\\path\\to\\sikuli-script.sikuli"], stdout=subprocess.PIPE)
process.wait()
print process.returncode

In Windows command prompt, when I run the script, I get the following output:

>C:\path\to\runsikuli.cmd -r C:\path\to\sikuli-script.sikuli
>... (stdout + stderr)
>16
>
>echo %errorlevel%
>16
>
>python myscript3.py
>0

In case 3, when I run the script manually in the command prompt, it is able to set the %errorlevel%. When I run the script using Python subprocess, subprocess is unable to get the correct exit code. It always return 0.

Why Python subprocess failed to get the exit code in case 3?

userpal
  • 1,483
  • 2
  • 22
  • 38
  • why do you run jython script using ` `? What is the exact command that you run manually that ends with `echo %errorlevel%`? Do you need the output (stdout/stderr) from the jython script? Unrelated: why do you need both python and jython? Could jython along be enough? – jfs Jul 03 '14 at 20:16
  • @J.F.Sebastian Hi Sebastian, I have added more description of the problems. – userpal Jul 04 '14 at 13:45
  • what happens if add a long pause in the jython script? Does the parent python script wait for it? Try: `print(subprocess.call(r'C:\path\to\runsikuli.cmd -r C:\path\to\sikuli-script.sikuli & echo %errorlevel%', shell=True))` – jfs Jul 04 '14 at 14:00
  • @J.F.Sebastian Hi Sebastian, I have added a long pause in the Jython script using `time.sleep(30)`. The parent python script waits for it to complete. When I run this command `print(subprocess.call(r'C:\path\to\runsikuli.cmd -r C:\path\to\sikuli-script.sikuli & echo %errorlevel%', shell=True))`, it prints out all the output from the Jython script execution. In the end, it prints out 2 exit code, 1 returned by `echo %errorlevel%`, 1 returned by `print(..)`, both are 0. The problem is, when I run the same Jython script manually in command prompt, the `%errorlevel%` is correctly set. – userpal Jul 07 '14 at 01:37
  • what happens if you run the *exact* command that is inside `r''` quotes literally (just copy-paste it) in the command prompt (is it cmd.exe or PowerShell?)? – jfs Jul 08 '14 at 01:07
  • @J.F.Sebastian I am using cmd.exe. I have copy-paste the command inside `r''` quote into cmd.exe. After I run it, it shows that the exit code is 0. Anyway, although I still don't know what is the root cause of this issue, I have found a way to get the exit code indirectly. Please refer to my answer below. – userpal Jul 08 '14 at 13:06
  • Can I ask what version of python you're using exactly? – mintchkin Jul 08 '14 at 13:47
  • @mintchkin Hi mintchkin, I am using Python 2.7 on Windows 7. – userpal Jul 09 '14 at 04:56
  • Does it help if you add `& exit` at the end: `subprocess.check_call(r'C:\path\to\runsikuli.cmd -r C:\path\to\sikuli-script.sikuli & exit', shell=True)`? ["subprocess on Windows: wrong return code with shell=True"](http://bugs.python.org/issue20117) Python issue might be related. – jfs Jul 16 '14 at 08:45
  • @J.F.Sebastian Thank you! Adding `& exit` at the end of the command solved the problem! Finally this problem is solved. :) Please put your answer in the answer section. Thanks. – userpal Jul 18 '14 at 13:13
  • @PatrickL: I've updated [my answer](http://stackoverflow.com/a/24633460/4279) to mention `& exit` workaround. – jfs Jul 26 '14 at 14:14

2 Answers2

3

As your comment says if you run the same command then both the command prompt and using Python subprocess module produce the same result (0 exit code).

You may see different exit codes because you use different commands. No surprise here. Python subprocess module returns correct (for a given command) exit code.


If it doesn't return the right exit status then you could add & exit at the end of your cmd.exe command as a workaround to get the correct return code, see "subprocess on Windows: wrong return code with shell=True" on Python issue tracker:

from subprocess import check_call

check_call(r'C:\path\to\runsikuli.cmd -r C:\path\to\sikuli-script.sikuli & exit',
           shell=True)
Community
  • 1
  • 1
jfs
  • 399,953
  • 195
  • 994
  • 1,670
  • Hi Sebastian, the command gives exit code 0 because you have added `& echo %errorlevel%` at the end of the command you gave me in `r''`. When I run my original command (without `& echo ..`) in cmd.exe, and then I manually run `echo %errorlevel%` in cmd.exe, it shows the exit code correctly (not 0). When I copy-paste my original command (without `& echo ..`) into Python subprocess and run it, it shows that exit code is 0. – userpal Jul 09 '14 at 04:55
  • @PatrickL: _no_, [you said](http://stackoverflow.com/questions/24555044/why-sometimes-python-subprocess-failed-to-get-the-correct-exit-code-after-runnin/24633460?noredirect=1#comment38118494_24555044): "**both** are zero." `echo %errrolevel%` prints exit code of the previous command, not the `echo` command itself. And _yes_, adding `& echo ..` makes `subprocess.call()` to return `0`. It doesn't make the first command to return `0`. – jfs Jul 09 '14 at 19:55
  • To avoid confusion, let me describe the commands i used in details. When I run `C:\path\to\runsikuli.cmd -r C:\path\to\sikuli-script.sikuli` in cmd.exe, and then run `echo %errrolevel%` in cmd.exe, it shows `16`. When I run your command `C:\path\to\runsikuli.cmd -r C:\path\to\sikuli-script.sikuli & echo %errorlevel%` in cmd.exe, it shows `0`. When I run `r'C:\path\to\runsikuli.cmd -r C:\path\to\sikuli-script.sikuli'` in Python subprocess and print the return code, it shows `0`. – userpal Jul 10 '14 at 00:53
  • @PatrickL: what happens if you run a command e.g. `python -c "exit(11)"` *before* running `...runsikuli.cmd ...sikuli & echo %errorlevel%` Does it print `11` or `0` in the end? What happens if you run `python -c "exit(12)"`, and then run `echo %errorlevel%` in cmd.exe? What happens if you run `python -c "exit(13)" & echo %errorlevel%`? Does it show `13`? What happens if you run `cmd /c "python -c "exit(14)""`, and then run `echo %errorlevel%` in cmd.exe? (you might need to add `^` before internal quotes `"`). – jfs Jul 10 '14 at 03:10
  • When I run `python -c "exit(11)"` before running `...runsikuli.cmd ...sikuli & echo %errorlevel%`, it prints `11`. When I run `python -c "exit(12)"` and then run `echo %errorlevel%`, it prints `12`. When I run `python -c "exit(13)" & echo %errorlevel%`, it prints `12`. When I run `cmd /c "python -c "exit(14)""` with `^` before internal quotes, it prints `14`. When I run `cmd /c "python -c "exit(14)""` without `^` before internal quotes, it prints `14`. Please note that all these commands are run in sequence in the same cmd.exe window. – userpal Jul 10 '14 at 05:12
  • @PatrickL: it is clear the results that `%errorlevel%` does not contain the exit code of the previous command (the one that comes before `&`). – jfs Jul 16 '14 at 08:49
0

Although this does not answer the question directly, you can use this method to get the exit code indirectly in Python subprocess.

Create a batch file batch.cmd. In the file, call the command that you want to execute like this:

call %1 -r %2
EXIT /B %errorlevel%

In your python script:

import subprocess
exitcode = subprocess.call(r'C:\path\to\batch.cmd C:\path\to\runsikuli.cmd C:\path\to\sikuli-script.sikuli', shell=True)
print "Exit Code = "+str(exitcode)
userpal
  • 1,483
  • 2
  • 22
  • 38