6

I don't seem to be getting the correct exit code from subprocess.call on Windows.

import subprocess
exit_code = subprocess.call(['ant.bat', 'fail'])
print exit_code # prints 0

Doing the same thing on windows seems to return something other than 0

> echo %errorlevel%
0
> ant fail
> echo %errorlevel%
1

Shouldn't the values from both calls give the same value? Am I doing something wrong?

In the worst case, how do I check the value of %errorlevel% in my python script?

UPDATE:

I tried something like this to get the errorlevel value:

environment = os.environment.copy()
cmd = subprocess.Popen(['ant.bat', 'fail'], env = environment)
for key, value in environment.items():
    print '%s = %s' % (key, value)

However I do not see errorlevel in that dictionary (os.getenv['errorlevel'] also fails).

1
  • Your code works for me (on Windows 7). Can you give some more detail? May it be that the problem is in the .bat file itself? Commented Jul 9, 2011 at 22:56

3 Answers 3

8

A process exit code and the errorlevel environment variable aren't the same:

ant.bat:

if "%1"=="batch_fail" exit /B 1
if "%1"=="proc_fail" exit 1


>>> import subprocess
>>> subprocess.call(['ant.bat', 'batch_fail'])
0
>>> subprocess.call(['ant.bat', 'proc_fail'])
1

batch_fail will set the errorlevel to 1, but that's no longer available after the shell exits. proc_fail, however, sets the process exit code to 1. The only solution that comes to mind is a wrapper batch file that calls ant.bat and sets the process exit code according to the errorlevel:

ant_wrapper.bat:

@echo off
call ant.bat %1
if errorlevel 1 exit 1

>>> subprocess.call(['ant_wrapper.bat'])
0
>>> subprocess.call(['ant_wrapper.bat', 'batch_fail'])
1
>>> subprocess.call(['ant_wrapper.bat', 'proc_fail'])
1

Edit:

Your update got me thinking about an alternate approach using Popen. You can run the batch file via cmd's /K option, which will run a command without exiting. Then simply send exit %errorlevel% via stdin, and communicate():

#test errorlevel==1
>>> p = subprocess.Popen(['cmd', '/K', 'ant.bat', 'batch_fail'], 
      stdin=subprocess.PIPE, stdout=subprocess.PIPE)
>>> stdoutdata, stderrdata = p.communicate(b'exit %errorlevel%\r\n')
>>> p.returncode
1

#test errorlevel==0
>>> p = subprocess.Popen(['cmd', '/K', 'ant.bat'], 
      stdin=subprocess.PIPE, stdout=subprocess.PIPE)
>>> stdoutdata, stderrdata = p.communicate(b'exit %errorlevel%\r\n')
>>> p.returncode
0
Sign up to request clarification or add additional context in comments.

2 Comments

Thank you for that info. So do you think I can get the %errorlevel% value with Popen? Please see my update to the original question. I posted my attempt at using Popen. Can I make that work somehow?
Thank you that does work. Is there a way to do the same thing without redirecting stdout though? I want to keep printing the output to the console, but removing stdout=PIPE results in all kinds of craziness for me (I sometimes end up having to close the whole terminal window.)
0

I was able to get the correct behavior by using the batch call command, like

cmd = [os.environ['COMSPEC'], '/c', 'call', bat_file]
try:
    subprocess.check_call(cmd)
except subprocess.CalledProcessError:
    # Error handling code

(I used subprocess.check_call but subprocess.call ought to work the same way).

It's also always a good idea to put if errorlevel 1 exit 1 after every command in your batch script, to propagate the errors (roughly the equivalent of bash's set -e).

Comments

-1

os.system('ant.bat fail') does exactly what you want. It does return the errorlevel.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.