web-dev-qa-db-ja.com

ノートブックの例外を処理するJupyterマジック

私のJupyter Notebooksには、長時間実行される実験がいくつかあります。いつ終了するかわからないので、ノートブックの最後のセルに電子メール機能を追加し、ノートブックが完了すると自動的に電子メールを受け取ります。

しかし、セルの1つにランダムな例外があると、ノートブック全体が実行を停止し、メールが届きません。 例外が発生した場合やカーネルが停止した場合に関数を実行できる魔法の関数があるかどうか疑問に思っています。

お気に入り

def handle_exception(stacktrace):
    send_mail_to_myself(stacktrace)


%%in_case_of_notebook_exception handle_exception # <--- this is what I'm looking for

他のオプションは、すべてのセルをtry-catchでカプセル化することですよね?しかし、それはとても面倒です。

提案を事前に感謝します。

18
Florian Golemo

そのような魔法のコマンドは存在しませんが、自分で書くことができます。

from IPython.core.magic import register_cell_magic

@register_cell_magic('handle')
def handle(line, cell):
    try:
        exec(cell)
    except Exception as e:
        send_mail_to_myself(e)
        raise # if you want the full trace-back in the notebook

ノートブック全体のマジックコマンドを自動的にロードすることはできません。この機能を必要とする各セルに追加する必要があります。

%%handle

some_code()
raise ValueError('this exception will be caught by the magic command')
18
show0k

@ show0kは(魔法の方法に関して)私の質問に正しい答えを出しました。どうもありがとう! :)

その答えが私を少し深く掘り下げるきっかけとなり、ノートブック全体のカスタム例外ハンドラーを定義できるIPythonメソッドに出くわしました。

私はそれを次のように機能させました:

from IPython.core.ultratb import AutoFormattedTB

# initialize the formatter for making the tracebacks into strings
itb = AutoFormattedTB(mode = 'Plain', tb_offset = 1)

# this function will be called on exceptions in any cell
def custom_exc(Shell, etype, evalue, tb, tb_offset=None):

    # still show the error within the notebook, don't just swallow it
    Shell.showtraceback((etype, evalue, tb), tb_offset=tb_offset)

    # grab the traceback and make it into a list of strings
    stb = itb.structured_traceback(etype, evalue, tb)
    sstb = itb.stb2text(stb)

    print (sstb) # <--- this is the variable with the traceback string
    print ("sending mail")
    send_mail_to_myself(sstb)

# this registers a custom exception handler for the whole current notebook
get_ipython().set_custom_exc((Exception,), custom_exc)

したがって、これはノートブックの上部にある単一のセルに配置でき、その結果、何か問題が発生した場合にメールを送信します。

自己/ TODOへの注意:このスニペットを小さなpythonモジュールにしてください。これは、ノートブックにインポートして、ラインマジックでアクティブ化できます。

注意してください。ドキュメントには、この警告が含まれていますset_custom_excメソッド:「警告:独自の例外ハンドラーをIPythonのメイン実行ループに配置することで、厄介なクラッシュが発生する可能性が非常に高くなります。この機能は、何をしているのか本当にわかっている場合にのみ使用してください。」

13
Florian Golemo

セルにtry..exceptステートメントを使用しないですぐに使用できる方法はないと思います。 AFAIK 4歳の問題 はこれについて言及していますが、まだオープンな状態です。

ただし、 runtools extension でうまくいく場合があります。

2
dashdashzako

なぜexecが常に解決策とは限らないのか

それは数年後のことであり、Jupyterマジックでエラーを処理しようとする同様の問題がありました。ただし、実際のJupyterノートブックで永続化する変数が必要でした。

%%try_except print
a = 12
raise ValueError('test')

この例では、エラーを印刷したい(ただし、オープニングポストの電子メールなど)が、a == 12は、次のセルで真になります。そのため、別のファイルでマジックを定義する場合、推奨されるメソッドexecは機能しません。私が見つけた解決策は、IPython機能を使用することです。

解決方法

from IPython.core.magic import line_magic, cell_magic, line_cell_magic, Magics, magics_class


@magics_class
class CustomMagics(Magics):
    @cell_magic
    def try_except(self, line, cell):
        """ This magic wraps a cell in try_except functionality """  
        try:
            self.Shell.ex(cell)  # This executes the cell in the current namespace
        except Exception as e:
            if ip.ev(f'callable({how})'):  # check we have a callable handler
                self.Shell.user_ns['error'] = e  # add error to namespace
                ip.ev(f'{how}(error)')  # call the handler with the error
            else:
                raise e


# Register
from IPython import get_ipython
ip = get_ipython()
ip.register_magics(CustomMagics)
1
Roelant