263

How can I get the name of an exception that was raised in Python?

e.g.,

try: foo = bar except Exception as exception: name_of_exception = ??? assert name_of_exception == 'NameError' print "Failed with exception [%s]" % name_of_exception 

For example, I am catching multiple (or all) exceptions, and want to print the name of the exception in an error message.

5
  • 3
    Why do you think you need this? Why not catch a more concrete exception (e.g. except NameError:) to begin with? Commented Aug 11, 2013 at 21:07
  • 17
    I have a couple scenarios where I want to catch all exceptions (or a list of them), and want to print out the name of the exception in an error message. Commented Aug 12, 2013 at 7:04
  • 2
    You might want to check out the standard library's traceback module, which has functions that do some nice formatting of exceptions and tracebacks. Commented May 22, 2014 at 23:16
  • 1
    @delnan this situation arises when you are testing if a function is raising an exception as programmed Commented Mar 14, 2016 at 15:32
  • I needed something like this to DRY up some code: several exceptions can be raised by the method I'm calling, each are handled with their own except statement, but the log entry is very similar in each case. Commented Oct 12, 2017 at 16:01

9 Answers 9

414

Here are a few different ways to get the name of the class of the exception:

  1. type(exception).__name__
  2. exception.__class__.__name__
  3. 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' 
Sign up to request clarification or add additional context in comments.

2 Comments

when you raise raise socket.timeout you only get the name: timeout
Is there a way to get the traceback(most recent call last) : ... ?
29

If you want the fully qualified class name (e.g. sqlalchemy.exc.IntegrityError instead of just IntegrityError), you can use the function below, which I took from MB's awesome answer to another question (I just renamed some variables to suit my tastes):

def get_full_class_name(obj): module = obj.__class__.__module__ if module is None or module == str.__class__.__module__: return obj.__class__.__name__ return module + '.' + obj.__class__.__name__ 

Example:

try: # <do something with sqlalchemy that angers the database> except sqlalchemy.exc.SQLAlchemyError as e: print(get_full_class_name(e)) # sqlalchemy.exc.IntegrityError 

Comments

25

You can print the exception using some formated strings:

Example:

try: #Code to execute except Exception as err: print(f"{type(err).__name__} was raised: {err}") 

Comments

12

You can also use sys.exc_info(). exc_info() returns 3 values: type, value, traceback. On documentation: https://docs.python.org/3/library/sys.html#sys.exc_info

import sys try: foo = bar except Exception: exc_type, value, traceback = sys.exc_info() assert exc_type.__name__ == 'NameError' print "Failed with exception [%s]" % exc_type.__name__ 

Comments

7

This works, but it seems like there must be an easier, more direct way?

try: foo = bar except Exception as exception: assert repr(exception) == '''NameError("name 'bar' is not defined",)''' name = repr(exception).split('(')[0] assert name == 'NameError' 

2 Comments

Replace except Exception as exception with the type of exception you'd like to catch, i.e. except NameError as exception.
I don't want to catch particular exceptions known in advance. I want to catch all exceptions.
2

When you say "name" this could mean a couple of things: it could mean only the "immediate" classname, or it could mean the fully qualified name. Usually the latter will be much more useful and less error-prone: I've come across more than one case of 2 or more types with same "immediate" classname but from different packages.

If you want to print or log the fully qualified name this is one of the simplest things to do:

try: do_something() except BaseException as e: logger.error(f'whoops! {type(e)}: {e}') # or maybe print(f'whoops! {type(e)}: {e}', file=sys.stderr) 

The fully qualified classname will then be printed out like this: "<class 'json.decoder.JSONDecodeError'>", and then be followed by the exception message. The OP says he wants "for example", to print a message, so assert statements as in the chosen answer don't seem to be called for.

The answer by MrName is also not irrelevant, and does make a sensible suggestion! if in the above you replaced logger.error(...) with logger.exception('whoops!') (NB a user message is a required param) you'd get your exception's fully qualified name logged, not to mention its message, and a stack trace for free.

PS as suggested by the name, JSONDecodeError in my example is an Error, not an Exception (it is a subclass of ValueError). Catching BaseException (the superclass of both Error and Exception) usually makes life easier when you're not fishing for a specific exception. The OP says he wants to catch "all" exceptions.

Comments

0

Even more comparison

class MyCustomError(Exception): pass try: assert False, MyCustomError("Can be very long message, printing it will be a bad idea in most cases") except Exception as e: print(" raising by `assert` ".center(80, "-")) print(f"{sys.exc_info()=}") print(f"{e=}\n{e.__class__=}\n{e.__class__.__name__=}\n{e.__class__.__qualname__=}\n{e.args=}\n{type(e)}") print() try: raise MyCustomError("Can be very long message, printing it will be a bad idea in most cases") except Exception as e: print(" raising by `raise` ".center(80, "-")) print(f"{sys.exc_info()=}") print(f"{e=}\n{e.__class__=}\n{e.__class__.__name__=}\n{e.__class__.__qualname__=}\n{e.args=}\n{type(e)}") 
----------------------------- raising by `assert` ------------------------------ sys.exc_info()=(<class 'AssertionError'>, AssertionError(MyCustomError('Can be very long message, printing it will be a bad idea in most cases')), <traceback object at 0x7f8ed84fe380>) e=AssertionError(MyCustomError('Can be very long message, printing it will be a bad idea in most cases')) e.__class__=<class 'AssertionError'> e.__class__.__name__='AssertionError' e.__class__.__qualname__='AssertionError' e.args=(MyCustomError('Can be very long message, printing it will be a bad idea in most cases'),) <class 'AssertionError'> ------------------------------ raising by `raise` ------------------------------ sys.exc_info()=(<class '__main__.MyCustomError'>, MyCustomError('Can be very long message, printing it will be a bad idea in most cases'), <traceback object at 0x7f8ed84fe380>) e=MyCustomError('Can be very long message, printing it will be a bad idea in most cases') e.__class__=<class '__main__.MyCustomError'> e.__class__.__name__='MyCustomError' e.__class__.__qualname__='MyCustomError' e.args=('Can be very long message, printing it will be a bad idea in most cases',) <class '__main__.MyCustomError'> 

1 Comment

I don't see any new ways of getting the exception name here that haven't already been seen in the other answers. Am I missing something @jedrix?
0

For a human readable error description you may also find "_doc_" helpful, this is the docstring for the connection class.

try: foo = bar except Exception as exception: print(exception.__doc__) 

Example output:
A connection error has occurred.

Comments

-1

The other answers here are great for exploration purposes, but if the primary goal is to log the exception (including the name of the exception), perhaps consider using logging.exception instead of print?

logging.exception(msg, *args, **kwargs)

Logs a message with level ERROR on the root logger. The arguments and behavior are otherwise the same as for debug(). Exception info is added to the logging message. This function should only be called from an exception handler.

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.