Reputation: 18084
What is the idiomatic python way to hide traceback errors unless a verbose or debug flag is set?
Example code:
their_md5 = 'c38f03d2b7160f891fc36ec776ca4685'
my_md5 = 'c64e53bbb108a1c65e31eb4d1bb8e3b7'
if their_md5 != my_md5:
raise ValueError('md5 sum does not match!')
Existing output now, but only desired when called with foo.py --debug
:
Traceback (most recent call last):
File "b:\code\apt\apt.py", line 1647, in <module>
__main__.__dict__[command] (packages)
File "b:\code\apt\apt.py", line 399, in md5
raise ValueError('md5 sum does not match!')
ValueError: md5 sum does not match!
Desired normal output:
ValueError: md5 sum does not match!
Here's a test script: https://gist.github.com/maphew/e3a75c147cca98019cd8
Upvotes: 75
Views: 68885
Reputation: 2024
Use the logging system to handle the error output.
I'll use requests connection error as an example use case, it generates a cascade of 3 exceptions each with a lengthy traceback. Only the final error message is of real importance - the called service is refusing, I don't need to know 3 pages of traceback from my client app!
# file: custom_exceptions.py
class Error(Exception):
"""This class should be used where traceback should not be logged"""
pass
try:
response = requests.get(url, auth=auth, headers=headers, timeout=TIMEOUT)
except requests.exceptions.ConnectionError as e:
raise custom_exceptions.Error(e)
except custom_exceptions.Error as e: # any custom error based on the custom Error class
if LOGLEVEL=logging.DEBUG:
logger.exception(e) # with traceback
else:
logger.error(e) # just the exception and message
exit()
except Exception as e:
logger.exception(e) # with traceback
exit()
The resultant log message - all the detail you need for this error scenario:
2021-07-23 10:58:27,545 [ERROR] HTTPConnectionPool(host='localhost', port=8080): Max retries exceeded with url: /next (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7fc54f11f9d0>: Failed to establish a new connection: [Errno 111] Connection refused'))
Upvotes: 1
Reputation: 31339
The short way is using the sys
module and use this command:
sys.tracebacklimit = 0
Use your flag to determine the behaviour.
Example:
>>> import sys
>>> sys.tracebacklimit=0
>>> int('a')
ValueError: invalid literal for int() with base 10: 'a'
The nicer way is to use and exception hook:
def exception_handler(exception_type, exception, traceback):
# All your trace are belong to us!
# your format
print "%s: %s" % (exception_type.__name__, exception)
sys.excepthook = exception_handler
If you still need the option of falling back to the original hook:
def exception_handler(exception_type, exception, traceback, debug_hook=sys.excepthook):
if _your_debug_flag_here:
debug_hook(exception_type, exception, traceback)
else:
print "%s: %s" % (exception_type.__name__, exception)
Now you can pass a debug hook to the handler, but you'll most likely want to always use the one originated in sys.excepthook
(so pass nothing in debug_hook
). Python binds default arguments once in definition time (common pitfall...) which makes this always work with the same original handler, before replaced.
Upvotes: 100
Reputation: 5616
try:
pass # Your code here
except Exception as e:
if debug:
raise # re-raise the exception
# traceback gets printed
else:
print("{}: {}".format(type(e).__name__, e))
Upvotes: 6