有没有办法防止从sys.exit()引发的SystemExit异常被捕获?
-
05-07-2019 - |
题
文档说调用sys.exit()会引发一个SystemExit异常,该异常可以在外层捕获。我有一种情况,我想明确地,毫无疑问地退出测试用例,但是unittest模块捕获SystemExit并阻止退出。这通常很好,但我试图处理的具体情况是我们的测试框架检测到它被配置为指向非测试数据库的情况。在这种情况下,我想退出并阻止任何进一步的测试运行。当然,由于unittest陷入了SystemExit并继续开心,它正在挫败我。
到目前为止我唯一想到的选择是使用ctypes或者类似的东西来直接调用exit(3),但这对于一些非常简单的东西来说似乎是一个非常难看的黑客。
解决方案
您可以致电 os._exit()
直接退出,不抛出异常:
import os
os._exit(1)
这绕过了所有的python关闭逻辑,例如 atexit
模块,并且不会运行您在这种情况下试图避免的异常处理逻辑。参数是流程返回的退出代码。
其他提示
正如Jerub所说, os._exit(1)
是你的答案。但是,考虑到它绕过所有清理程序,包括 finally:
块,关闭文件等,并且应该不惜一切代价避免,我可以提出一个“更安全 - ISH"使用它的方式?
如果问题是 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!
不隶属于 StackOverflow