Batch file not receiving the ERRORLEVEL from the python script it launches - python

I have a batch file running a python script.
This python script always ends using sys.exit(code) no matter what, with code being an error code.
The batch file doesn't get my error code and instead always reads 0 with the following:
..\..\STS\Python\python.exe Version_code_ID.py %*
echo Error level = %ERRORLEVEL%
This instalation of python is in 3.7.1.
I know for sure my python code exited with other codes than 0 thanks to my logger (and me voluntarily causing errors for testing purpose).
For example I had it exit with 1 and 12, both attempts resulting in getting 0 in the batch.
Just in case, here is also the python function I use to exit:
def exit(code):
if(code > 0 ):
log.error("The computing module will shutdown with the following error code : "+str(code))
elif(code == 0):
log.info("Execution sucessfull")
log.info("STOP of VERSION_CODE_ID Computing Module")
log.removeHandler(stream_handler)
log.removeHandler(file_handler)
stream_handler.close()
file_handler.close()
sys.exit(code)
log is just the name of my logging.handlers logger.
Any idea what might be causing this problem?

Turns out the problem was that the bulk of my python script was in this try clause:
try:
#All of my code
except SystemExit:
()
except Exception as ex:
fun.log.error('ERROR: Unknown exception: ' + repr(ex))
I originally added the
except SystemExit:
()
because I thought SystemExit showing-up as an "exception" in the console was a problem, but it's not.
In short the solution was to remove that except.
The reason seem to be that catching the systemExit, as the name implies, doesn't let it get sent to the batch, which then believes no error code was sent.
Surprisingly for me except Exception as ex: doesn't catch the systemExit made by sys.exit(). That's great in my case since I still need it to log unknown exceptions.

Related

How to distinguish between subprocess errors in python?

