python exception message capturing - python

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.

Related

How to remove the "Traceback most recent call last" in Python when raising an exception?

I am creating a Python program that requires the use of the OS module, and I would like to custom-report error messages. I am using try and except to accomplish this:
try:
os.mkdir(name)
except FileExistsError:
raise FileExistsError(name + "\n" + " ^ The directory you specified already exists.")
But, I would like to remove the
Traceback (most recent call last):
File "file.py", line 20, in <module>
raise FileExistsError(name + "\n" + " ^ The directory you specified already exists.")
part so that the code that raises this exception is not printed every time that I raise the exception.
How would I go about doing this?
How most command line programs do it is to catch the exception near the top of the program where you interact with the user and print it out in a form that is useful to them:
def makedir(name):
try:
os.mkdir(name)
except FileExistsError:
raise FileExistsError(
name + "\n" + "^ The directory you specified already exists."
)
def main():
try:
makedir("/tmp")
except FileExistsError as e:
print("OOOPS", e)
return
If you catch too broad of an exception class at the top, you will harm your own ability to debug and your user's ability to give you precise error messages, so you should be precise. In fact you might want to invent your own exception classes like this:
class MyAppExceptions(Exception):
pass
class MyAppFileExists(MyAppExceptions):
pass
def makedir(name):
try:
os.mkdir(name)
except FileExistsError:
raise MyAppFileExists(
name + "\n" + "^ The directory you specified already exists."
)
def main():
try:
makedir("/tmp")
except MyAppFileExists as e:
print("OOOPS", e)
return
Then if your program gets a FileExistsError for a reason that you did not anticipate, you will still get an exception traceback that you can use for debugging.
If you want to ignore the full traceback, there is an easy way:
try:
...
except FileExistsError as e:
raise MyAppFileExists('message').with_traceback(None) from None
If you want to remove only the last part, it's a bit harder:
try:
...
except FileExistsError:
try:
raise MyAppFileExists('message')
except MyAppFileExists as e:
tb=e.__traceback__
next_tb=tb
while next_tb.tb_next.tb_next is not None:
next_tb=next_tb.tb_next
next_tb.tb_next=None
raise e.with_traceback(tb) from None
That from None means that Python should not printDuring handling of the above exception, another exception occurred:. If you want this to happpen, just remove the from None Part

Python: When catching a generic (any) exception, how do I store the exception name in a variable?

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)

How many exceptions are possible when reading a json in Python/django?

I have:
MY_PATH_DIR = 'path/to/my/json/file.json'
try:
with open(MY_PATH_DIR, 'r') as f:
MY_PATH_DIR = json.load(f)
except IOError, RuntimeError, ValueError:
pass
except PermissionDenied:
pass
And I want to catch all possible errors. With
IOError - I am catching errors when the file doesn't exist or has a
syntax error (non valid JSON).
RuntimeError - couldn't test it but I think that makes sense from the
documentation in case of an unexpected error
ValueError - I got from here in case nothing got returned
PermissionDenied - is a specific Django error
Are there any other Exceptions that would make sense? I'm not sure if OSError makes sense here. I think that would be raised earlier, right?
The purpose of capturing exceptions is to control the program's behavior when something bad happened, but in an expected way. If you are not even sure what would cause that exception happen, capturing it would only swallow the underlying programming errors you might have.
I wouldn't add as many kinds of exception as possible to that single block of code, you should only add what you care about. To take it to extreme, each line of code would yield certain exceptions but for obvious reason you couldn't do try except for all of them.
Edit:
For the sake of correctness, since you mentioned I don't want my code to break in any case, you could simply do:
try:
# json.load
except Exception as e:
print "Let's just ignore all exceptions, like this one: %s" % str(e)
This is would give you what exception happens as output.
import random
import sys
def main():
"""Demonstrate the handling of various kinds of exceptions."""
# This is like what you are doing in your code.
exceptions = IOError, RuntimeError, ValueError
try:
raise random.choice(exceptions)()
except exceptions as error:
print('Currently handling:', repr(error))
# The following is not much different from Shang Wang's answer.
try:
raise random.choice(exceptions)()
except Exception as error:
print('Currently handling:', repr(error))
# However, the following code will sometimes not handle the exception.
exceptions += SystemExit, KeyboardInterrupt, GeneratorExit
try:
raise random.choice(exceptions)()
except Exception as error:
print('Currently handling:', repr(error))
# The code can be slightly altered to take the new errors into account.
try:
raise random.choice(exceptions)()
except BaseException as error:
print('Currently handling:', repr(error))
# This does not take into account classes not in the exception hierarchy.
class Death:
pass
try:
raise Death()
except BaseException as error:
print('Currently handling:', repr(error))
# If your version of Python does not consider raising an exception from an
# instance of a class not derived from the BaseException class, the way to
# get around this problem would be with the following code instead.
try:
raise Death()
except:
error = sys.exc_info()[1]
print('Currently handling:', repr(error))
if __name__ == '__main__':
main()

Report type/name of unspecified error in `try` statement? python 2

Here is a quick example of what I mean -
try:
something_bad
# This works -
except IndexError as I:
write_to_debug_file('there was an %s' % I)
# How do I do this? -
except as O:
write_to_debug_file('there was an %s' % O)
What is the correct syntax for the second exception?
Thanks in advance :)
except Exception as exc:
Exception is the base class for all "built-in, non-system-exiting exceptions" and should be the base class for user-defined ones as well. except Exception will therefore catch everything except for the few that do not subclass Exception, such as SystemExit, GeneratorExit, KeyboardInterrupt.
You don't have to specify the error type. Just use sys.exc_info() to read out the last exception:
import sys
try:
foobar
except:
print "Unexpected error of type", sys.exc_info()[0].__name__
print "Error message:", sys.exc_info()[1]
Reference: https://docs.python.org/2/tutorial/errors.html#handling-exceptions
As already pointed by Jason, you can use except Exception as O or except BaseException as O if you want to catch all exceptions, including KeyboardInterrupt.
If you need exception's name, you can use name = O.__class__.__name__ or name = type(O).__name__.
Hope this helps

How to handle the EXCEPT message?

I am working with Python.
In my program I am using "try:" and "except:". Inside the "except" I want to send an email telling that some error has occurred and the action could not be executed, but I also like to add which is exactly the error.
Is there any way I can print the error message or use it in a variable?
I hope I made myself clear
Thanks a lot
Python >= 2.6
try:
...
except Exception as e:
print(e)
Python < 2.6
try:
...
except Exception, e:
print(e)
it will print the actuall message.
In Python < 2.6
try:
...
except Exception, e:
print(e)
In Python >= 2.6
try:
...
except Exception as e:
print(e)
This will give you the Exception message.
If you want the full traceback you can use the following:
import traceback
try:
...
except Exception, e:
print traceback.format_exc()

Categories

Resources