currently I have some code like this
try:
somecode
except Exception as Error:
fallbackcode
Now i want to add another fallback to the fallbackcode
Whats is the best practice to make a nested try/catch in python?
try:
somecode
except Exception as Error:
try:
fallbackcode
except Exception as Error:
nextfallbackcode
produces intendation errors
You should be able to do nested try/except blocks exactly how you have it implemented in your question.
Here's another example:
import os
def touch_file(file_to_touch):
"""
This method accepts a file path as a parameter and
returns true/false if it successfully 'touched' the file
:param '/path/to/file/'
:return: True/False
"""
file_touched = True
try:
os.utime(file_to_touch, None)
except EnvironmentError:
try:
open(file_to_touch, 'a').close()
except EnvironmentError:
file_touched = False
return file_touched
You can rewrite the logic using a loop provided all your callbacks and fallbacks have same API interface
for code in [somecode, fallbackcode, nextfallbackcode]:
try:
code(*args, **kwargs)
break
except Exception as Error:
continue
else:
raise HardException
This would be the preferred way instead of multiple level of nested exception blocks.
you can use functions to handle errors :
def func0():
try:
somecode
except:
other_func()
def func1():
try:
somecode
except:
func0()
You could have change it like this:
try:
try:
somecode
except Exception as Error:
fallbackcode
except Exception as Error:
nextfallbackcode
I know I can store an exception name in a variable with this syntax:
try:
code
except TypeError as e:
logger.error(e)
except NameError as e:
logger.error(e)
How do I do the same for the generic except: message? I assume that this (which is the general idea) won't work:
try:
code
except as e:
logger.error(e)
You can you use type(e).__name__ to capture the name of any error you encounter, and access the message as you a normal variable, with e.message. All the built in errors (indexError, TypeError, etc.) are children of the class Exception, so they will be picked up. to save it as a variable named 'err':
try:
code
except Exception as e:
err = type(e).__name__
message = e.message
This will save the error type of any exception of the base python type Exception that you run into, using the built in __name__ variable
BaseException is the broadest type you can catch:
try:
# some code
except BaseException as e:
logger.error(e)
You are able to catch Exception:
import logging
try:
code
except TypeError as e:
logger.error(e)
except NameError as e:
logger.error(e)
except Exception as e:
logging.error(e)
I ran into this with Python 2, where old-style classes aren't caught by except Exception or except BaseException. I solved it by using sys.exc_info to access the current exception:
import sys
try:
code
except:
e = sys.exc_info()[1]
logging.error(e)
This question already has answers here:
Python: Catching specific exception
(3 answers)
Closed 5 years ago.
I'm using a python library in which at one point an exception is defined as follows:
raise Exception("Key empty")
I now want to be able to catch that specific exception, but I'm not sure how to do that.
I tried the following
try:
raise Exception('Key empty')
except Exception('Key empty'):
print 'caught the specific exception'
except Exception:
print 'caught the general exception'
but that just prints out caught the general exception.
Does anybody know how I can catch that specific Key empty exception? All tips are welcome!
Define your exception:
class KeyEmptyException(Exception):
def __init__(self, message='Key Empty'):
# Call the base class constructor with the parameters it needs
super(KeyEmptyException, self).__init__(message)
Use it:
try:
raise KeyEmptyException()
except KeyEmptyException as e:
print e
Update: based on the discussion in comment OP posted:
But the lib is not under my control. It's open source, so I can edit it, but I would preferably try to catch it without editing the library. Is that not possible?
say library raises an exception as
# this try is just for demonstration
try:
try:
# call your library code that can raise `Key empty` Exception
raise Exception('Key empty')
except Exception as e:
# if exception occurs, we will check if its
# `Key empty` and raise our own exception
if str(e) == 'Key empty':
raise KeyEmptyException()
else:
# else raise the same exception
raise e
except Exception as e:
# we will finally check what exception we are getting
print('Caught Exception', e)
you need to subclass Exception:
class EmptyKeyError(Exception):
pass
try:
raise EmptyKeyError('Key empty')
except EmptyKeyError as exc:
print(exc)
except Exception:
print('caught the general exception')
I'm wondering a user defined exception I've raised in my python program from within a class isn't being handled by the correct exception handler within my main(). Say I have a class:
class Pdbalog:
# Constructor
def __init__(self, logtype):
if logtype == 1 or logtype == 2:
# These are valid
self.logtypeV = logtype
...<continue processing>
else:
# Invalid
raise Exception("Invalid Logtype")
My main looks like:
from pdbalog import *
def main():
try:
mylog = Pdbalog(10)
...<other code here>
except "Invalid Logtype":
print('Exiting...')
except:
print('Unhandled exception')
raise
I would expect the when main is run that the line where I instantiate the Pdbalog object would raise an exception (Exception("Invalid Logtype")) and the exception handler in main (except "Invalid Logtype") would print the output string "Exiting...". However, it does not. It is being handled by the unhandled exception handler. What ends up happening is the string "Unhandled exception" is being output. Why isn't the
except "Invalid Logtype":
handling the exception?
I am using an old version of python (2.4).
Exception("Invalid Logtype") is still just an Exception, just now with an error message. "Invalid Logtype" isn't an error, just a str, so you can't catch it.
Try:
class InvalidLogtype(Exception): pass
try:
raise InvalidLogType
except InvalidLogType:
pass
Note that you can catch based on error messages by doing
except Exception, e:
if e.args == ("Invalid Logtype",):
...
else:
raise
Try this instead:
class InvalidLogType(Exception):
pass
then
raise InvalidLogType()
then
except InvalidLogType:
etc
import ftplib
import urllib2
import os
import logging
logger = logging.getLogger('ftpuploader')
hdlr = logging.FileHandler('ftplog.log')
formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s')
hdlr.setFormatter(formatter)
logger.addHandler(hdlr)
logger.setLevel(logging.INFO)
FTPADDR = "some ftp address"
def upload_to_ftp(con, filepath):
try:
f = open(filepath,'rb') # file to send
con.storbinary('STOR '+ filepath, f) # Send the file
f.close() # Close file and FTP
logger.info('File successfully uploaded to '+ FTPADDR)
except, e:
logger.error('Failed to upload to ftp: '+ str(e))
This doesn't seem to work, I get syntax error, what is the proper way of doing this for logging all kind of exceptions to a file
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))
The syntax is no longer supported in python 3. Use the following instead.
try:
do_something()
except BaseException as e:
logger.error('Failed to do something: ' + str(e))
If you want the error class, error message, and stack trace, use sys.exc_info().
Minimal working code with some formatting:
import sys
import traceback
try:
ans = 1/0
except BaseException as ex:
# Get current system exception
ex_type, ex_value, ex_traceback = sys.exc_info()
# Extract unformatter stack traces as tuples
trace_back = traceback.extract_tb(ex_traceback)
# Format stacktrace
stack_trace = list()
for trace in trace_back:
stack_trace.append("File : %s , Line : %d, Func.Name : %s, Message : %s" % (trace[0], trace[1], trace[2], trace[3]))
print("Exception type : %s " % ex_type.__name__)
print("Exception message : %s" %ex_value)
print("Stack trace : %s" %stack_trace)
Which gives the following output:
Exception type : ZeroDivisionError
Exception message : division by zero
Stack trace : ['File : .\\test.py , Line : 5, Func.Name : <module>, Message : ans = 1/0']
The function sys.exc_info() gives you details about the most recent exception. It returns a tuple of (type, value, traceback).
traceback is an instance of traceback object. You can format the trace with the methods provided. More can be found in the traceback documentation .
There are some cases where you can use the e.message or e.messages.. But it does not work in all cases. Anyway the more safe is to use the str(e)
try:
...
except Exception as e:
print(e.message)
Updating this to something simpler for logger (works for both python 2 and 3). You do not need traceback module.
import logging
logger = logging.Logger('catch_all')
def catchEverythingInLog():
try:
... do something ...
except Exception as e:
logger.error(e, exc_info=True)
... exception handling ...
This is now the old way (though still works):
import sys, traceback
def catchEverything():
try:
... some operation(s) ...
except:
exc_type, exc_value, exc_traceback = sys.exc_info()
... exception handling ...
exc_value is the error message.
You can use logger.exception("msg") for logging exception with traceback:
try:
#your code
except Exception as e:
logger.exception('Failed: ' + str(e))
Using str(e) or repr(e) to represent the exception, you won't get the actual stack trace, so it is not helpful to find where the exception is.
After reading other answers and the logging package doc, the following two ways works great to print the actual stack trace for easier debugging:
use logger.debug() with parameter exc_info
try:
# my code
except SomeError as e:
logger.debug(e, exc_info=True)
use logger.exception()
or we can directly use logger.exception() to print the exception.
try:
# my code
except SomeError as e:
logger.exception(e)
After python 3.6, you can use formatted string literal. It's neat! (https://docs.python.org/3/whatsnew/3.6.html#whatsnew36-pep498)
try
...
except Exception as e:
logger.error(f"Failed to upload to ftp: {e}")
You can try specifying the BaseException type explicitly. However, this will only catch derivatives of BaseException. While this includes all implementation-provided exceptions, it is also possibly to raise arbitrary old-style classes.
try:
do_something()
except BaseException, e:
logger.error('Failed to do something: ' + str(e))
If you want to see the original error message, (file & line number)
import traceback
try:
print(3/0)
except Exception as e:
traceback.print_exc()
This will show you the same error message as if you didn't use try-except.
for the future strugglers,
in python 3.8.2(and maybe a few versions before that), the syntax is
except Attribute as e:
print(e)
Use str(ex) to print execption
try:
#your code
except ex:
print(str(ex))
In Python 3, str(ex) gives us the error message. You could use repr(ex) to get the full text, including the name of the exception raised.
arr = ["a", "b", "c"]
try:
print(arr[5])
except IndexError as ex:
print(repr(ex)) # IndexError: list index out of range
print(str(ex)) # list index out of range
There is also a way to get the raw values passed to the exception class without having to change the content type.
For e.g I raise type codes with error messages in one of my frameworks.
try:
# TODO: Your exceptional code here
raise Exception((1, "Your code wants the program to exit"))
except Exception as e:
print("Exception Type:", e.args[0][0], "Message:", e.args[0][1])
Output
Exception Type: 1 Message: 'Your code wants the program to exit'
The easiest way to do this is available through the Polog library. Import it:
$ pip install polog
And use:
from polog import log, config, file_writer
config.add_handlers(file_writer('file.log'))
with log('message').suppress():
do_something()
Note how much less space the code has taken up vertically: only 2 lines.