除非设置了调试标志,否则隐藏回溯

时间:2014-12-28 07:52:45

标签: python error-handling user-experience

除非设置了详细或调试标志,否则隐藏回溯错误的惯用python方法是什么?

示例代码:

their_md5 = 'c38f03d2b7160f891fc36ec776ca4685'
my_md5 = 'c64e53bbb108a1c65e31eb4d1bb8e3b7' 
if their_md5 != my_md5:
    raise ValueError('md5 sum does not match!')

现在的输出,但仅在使用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!

所需的正常输出:

ValueError: md5 sum does not match!

这是一个测试脚本:https://gist.github.com/maphew/e3a75c147cca98019cd8

4 个答案:

答案 0 :(得分:47)

简短的方法是使用sys模块并使用此命令:

sys.tracebacklimit = 0

使用您的标志来确定行为。

示例:

>>> import sys
>>> sys.tracebacklimit=0
>>> int('a')
ValueError: invalid literal for int() with base 10: 'a'

更好的方法是使用和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

编辑:

如果你仍然需要选择回到原来的钩子:

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)

现在您可以将调试挂钩传递给处理程序,但您很可能希望始终使用sys.excepthook中的调用挂钩(因此debug_hook中不传递任何内容)。 Python在定义时间(常见的陷阱...)中绑定默认参数一次,这使得它在替换之前始终使用相同的原始处理程序。

答案 1 :(得分:3)

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

答案 2 :(得分:0)

使用日志系统来处理错误输出。

我将使用请求连接错误作为示例用例,它生成 3 个异常的级联,每个异常都有很长的回溯。只有最终的错误消息才是真正重要的 - 被调用的服务正在拒绝,我不需要从我的客户端应用程序中知道 3 页的回溯!

  1. 定义自定义错误类
# file: custom_exceptions.py

class Error(Exception):
    """This class should be used where traceback should not be logged"""
    pass
  1. 在内部函数中,捕获异常并将其强制转换为自定义错误类
    try:
        response = requests.get(url, auth=auth, headers=headers, timeout=TIMEOUT)
    except requests.exceptions.ConnectionError as e:
        raise custom_exceptions.Error(e)
  1. 在调用函数中以不同方式处理自定义异常和意外异常
    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()

由此产生的日志消息 - 此错误场景所需的所有详细信息:

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

答案 3 :(得分:-1)

我会邪恶地回答:

<块引用>

不要隐藏回溯

Traceback 是向开发人员显示错误 - 未处理的异常。 delelopers 没有准备,没有注意到的东西。一个字——可憎。

但你是最聪明的人。您会看到有些情况下 md5 sum 不会太多,然后您将结束您的程序。所以也许让我们做精确的:

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

更重要的是 - 你的开发伙伴会很感激 - 他们仍然会有他们的回溯并且永远不会尝试处理这样的异常。 很快 - 如果您不想处理它,则没有理由引发异常。

但是……

如果你真的必须提出异常(所以也许会有一些可以接受的情况,你的开发伙伴想要处理它,例如使用 sha256,或者它只是巨大项目的一小部分),那么你可以这样做:

 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)

     

当然这些都是简化的例子...