web-dev-qa-db-ja.com

sys.exit()から発生したSystemExit例外がキャッチされないようにする方法はありますか?

ドキュメントは、sys.exit()を呼び出すと、外部レベルでキャッチできるSystemExit例外が発生すると述べています。テストケース内から明確かつ間違いなく終了したい状況がありますが、unittestモジュールはSystemExitをキャッチし、終了を防ぎます。これは通常素晴らしいことですが、私が処理しようとしている特定の状況は、テストフレームワークが非テストデータベースを指すように構成されていることを検出した状況です。この場合、終了して、それ以上のテストが実行されないようにします。もちろん、unittestはSystemExitをトラップし、その方法で喜んで続行するので、私を妨害しています。

私がこれまで考えた唯一のオプションは、ctypesまたはexit(3)を直接呼び出すのに似たものを使用することですが、これは本当にシンプルなものに対する非常に厄介なハックのようです。

51
John

os._exit() を呼び出して、例外をスローせずに直接終了できます。

import os
os._exit(1)

これは、atexitモジュールなどのpythonシャットダウンロジックのすべてをバイパスし、この状況で回避しようとしている例外処理ロジックを実行しません。引数は、プロセスによって返される終了コードです。

75
Jerub

Jerubが言ったように、os._exit(1)があなたの答えです。しかし、finally:_ブロック、ファイルのクローズなどを含む all クリーンアップ手順をバイパスすることを考慮し、すべてのコストで実際に回避する必要があります。 「使用方法は?

問題がSystemExitが外部レベル(つまり、unittest)でキャッチされている場合、 be自身が外部レベルになります!メインコードをラップしますtry/exceptブロックでSystemExitをキャッチし、そこでos._exitを呼び出します。 and only there!この方法で、通常_sys.exit_を呼び出すことができますコード内の任意の場所で、最上位にバブルし、すべてのファイルを正常に閉じてすべてのクリーンアップを実行し、 then 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!
_
47
MestreLion