Hide traceback unless a debug flag is set

Python Programming

Question or problem about Python programming:

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 
    __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

How to solve the problem:

Solution 1:

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
Edit:

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.

Solution 2:

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))

Solution 3:

I’ll answer wickedly:


Don’t hide tracebacks

Traceback is to show developer an error – unhandled exception. Something that delelopers didn’t prepare, didn’t notice. In one word – abomination.

But you are the clever one. You see that there are cases when md5 sum will not much, and than you shall end your program. So maybe let’s do exaclty that:

if their_md5 != my_md5:
  sys.stderr.write('md5 sum does not match!')
  exit(-1)

What is more – your fellow devs would be thankfull – they will still have their tracebacks and will never try to handle such exception.
Shortly – there is no reason to raise exception if you don’t want to handle it.

But…

if you really have to raise exception (so maybe there will be some cases that would be acceptable, and your fellow dev would like to handle it, e.g. with sha256, or it would be small part of gigantic project) than you can do this:

 def do_sth_with_md5(their_md5, my_md5):
     if their_md5 != my_md5:
         raise ValueError('md5 sum does not match!')
     actual_staff_to_do(their_md5, my_md5)
    (...)

 ... somewhere else ...
 try:
     do_sth_with_md5(their, my)
 except ValueError:
     sys.stderr.write('md5 sum does not match!') #or sha256handling... whatever
     exit(-1)

     

Of course those are simplified examples…

Hope this helps!