Jupyter Notebook:发生崩溃时如何重新启动上面的所有单元格?

Jupyter Notebook: How to relaunch all cells above when a crash occurs?

问题 1:

我正在使用带有 python 的 jupyter 4,我需要我的脚本在发生崩溃时重新启动上面的所有单元格

这可能吗?

问题 2:

如果我需要重新启动所有的一些cell,我可以让python根据一些cell-id执行它们吗?然后我可以创建一个单元格 ID 列表,在捕获异常时必须重新执行这些单元格 ID...

我是 运行 Notebook server 5.4.0,我有一个选项 Cell > Run All Above,它似乎正是这样做的。

您始终可以使用 Cell > Run All Above 重新启动活动单元格上方的所有单元格。但是当谈到以编程方式可靠地这样做时,我有好消息也有坏消息要告诉你。


让我们把关于问题 2 的坏消息排除在外:否


...至少不是很可靠,因为如果您插入或删除任何其他单元格,单元格的任何 ID 都会改变。

根据 Execute specific cells through widgets and conditions 在 github 上的说法:

We don't have the Ids of of cell in order to handle them programatically.

再往下 post:

There are some APIs which can run cells identified by numbers, but unfortunately the numbers change if you insert or delete a cell somewhere above.


关于第一个问题的好消息:是


...但不能 100% 确定它会根据您问题中的详细信息解决您的错误处理需求。但我们稍后会谈到这一点。因为好消息是标题中问题的答案

How to relaunch all cells above when a crash occurs?

是的,我们可以!

这个问题的难点(甚至可能是不可能的)部分是将其实现为一种健壮的错误处理方法。如果您只对此感兴趣,请跳至我的回答末尾的 The hard part 部分。现在,让我们继续 easy part,即以编程方式 运行 菜单选项 Cell > Run All(如 Nic Cottrell 的回答中所述) .您有两个选择:

选项1 - 运行上面所有单元格执行一个单元格:

如果您在单元格中插入以下代码段 运行,上面的所有单元格都将被执行:

from IPython.display import Javascript
display(Javascript('IPython.notebook.execute_cells_above()'))

选项 2 - 运行 通过单击按钮上方的所有单元格:

如果您在单元格中插入以下代码片段 运行,当您单击出现的按钮时,上面的所有单元格都将被执行:

片段:

from IPython.core.display import display, HTML
HTML('''<script> </script> <form action="javascript:IPython.notebook.execute_cells_above()"><input type="submit" id="toggleButton" value="Run all"></form>''')

输出:


THE HARD PART

那么,我们如何设置它以在发生崩溃时处理错误?我不是这方面的专家,但我认为我已经能够进行适合您的设置。但这很可能取决于相关错误的类型和您的其余工作流程。

以下示例基于两个不同的错误消息。第一个是 NameError ,当您尝试为不存在的变量赋值时出现。这将很有用,因为 re-running 错误后的某些单元格需要一个迭代器,该迭代器仅在笔记本完全重新启动时才重置,而不是当单元格 re-run 作为错误处理方法的一部分时。只有在重新启动笔记本电脑时重新启动内核时才会出现名称错误。作为错误处理的一部分,值 0 被分配给 x1。当单元格只有re-run时x1会增加1.

第二个错误将作为 您的 错误的代理,并且是每次尝试 delete an element from a list that does not exist。这给我们带来了真正的挑战,因为如果您的错误处理程序 re-run 每次触发错误时都包含上面的所有单元格,您很快就会陷入错误的循环。但是我们将使用一个计数器来处理这个问题,该计数器会在 运行 秒后退出单元格的循环执行。

似乎不​​存在重新运行您的现有单元格的功能也有点问题,或初始化 run cells above 功能的单元格。但我们将使用与之前相同的 github post 的另一个建议来处理该问题:

Doing the following helps me to execute the cell right below the code cell. You can also change the values to get cells in other parts of the notebook. display(Javascript('IPython.notebook.execute_cell_range(IPython.notebook.get_selected_index()+1, IPython.notebook.get_selected_index()+2)'))

建议的笔记本 work-flow:

