Subprocess in Python 3.7 returning different (incorrect?) return code compared with Python 2.7

255 Views Asked by At

Some help with a Python 2.7 / 3.7 return code difference in 'subprocess' would be appreciated.

I'm updating some code so that it produces the same output with both Python 2.7 and Python 3.7.

The code runs an external program using 'subprocess' and reads the program's return code. If the external program runs for more than a specific time, it kills itself and returns a return code of '-1'. When the external program is run in a Command Prompt the return code is '-1', as below,:

C:> test.exe -itest.cmd test.stl > null

C:> echo %ERRORLEVEL%

-1

I can run the command using subprocess in Python as below (I've also run it with os.system just as a comparison):

import os, sys, subprocess

print("\nOutput for Python version: " + sys.version.split("(")[0])

cmd = "test.exe -itest.cmd test.stl > null"
p_input = cmd.split()

p = subprocess.Popen(p_input, stdout=subprocess.PIPE)
p.communicate()
p_rc = p.returncode
print("subprocess return code :" + str(p_rc))

os_rc = os.system(cmd)
print("os.system return code :" + str(os_rc))

When I run the code with Python 2.7 I get the 'expected' return code:

Output for Python version: 2.7.16

subprocess return code :-1

os.system return code :-1

When I run the code with Python 3.7 I get a different return code for subprocess (but not for os.system):

Output for Python version: 3.7.9

subprocess return code :4294967295

os.system return code :-1

Is this different result expected? Whether it is, or not, how can I get my desired return code of '-1' with Python 3.7?

Running Python 2.7.16 / 3.7.9 on Windows 10

Thanks in advance :-)

Nick

1

There are 1 best solutions below

0
Nick Fromage On

subprocess.returncode now (since 3.3) returns an UNSIGNED 32 bit integer, so the returned value isn't incorrect - just not a signed 32 bit integer. To see negative return codes, the answer needs converting to a SIGNED 32 bit integer. This can be done by adding the following to the above code:

import ctypes
...
# get signed value return code in Python 3.*
p_rc = ctypes.c_int32(p_rc).value
print("SIGNED return code  :" + str(p_rc))

This gives the following output for Python 3.7:

Output for Python version: 3.7.9

subprocess return code :4294967295

SIGNED return code :-1

os.system return code :-1

Other ways of doing the same (thanks to kknechtel on discuss.python.org)... With struct:

import struct
...
p_rc = struct.unpack('i', struct.pack('I', p_rc))[0]

Or:

p_rc = (p_rc - (1 << 32)) if (p_rc >= (1 << 31)) else p_rc