I have an issue trying to catch a Python exception:
File "/usr/lib/python2.7/dist-packages/numpy/lib/nanfunctions.py",
line 427, in nanargmax
raise ValueError("All-NaN slice encountered") ValueError: All-NaN slice encountered
The error appears with this code when effectively the slice contains All-NaN. However, I want to catch that situation and handle it.
with warnings.catch_warnings():
warnings.filterwarnings('error')
try:
action = np.nanargmax(self.Q[state])
except Warning as e:
print "error"
sys.exit(0)
I expect to print the word error, however, the try-except statement is ignored. Any help, please?
You should change except Warning as e to except ValueError as e.
This is because the ValueError class is not a subclass of the Warning class. Alternatively, you could catch any Exception with except Exception as e since all exceptions are a subclass of the Exception class, but best practice is to be as precise as possible with the exceptions that you catch.
Related
If I have that code:
try:
some_method()
except Exception, e:
How can I get this Exception value (string
representation I mean)?
use str
try:
some_method()
except Exception as e:
s = str(e)
Also, most exception classes will have an args attribute. Often, args[0] will be an error message.
It should be noted that just using str will return an empty string if there's no error message whereas using repr as pyfunc recommends will at least display the class of the exception. My take is that if you're printing it out, it's for an end user that doesn't care what the class is and just wants an error message.
It really depends on the class of exception that you are dealing with and how it is instantiated. Did you have something in particular in mind?
Use repr() and The difference between using repr and str
Using repr:
>>> try:
... print(x)
... except Exception as e:
... print(repr(e))
...
NameError("name 'x' is not defined")
Using str:
>>> try:
... print(x)
... except Exception as e:
... print(str(e))
...
name 'x' is not defined
Even though I realise this is an old question, I'd like to suggest using the traceback module to handle output of the exceptions.
Use traceback.print_exc() to print the current exception to standard error, just like it would be printed if it remained uncaught, or traceback.format_exc() to get the same output as a string. You can pass various arguments to either of those functions if you want to limit the output, or redirect the printing to a file-like object.
Another way hasn't been given yet:
try:
1/0
except Exception, e:
print e.message
Output:
integer division or modulo by zero
args[0] might actually not be a message.
str(e) might return the string with surrounding quotes and possibly with the leading u if unicode:
'integer division or modulo by zero'
repr(e) gives the full exception representation which is not probably what you want:
"ZeroDivisionError('integer division or modulo by zero',)"
edit
My bad !!! It seems that BaseException.message has been deprecated from 2.6, finally, it definitely seems that there is still not a standardized way to display exception messages. So I guess the best is to do deal with e.args and str(e) depending on your needs (and possibly e.message if the lib you are using is relying on that mechanism).
For instance, with pygraphviz, e.message is the only way to display correctly the exception, using str(e) will surround the message with u''.
But with MySQLdb, the proper way to retrieve the message is e.args[1]: e.message is empty, and str(e) will display '(ERR_CODE, "ERR_MSG")'
To inspect the error message and do something with it (with Python 3)...
try:
some_method()
except Exception as e:
if {value} in e.args:
{do something}
The following worked for me:
import traceback
try:
some_method()
except Exception as e:
# Python 3.9 or older
print("".join(traceback.format_exception_only(type(e), e)).strip())
# Python 3.10+
print("".join(traceback.format_exception_only(e)).strip())
If some_method() raises the exception ValueError("asdf"), this prints what you see in tracebacks--minus the traceback: ValueError: asdf.
Here is the documentation on this.
For python2, It's better to use e.message to get the exception message, this will avoid possible UnicodeDecodeError. But yes e.message will be empty for some kind of exceptions like OSError, in which case we can add a exc_info=True to our logging function to not miss the error.
For python3, I think it's safe to use str(e).
I have this rather intricate try except block:
try:
self.sorting = sys.argv[1]
try:
test_sorting_var = int(self.sorting)
if test_sorting_var < 1:
print "Sorting column number not valid."
raise ValueError
else:
self.sorting = test_sorting_var
except ValueError:
print "There's a problem with the sorting value provided"
print "Either the column doesn't exists or the column number is invalid"
print "Please try a different sorting value or omit it."
sys.exit(1)
except:
if self.sorting not in self.output_table.column_headers:
print "Sorting column name not valid."
raise ValueError
except:
pass
Basically I'm checking:
If there's a sys.argv[1]
If so, try it as int, and see if it's less than 1
If int fails, test it as string
In both 2+3, if the tests don't succeed, I'm raising a ValueError that should be caught in the except ValueError block and it does as expected:
Sorting column number not valid.
There's a problem with the sorting value provided
Either the column doesn't exists or the column number is invalid
Please try a different sorting value or omit it.
BUT! The sys.exit(1) is not invoked and the program just continues.
How can I fix it and even make it more readable?
In the last two lines you catch any exception:
except:
pass
This includes the exception SystemExit, which is raised by sys.exit.
To fix this, only catch exceptions deriving from Exception, which
SystemExit does not:
except Exception:
pass
In general, it's (almost) never a good idea to do a bare except, always catch Exception, or if possible, something more specific.
The builtint sys.exit() raises a SystemExit-Exception. As you are catching any type of exception when you don't define the Exception to catch (except: without an Exception Type) the SystemExit gets also caught. Ultimately the function will run until the last line where you wrote pass.
Best thing to do is to always catch specific Exceptions and never ever catch all Exceptions with an except:.
Furthermore you should put the check if self.sorting is not in self.output_table.column_headers outside the try catch where you check for a valid self.sorting.
From the documentation for sys.exit:
Exit from Python. This is implemented by raising the SystemExit exception, so cleanup actions specified by finally clauses of try statements are honored, and it is possible to intercept the exit attempt at an outer level.
This means that the outer try except loop is catching the SystemExit exception and causing it to pass. You can add this exception to the outer block and call it again.
I think I would do something like this:
import sys
def MyClass(object):
def method(self, argv, ...):
# ...
if len(argv) < 2:
raise RuntimeError("Usage: {} <sorting column>".format(argv[0]))
sorting = argv[1]
try:
self.sorting = int(sorting)
except ValueError:
try:
self.sorting = self.output_table.column_headers.index(sorting)
except ValueError:
raise ValueError("Invalid sorting column '{}'.".format(sorting))
# ...
try:
# ...
obj.method(sys.argv, ...)
except Exception as e:
sys.exit(e.message)
It's okay to ask for forgiveness instead of permission when it makes things easier (for example to parse a number), but if you need to make sure if sys.argv has enough elements just check it, it will make the program flow clearer.
Avoid using sys.exit within regular code, try to use it only in the outermost levels. For the most part, it is generally better to let exceptions bubble up and catch them at top level or let them crash the program if necessary.
Do make use of exception parameters to store error information, you can decide at a later point whether to print the error, log it, show it in a popup, ...
Instead of using sys.argv directly from within a class, you can pass it as an argument to the method/constructor, it will make the code easier to test and more flexible towards the future.
In Java, getting the message of an exception is as easy as always calling a certain method.
But in Python, it seems to be impossible. Sometimes it works by doing this:
try:
# Code
pass
except Exception as e:
print(e.message)
But sometimes capturing an exception like that ends up by raising another exception because the message attribute doesn't exist. Ironically sad. Trying to control a error produces another one...
Sometimes it works by doing this:
print(e.msg)
But sometimes it also raises missing attribute exception.
Sometimes this works as well:
print(str(e))
But sometimes it prints an empty string so it is simply useless.
I've even heard that it depends on the library you're using, on the concrete Exception implementation. That seems really stupid for me. How can I handle an error for printing what has happened if I never know what attributes does it have for retrieving the error message?
But sometimes it prints an empty string so it is simply useless.
Yeah, that's what happens when someone raises an exception without a message. Blame authors (of the lib you are using) for that.
Generally you can use repr which is supposed to be unambiguous and if not overriden contains at least information about the exception's type:
try:
0/0
except Exception as exc:
print(repr(exc))
raise
If you need whole traceback you can use
import traceback
try:
0/0
except Exception:
print(traceback.format_exc())
raise
Is there a function in Python, e.g. get_exception, so I can do this:
try:
can_raise_anything()
except:
ex = *get_exception()*
print('caught something: ' + str(ex))
I know in Python 3, I should use except BaseException as ex: to do the task. I'm just curious to see if there is a function can do that.
except BaseException as e also works in Python 2.
If you really want to use a function for some reason, sys.exc_info() will return a tuple whose second element is the exception object. (The first element is the exception type, and the third element is the traceback.)
The except block can receive an additional part which looks like this:
try:
stuff()
except Exception as e:
print e
Some libraries (including builtin ones) provide specific Exception types, which can be used for reacting better depending to the type of error found. Combining this with the fact you can have as many except blocks for one try block, you can make a very fail-safe app. Example of a complex try-except block:
try:
result = a / b
except TypeError as e:
print "Woops! a and b must be numbers!"
result = int(a) / int(b)
print e
except NameError as e:
print "A variable used doesn't exist!"
print e
except ArithmeticError as e:
print "It seems you've gone past infinity, under atomicity or divided by zero!"
print e
except Exception as e:
print "Something REALLY unexpected happened!"
print e
Built-in exceptions used in the example:
TypeError: When the type of a variable is unexpected (e.g adding strings and numbers)
NameError: A variable used is not existant
ArithmeticError: General math error
Exception: Any kind of error, can be used for simple excepts or just for "everything else"
A list of built-in exceptions and their descriptions for Python 2.x can be found at http://docs.python.org/2/library/exceptions.html.
Note: Usually custom libraries have comments describing the custom exceptions they raise.
This question already has answers here:
Manually raising (throwing) an exception in Python
(11 answers)
Closed 4 years ago.
I have read the official definition of "raise", but I still don't quite understand what it does.
In simplest terms, what is "raise"?
Example usage would help.
It has two purposes.
jackcogdill has given the first one:
It's used for raising your own errors.
if something:
raise Exception('My error!')
The second is to reraise the current exception in an exception handler, so that it can be handled further up the call stack.
try:
generate_exception()
except SomeException as e:
if not can_handle(e):
raise
handle_exception(e)
raise without any arguments is a special use of python syntax. It means get the exception and re-raise it. If this usage it could have been called reraise.
raise
From The Python Language Reference:
If no expressions are present, raise re-raises the last exception that
was active in the current scope.
If raise is used alone without any argument is strictly used for reraise-ing. If done in the situation that is not at a reraise of another exception, the following error is shown:
RuntimeError: No active exception to reraise
It's used for raising errors.
if something:
raise Exception('My error!')
Some examples here
Besides raise Exception("message") and raise Python 3 introduced a new form, raise Exception("message") from e. It's called exception chaining, it allows you to preserve the original exception (the root cause) with its traceback.
It's very similar to inner exceptions from C#.
More info:
https://www.python.org/dev/peps/pep-3134/
You can use it to raise errors as part of error-checking:
if (a < b):
raise ValueError()
Or handle some errors, and then pass them on as part of error-handling:
try:
f = open('file.txt', 'r')
except IOError:
# do some processing here
# and then pass the error on
raise
raise causes an exception to be raised. Some other languages use the verb 'throw' instead.
It's intended to signal an error situation; it flags that the situation is exceptional to the normal flow.
Raised exceptions can be caught again by code 'upstream' (a surrounding block, or a function earlier on the stack) to handle it, using a try, except combination.