有没有办法防止从sys.exit()引发的SystemExit异常被捕获?

问题描述 投票:50回答:2

文档说调用sys.exit()会引发一个SystemExit异常,该异常可以在外层捕获。我有一种情况,我想明确地,毫无疑问地退出测试用例,但是unittest模块捕获SystemExit并阻止退出。这通常很好,但我试图处理的具体情况是我们的测试框架检测到它被配置为指向非测试数据库的情况。在这种情况下,我想退出并阻止任何进一步的测试运行。当然,由于unittest陷入了SystemExit的困境并继续开心,它正在挫败我。

到目前为止我唯一想到的选择是使用ctypes或者类似的东西来直接调用exit(3),但这对于一些非常简单的东西来说似乎是一个相当糟糕的黑客。

python exception exit systemexit
2个回答
70
投票

您可以调用os._exit()直接退出,而不会抛出异常:

import os
os._exit(1)

这绕过了所有的python关闭逻辑,例如atexit模块,并且不会运行您在这种情况下试图避免的异常处理逻辑。参数是进程返回的退出代码。


46
投票

正如Jerub所说,os._exit(1)是你的答案。但是,考虑到它绕过所有清理程序,包括finally:块,关闭文件等,并且应该不惜一切代价避免,我可以提出一种“更安全”的方式来使用它吗?

如果你的问题是SystemExit被捕获在外层(即unittest),那么你自己就是外层!将主代码包装在try / except块中,捕获SystemExit,然后在那里调用os._exit,只在那里!这样你就可以在代码中的任何地方调用sys.exit,让它冒泡到顶层,优雅地关闭所有文件并运行所有清理,然后调用os._exit。

您甚至可以选择哪些出口是“紧急”出口。下面的代码是这种方法的一个例子:

import sys, os

EMERGENCY = 255  # can be any number actually

try:
    # wrap your whole code here ...
    # ... some code
    if x: sys.exit()
    # ... some more code
    if y: sys.exit(EMERGENCY)  # use only for emergency exits
    # ...
except SystemExit as e:
    if e.code != EMERGENCY:
        raise  # normal exit, let unittest catch it
    else:
        os._exit(EMERGENCY)  # try to stop *that*, sucker!
© www.soinside.com 2019 - 2024. All rights reserved.