在下面的四个单元格中插入以下四个片段。单击菜单选项 Cell > Run all 一次,我们就可以开始了!

片段 1 - 导入和设置

import sys
import os
from IPython.core.display import display, HTML
from IPython.display import Javascript
from random import randint

# Trigger to randomly raise en error in the next cell
ErrorTrigger = randint(0, 9)

# Assignment of variables at first run of the Norebook
try: x1
except NameError: x1 = None
if x1 is None:
    %qtconsole # opens a qtconsole (for variable inspection and debugging)
    x1 = 0 # counter for NameError
    x2 = 0 # counter for assignment error (used in cells below)
    mr = 0 # counter for manual relaunch by button 
    
    ErrorTriggers=[] # container for ErroTriggers    
    print('NameErrors = ', x1)
else:
    x1 = x1 + 1
    ErrorTriggers.append(ErrorTrigger)
#print('Executions:', x1, '||', 'Triggers:', ErrorTriggers)

代码段 2 - 错误的代理

# PROXY ERROR => INSERT YOUR CODE FROM HERE ################################################################
list1 = [1,2,3,4]

# 80 % chance of raising an error trying to delete an element that does not exist in the list
if ErrorTrigger > 2:
    elemDelete = 8 # error
else:
    elemDelete = 0 # not error
try:
    del list1[elemDelete]
    print('Executions:', x1, '||', 'Triggers:', ErrorTriggers)
    print('Routine success on attempt', x2 + 1)
    print('Error mesg: None')
    ErrorTriggers=[]
    x2 = 0 # reset error counter
    
# TO HERE #################################################################################################
except Exception:
    
    x2 = x2 + 1
    # Will end error handler after 5 attempts
    if x2 < 3:
        # As long as we're UNDER the attempt limit, the next cell executed by:
        display(Javascript('IPython.notebook.execute_cell_range(IPython.notebook.get_selected_index()+1,'+
                           ' IPython.notebook.get_selected_index()+2)'))
    else:
        # If we're OVER the attempt limit, it all ends here. The next cell is NOT run.
        # And NEITHER is the last cell with the button to relaunch the whole thing.
     
        print('Executions:', x1, '||', 'Triggers:', ErrorTriggers)
        print('Routine aborted after attempt', x2)
        print('Error msg:', sys.exc_info()[1]) # Returns a message describing the error
        # reset variables 
        ErrorTriggers = []
        x2 = 0

代码段 3 - 重新运行 上述所有单元格作为错误处理程序的单元格

display(Javascript('IPython.notebook.execute_cells_above()'))

片段 4 - 重新运行 整个事情的单元格,错误概率为 20%

HTML('''<script> </script> <form action="javascript:IPython.notebook.execute_cells_above()"><input type="submit" id="toggleButton" value="Run again!"></form>''')

几次测试后的截图运行s:

如果片段中的评论不清楚,我很乐意添加更多详细信息。 但是,如果您通过单击 Run Again! 多次 运行 笔记本,同时查看单元格 3 的输出,您将很快掌握整个内容是如何组合在一起的:

这是用于 jupyterlab

  1. 转到:Settings->Advanced Settings Editor->Keyboard Shortcuts

  2. 将下面的代码粘贴到 User Preferences window:

{
    "shortcuts": [
        {
            "command": "notebook:run-all-above",
            "keys": [
        "Shift Backspace"
      ],
      "selector": ".jp-Notebook.jp-mod-editMode"
        }
    ]
}
  1. 点击保存(user-preferences右上window)

这将立即生效。在这里,连续按两次 shift + backspace 会运行所选行上方的所有单元格。 值得注意的是,system defaults 具有所有菜单命令的空模板,包括此代码(搜索 run-all-above)。

在 Jupyter 中,在出错后单击您想要 re-run 的每个单元格,然后转到“查看”>“单元格工具栏”>“标签”。在单元格顶部的框中键入 'raises-exception'(无引号)并添加标签。

在下一个单元格中,输入以下内容:

from IPython.display import Javascript
Javascript("IPython.notebook.execute_all_cells()")

然后 select 单元格 > 运行 全部。

这应该会捕获错误并且 运行 无限循环中的所有单元格,直到被中断。