How to get exception message in Python properly
If you look at the documentation for the built-in errors, you'll see that most Exception
classes assign their first argument as a message
attribute. Not all of them do though.
Notably,EnvironmentError
(with subclasses IOError
and OSError
) has a first argument of errno
, second of strerror
. There is no message
... strerror
is roughly analogous to what would normally be a message
.
More generally, subclasses of Exception
can do whatever they want. They may or may not have a message
attribute. Future built-in Exception
s may not have a message
attribute. Any Exception
subclass imported from third-party libraries or user code may not have a message
attribute.
I think the proper way of handling this is to identify the specific Exception
subclasses you want to catch, and then catch only those instead of everything with an except Exception
, then utilize whatever attributes that specific subclass defines however you want.
If you must print
something, I think that printing the caught Exception
itself is most likely to do what you want, whether it has a message
attribute or not.
You could also check for the message attribute if you wanted, like this, but I wouldn't really suggest it as it just seems messy:
try:
pass
except Exception as e:
# Just print(e) is cleaner and more likely what you want,
# but if you insist on printing message specifically whenever possible...
if hasattr(e, 'message'):
print(e.message)
else:
print(e)
How do I print an exception in Python?
For Python 2.6 and later and Python 3.x:
except Exception as e: print(e)
For Python 2.5 and earlier, use:
except Exception,e: print str(e)
python exception message capturing
You have to define which type of exception you want to catch. So write except Exception, e:
instead of except, e:
for a general exception (that will be logged anyway).
Other possibility is to write your whole try/except code this way:
try:
with open(filepath,'rb') as f:
con.storbinary('STOR '+ filepath, f)
logger.info('File successfully uploaded to '+ FTPADDR)
except Exception, e: # work on python 2.x
logger.error('Failed to upload to ftp: '+ str(e))
in Python 3.x and modern versions of Python 2.x use except Exception as e
instead of except Exception, e
:
try:
with open(filepath,'rb') as f:
con.storbinary('STOR '+ filepath, f)
logger.info('File successfully uploaded to '+ FTPADDR)
except Exception as e: # work on python 3.x
logger.error('Failed to upload to ftp: '+ str(e))
How do I log a Python error with debug information?
logger.exception
will output a stack trace alongside the error message.
For example:
import logging
try:
1/0
except ZeroDivisionError:
logging.exception("message")
Output:
ERROR:root:message
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
ZeroDivisionError: integer division or modulo by zero
@Paulo Cheque notes, "be aware that in Python 3 you must call the logging.exception
method just inside the except
part. If you call this method in an arbitrary place you may get a bizarre exception. The docs alert about that."
When I catch an exception, how do I get the type, file, and line number?
import sys, os
try:
raise NotImplementedError("No error")
except Exception as e:
exc_type, exc_obj, exc_tb = sys.exc_info()
fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
print(exc_type, fname, exc_tb.tb_lineno)
How to print an exception in Python 3?
I'm guessing that you need to assign the Exception
to a variable. As shown in the Python 3 tutorial:
def fails():
x = 1 / 0
try:
fails()
except Exception as ex:
print(ex)
To give a brief explanation, as
is a pseudo-assignment keyword used in certain compound statements to assign or alias the preceding statement to a variable.
In this case, as
assigns the caught exception to a variable allowing for information about the exception to stored and used later, instead of needing to be dealt with immediately.
(This is discussed in detail in the Python 3 Language Reference: The try
Statement.)
There are other compound statements that use as
. The first is the with
statement:
@contextmanager
def opening(filename):
f = open(filename)
try:
yield f
finally:
f.close()
with opening(filename) as f:
# ...read data from f...
Here, with
statements are used to wrap the execution of a block with methods defined by context managers. This functions like an extended try...except...finally
statement in a neat generator package, and the as
statement assigns the generator-produced result from the context manager to a variable for extended use.
(This is discussed in detail in the Python 3 Language Reference: The with
Statement.)
As of Python 3.10, match
statements also use as
:
from random import randint
match randint(0, 2):
case 0|1 as low:
print(f"{low} is a low number")
case _:
print("not a low number")
match
statements take an expression (in this case, randint(0, 2)
) and compare its value to each case
branch one at a time until one of them succeeds, at which point it executes that branch's block. In a case
branch, as
can be used to assign the value of the branch to a variable if that branch succeeds. If it doesn't succeed, it is not bound.
(The match
statement is covered by the tutorial and discussed in detail in the Python 3 Language Reference: match
Statements.)
Finally, as
can be used when importing modules, to alias a module to a different (usually shorter) name:
import foo.bar.baz as fbb
This is discussed in detail in the Python 3 Language Reference: The import
Statement.
Proper way to declare custom exceptions in modern Python?
Maybe I missed the question, but why not:
class MyException(Exception):
pass
To override something (or pass extra args), do this:
class ValidationError(Exception):
def __init__(self, message, errors):
# Call the base class constructor with the parameters it needs
super().__init__(message)
# Now for your custom code...
self.errors = errors
That way you could pass dict of error messages to the second param, and get to it later with e.errors
.
In Python 2, you have to use this slightly more complex form of super()
:
super(ValidationError, self).__init__(message)
How to get the name of an exception that was caught in Python?
Here are a few different ways to get the name of the class of the exception:
type(exception).__name__
exception.__class__.__name__
exception.__class__.__qualname__
e.g.,
try:
foo = bar
except Exception as exception:
assert type(exception).__name__ == 'NameError'
assert exception.__class__.__name__ == 'NameError'
assert exception.__class__.__qualname__ == 'NameError'
How do I determine what type of exception occurred?
The other answers all point out that you should not catch generic exceptions, but no one seems to want to tell you why, which is essential to understanding when you can break the "rule". Here is an explanation. Basically, it's so that you don't hide:
- the fact that an error occurred
- the specifics of the error that occurred (error hiding antipattern)
So as long as you take care to do none of those things, it's OK to catch the generic exception. For instance, you could provide information about the exception to the user another way, like:
- Present exceptions as dialogs in a GUI
- Transfer exceptions from a worker thread or process to the controlling thread or process in a multithreading or multiprocessing application
So how to catch the generic exception? There are several ways. If you just want the exception object, do it like this:
try:
someFunction()
except Exception as ex:
template = "An exception of type {0} occurred. Arguments:\n{1!r}"
message = template.format(type(ex).__name__, ex.args)
print message
Make sure message
is brought to the attention of the user in a hard-to-miss way! Printing it, as shown above, may not be enough if the message is buried in lots of other messages. Failing to get the users attention is tantamount to swallowing all exceptions, and if there's one impression you should have come away with after reading the answers on this page, it's that this is not a good thing. Ending the except block with a raise
statement will remedy the problem by transparently reraising the exception that was caught.
The difference between the above and using just except:
without any argument is twofold:
- A bare
except:
doesn't give you the exception object to inspect - The exceptions
SystemExit
,KeyboardInterrupt
andGeneratorExit
aren't caught by the above code, which is generally what you want. See the exception hierarchy.
If you also want the same stacktrace you get if you do not catch the exception, you can get that like this (still inside the except clause):
import traceback
print traceback.format_exc()
If you use the logging
module, you can print the exception to the log (along with a message) like this:
import logging
log = logging.getLogger()
log.exception("Message for you, sir!")
If you want to dig deeper and examine the stack, look at variables etc., use the post_mortem
function of the pdb
module inside the except block:
import pdb
pdb.post_mortem()
I've found this last method to be invaluable when hunting down bugs.
Related Topics
Putting Many Python Pandas Dataframes to One Excel Worksheet
Get Inserted Key Before Commit Session
Python: Fastest Way to Create a List of N Lists
Convert a List of Tuples to a List of Lists
How to One Hot Encode Variant Length Features
Using Monotonically_Increasing_Id() for Assigning Row Number to Pyspark Dataframe
Class Variables Is Shared Across All Instances in Python
Fastest Way to Search a List in Python
How to Access the Type Arguments of Typing.Generic
Difference Between Data and JSON Parameters in Python Requests Package
Use Scipy.Integrate.Quad to Integrate Complex Numbers
Fitting a Normal Distribution to 1D Data
Overriding Properties in Python
Checking Odd/Even Numbers and Changing Outputs on Number Size