I'm working on a terminal that can call other programs like any other terminal. I'm using subprocess for it, on Windows.
I'm running into 2 issues.
First:
Currently, I'm using OSError for all errors raised when using subprocess.Popen.
The code for it is here:
try:
subprocess.Popen([command])
except OSError:
print("'" + command[0] + "' is not recognised as a command, program or bterm file.")
When I type python, it opens command-line python correctly.
When I type asdfa, it returns the error.
The problem is, when I type python non-existent-file.py I get the same error, when the child argument was the issue.
I want the terminal to return (null): can't open file 'test': [Errno 2] No such file or directory like when it's called from cmd or bash.
How can I distinguish between these 2 errors, while keeping my custom error message for when the file doesn't exist?
Second: Whenever I pass multi-word args into subprocess.Popen or subprocess.call I automatically get that error, which I don't get using os.system()
I don't want to use os.system because I can't raise custom errors with it.
What am I doing wrong?
Exceptions in subprocess calls:
Exceptions raised in the child process, before the new program has started to execute, will be re-raised in the parent.
Additionally, the exception object will have one extra attribute called child_traceback, which is a string containing traceback information from the child’s point of view.
The most common exception raised is OSError.
This occurs, for example, when trying to execute a non-existent file. Applications should prepare for OSError exceptions.
A ValueError will be raised if Popen is called with invalid arguments.
check_call() and check_output() will raise CalledProcessError if the called process returns a non-zero return code.
You can find more at:
https://docs.python.org/2/library/subprocess.html#exceptions
As well as you can find the Exception Heirarchy at:
https://docs.python.org/2/library/exceptions.html#exception-hierarchy
try:
output = subprocess.check_output("\\test.exe')
except subprocess.CalledProcessError as e:
print("Something Fishy... returncode: " + e.returncode + ", output:\n" + e.output)
else:
print("Working Fine:\n" + output)
You could test for the existence of the executable first with the help of shutil.which.
if shutil.which(commands[0]):
try:
subprocess.Popen([commands])
except OSError as err:
print(err)
else:
print("'{}' is not recognised as a command, program or bterm file.".format(commands[0])
The documentation has a great deal of info however: https://docs.python.org/dev/library/subprocess.html which may be helpful.
Edit: showed how to capture output, thanks to Auxilor

Trigger failure in Jenkins, when anything in a python script fail

I have a python script running in the build phase of Jenkins, in the execute shell area.
The problem is that if the script fail, I still see the build as successful. I did check and python use something similar to the return code for a shell command (the one you call with $?), although I can't figure out where to put the call to have "any" failure in the python script to trigger that return code
import sys
..... code here
....functions
sys.exit(-1)
I need to return sys.exit(-1), but where do you put it in the python code? So far I can only handle it using try blocks, and in the exception part I put the sys.exit(-1), but this add a lots of code, since I have a lots of functions in the script.
Is there a global location that I can use, to trigger the failure, so the Jenkins job fail?
def main():
try:
do_the_work()
sys.exit(0) # success
except:
# insert code to log and debug the problem
sys.exit(-1)
In words: if do_the_work returns, sys.exit(0). If do_the_work raises any exception which it does not itself handle, sys.exit(-1). Inside do_the_work, do not return except on success. raise an exception on any unrecoverable error state, for example
class DoSomethingError( exception)
...
ok = do_something()
if not ok:
print ("do_something error return")
raise DoSomethingError
Logging and debugging: search stack overflow for python answers concerning how to obtain and log an error traceback from a caught exception.
This question is a repeat, please see the below similar questions which are already answered.
How/When does Execute Shell mark a build as failure in Jenkins?
Jenkins Build Script exits after Google Test execution

How to catch assertion(caused in C++) during runtime in python

I want to embed C++ in python application. I don't want to use Boost library.
If C++ function do assertion, I want to catch it and print error in my python application or get some detailed information like line number in python script that caused error. and main thing is "I want to proceed further in python execution flow"
How can I do it? I can't find any functions to get detailed assertion information in Python API or C++.
C++ Code
void sum(int iA, int iB)
{
assert(iA + iB >10);
}
Python Code
from ctypes import *
mydll = WinDLL("C:\\Users\\cppwrapper.dll")
try:
mydll.sum(10,3)
catch:
print "exception occurred"
# control should go to user whether exceptions occurs, after exception occurs if he provide yes then continue with below or else abort execution, I need help in this part as well
import re
for test_string in ['555-1212', 'ILL-EGAL']:
if re.match(r'^\d{3}-\d{4}$', test_string):
print test_string, 'is a valid US local phone number'
else:
print test_string, 'rejected'
Thanks in advance.
This can't really be done in exactly the way you say, (as was also pointed out in the comments).
Once the assertion happens and SIGABRT is sent to the process, it's in the operating system's hands what will happen, and generally the process will be killed.
The simplest way to recover from a process being killed, is to have the process launched by an external process. Like, a secondary python script, or a shell script. It's easy in bash scripting, for instance, to launch another process, check if it terminates normally or is aborted, log it, and continue.
For instance here's some bash code that executes command line $command, logs the standard error channel to a log file, checks the return code (which will be 130 or something for an SIGABRT) and does something in the various cases:
$command 2> error.log
error_code="$?"
if check_errs $error_code; then
# Do something...
return 0
else
# Do something else...
return 1
fi
Where check_errs is some other subroutine that you would write.

Exit the python function in case of error, and need to pass the exit value to batch file

if ("FATAL_ERROR" == level):
send_mail()
sys.exit()
Can anyone help with the above Exit function, as we have to pass the exit value to the batch file once it receives error?
send mail is the function written in the script, which send the mail to the user when a fatal error occurs...System.error is typing mistake... it's actually sys.exit()...i want whenever "fatal error occurs" it come out and pass the exit value to the batch file...we tried we the sys.exit() but it's not working...pls suggest with some more functions
You can use
sys.exit(1)
to have the Python script end with an error. But, as the sys.exit documentation documentation states, this might not work on Windows (the doc speaks of "shells and the like").
I infer you are using Windows because you speak of "batch files". Maybe you have to do Windows-Batch-File-Magic and rephrase a question fo be about Windows rather then Python then.

IOError Input/Output Error When Printing

I have inherited some code which is periodically (randomly) failing due to an Input/Output error being raised during a call to print. I am trying to determine the cause of the exception being raised (or at least, better understand it) and how to handle it correctly.
When executing the following line of Python (in a 2.6.6 interpreter, running on CentOS 5.5):
print >> sys.stderr, 'Unable to do something: %s' % command
The exception is raised (traceback omitted):
IOError: [Errno 5] Input/output error
For context, this is generally what the larger function is trying to do at the time:
from subprocess import Popen, PIPE
import sys
def run_commands(commands):
for command in commands:
try:
out, err = Popen(command, shell=True, stdout=PIPE, stderr=PIPE).communicate()
print >> sys.stdout, out
if err:
raise Exception('ERROR -- an error occurred when executing this command: %s --- err: %s' % (command, err))
except:
print >> sys.stderr, 'Unable to do something: %s' % command
run_commands(["ls", "echo foo"])
The >> syntax is not particularly familiar to me, it's not something I use often, and I understand that it is perhaps the least preferred way of writing to stderr. However I don't believe the alternatives would fix the underlying problem.
From the documentation I have read, IOError 5 is often misused, and somewhat loosely defined, with different operating systems using it to cover different problems. The best I can see in my case is that the python process is no longer attached to the terminal/pty.
As best I can tell nothing is disconnecting the process from the stdout/stderr streams - the terminal is still open for example, and everything 'appears' to be fine. Could it be caused by the child process terminating in an unclean fashion? What else might be a cause of this problem - or what other steps could I introduce to debug it further?
In terms of handling the exception, I can obviously catch it, but I'm assuming this means I wont be able to print to stdout/stderr for the remainder of execution? Can I reattach to these streams somehow - perhaps by resetting sys.stdout to sys.__stdout__ etc? In this case not being able to write to stdout/stderr is not considered fatal but if it is an indication of something starting to go wrong I'd rather bail early.
I guess ultimately I'm at a bit of a loss as to where to start debugging this one...
I think it has to do with the terminal the process is attached to. I got this error when I run a python process in the background and closed the terminal in which I started it:
$ myprogram.py
Ctrl-Z
$ bg
$ exit
The problem was that I started a not daemonized process in a remote server and logged out (closing the terminal session). A solution was to start a screen/tmux session on the remote server and start the process within this session. Then detaching the session+log out keeps the terminal associated with the process. This works at least in the *nix world.
I had a very similar problem. I had a program that was launching several other programs using the subprocess module. Those subprocesses would then print output to the terminal. What I found was that when I closed the main program, it did not terminate the subprocesses automatically (as I had assumed), rather they kept running. So if I terminated both the main program and then the terminal it had been launched from*, the subprocesses no longer had a terminal attached to their stdout, and would throw an IOError. Hope this helps you.
*NB: it must be done in this order. If you just kill the terminal, (for some reason) that would kill both the main program and the subprocesses.
I just got this error because the directory where I was writing files to ran out of memory. Not sure if this is at all applicable to your situation.
I'm new here, so please forgive if I slip up a bit when it comes to the code detail.
Recently I was able to figure out what cause the I/O error of the print statement when the terminal associated with the run of the python script is closed.
It is because the string to be printed to stdout/stderr is too long. In this case, the "out" string is the culprit.
To fix this problem (without having to keep the terminal open while running the python script), simply read the "out" string line by line, and print line by line, until we reach the end of the "out" string. Something like:
while true:
ln=out.readline()
if not ln: break
print ln.strip("\n") # print without new line
The same problem occurs if you print the entire list of strings out to the screen. Simply print the list one item by one item.
Hope that helps!
The problem is you've closed the stdout pipe which python is attempting to write to when print() is called
This can be caused by running a script in the background using & and then closing the terminal session (ie. closing stdout)
$ python myscript.py &
$ exit
One solution is to set stdout to a file when running in the background
Example
$ python myscript.py > /var/log/myscript.log 2>&1 &
$ exit
No errors on print()
It could happen when your shell crashes while the print was trying to write the data into it.
For my case, I just restart the service, then this issue disappear. don't now why.
My issue was the same OSError Input/Output error, for Odoo.
After I restart the service, it disappeared.

Categories

Resources