5

In Python, I run an exe made using FORTRAN. I use the subprocess module. that exe accesses and writes to several files. If I make those files readonly, I see the following trace in my Python console.

I tried by using try, except statements. But I could not capture the error. I also tried using p.stdout.readline(). But was unsuccessful.

Is there a systematic way to capture this sort of errors.

Code:

import subprocess p = subprocess.Popen('C:\\TGSSR\\test.exe' , shell=True, stdout=subprocess.PIPE) 

Traceback:

forrtl: severe (9): permission to access file denied, unit 6, file C:\test\mar22_SSOUT\RawReadLog.dat Image PC Routine Line Source test.exe 0116DC40 Unknown Unknown Unknown test.exe 0113D42F Unknown Unknown Unknown test.exe 0112AE97 Unknown Unknown Unknown test.exe 0112A1DA Unknown Unknown Unknown test.exe 0110D746 Unknown Unknown Unknown test.exe 0108B9AC Unknown Unknown Unknown test.exe 01173FE3 Unknown Unknown Unknown test.exe 011588F5 Unknown Unknown Unknown kernel32.dll 76D33677 Unknown Unknown Unknown ntdll.dll 77A39F42 Unknown Unknown Unknown ntdll.dll 77A39F15 Unknown Unknown Unknown 
2
  • 1
    unrelated: to avoid escaping backslashes, you could use raw-string literals: r'C:\TGSSR\test.exe'. Don't use shell=True on Windows unless you use the shell functionality e.g., to call a builtin shell command such as dir. Don't use stdout=PIPE unless you read from p.stdout later Commented Mar 23, 2014 at 4:27
  • Sometimes errors are written outside stdout/stderr (directly to the terminal). See Capture “Segmentation fault” message for a crashed subprocess: no out and err after a call to communicate() Commented Mar 23, 2014 at 13:07

4 Answers 4

8

Run the process:

p = subprocess.Popen(['C:\\TGSSR\\test.exe'], stdout=subprocess.PIPE, stderr=subprocess.PIPE) # shell = True is not needed 

To capture the error message:

stdout, stderr = p.communicate() # stdout = normal output # stderr = error output 

Check the process return code:

if p.returncode != 0: # handle error 
Sign up to request clarification or add additional context in comments.

7 Comments

While maybe not necessary on windows, if you're going to not use a shell, you should pass the executable as a list: ['C:\\TGSSR\\test.ext']. Also, the returncode may not be reliable as (to my knowledge), there still isn't a good standardized way to set a process's return code in Fortran.
in this case p is null in both states (successful or unsuccessful). So I'm unable to rely on that!
@mgilson: Popen("program") works. It is equivalent to Popen(["program"]) on POSIX. On Windows, a string argument always works.
@user3161836: p is not null; you might mean p.returncode is None. The latter means that the process is not complete yet. You should check p.returncode after p.communicate() returns (it waits for the process to finish)
@mgilson: I actually forgot about that. Thanks for the pointing that out.
|
3

Python 3.5 introduced the subprocess.run() method.

Here is the @kirbyfan64sos answer updated for Python >=3.5:

Run the process:

p = subprocess.run(['C:\\TGSSR\\test.exe'], stdout=subprocess.PIPE, stderr=subprocess.PIPE) 

In >=3.5, you can access the returncode, stdout, and stderr from the executed process.

To capture the error message:

stdout = p.stdout # stdout = normal output stderr = p.stderr # stderr = error output 

Check the process return code:

if p.returncode != 0: # handle error 

Comments

2

If don't need all of Popen's functionality but just need to fetch stdout, you could also go for:

try: output = subprocess.check_output('C:\\TGSSR\\test.exe') except subprocess.CalledProcessError as e: print("Oops... returncode: " + e.returncode + ", output:\n" + e.output) else: print("Everything ok:\n" + output) 

EDIT: As mgilson pointed out in the other answer, this requires a non-zero returncode on failures. If that isn't the case, you could try something along the lines of:

output = subprocess.check_output('C:\\TGSSR\\test.exe') if "permission to access file denied" in output: print("Failed") 

with some string that will only be on stdout in case of an error

3 Comments

it should be subprocess.CalledProcessError in this case
This works for me.if I just need to run the exe, I think I can go for this option. Am I going to mis any major functionality if I go this way?
That was probably badly worded, check_output is a convenience function based on Popen which doesn't require handling stdout/stderr yourself (in your first post, you would actually need at least a p.communicate() in order to prevent the stdout pipe buffer from completely filling if you FORTRAN tool outputs a lot which would effectively stall execution). You can however easily switch to Popen. Popen gives more fine-grained control of process creation: link
0

In the majority of cases, you need to use subprocess.run. And to capture the error, you have to use the parameter "capture_output=True, check=True"

check=True is really necessary.

try: subprocess.run(args, cwd, capture_output=True, check=True) except subprocess.CalledProcessError as e: print("Error while executing YoloV5:") for k, v in e.__dict__.items(): print(k) if isinstance(v, bytes): print(v.decode("utf-8")) else: print(v) raise Exception("Error in subcommand") 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.