在版本控制下使用IPython笔记本

在版本控制下保持IPython笔记本的好策略是什么?

笔记本电脑格式非常适合版本控制:如果想要版本控制笔记本电脑和输出,那么这种方式效果很好。 当人们只想控制输入的版本,排除单元格输出(也就是“构建产品”),这可能是一个大的二进制blob,特别是对于电影和剧情,这种烦恼就出现了。 特别是,我试图找到一个好的工作流程:

  • 允许我选择包括或不包括输出,
  • 如果我不想要它,可以防止我意外地提交输出,
  • 允许我在本地版本中保留输出,
  • 允许我使用版本控制系统查看输入更改的时间(例如,如果我只是版本控制输入,但是本地文件有输出,那么我希望能够看到输入是否已更改(需要提交)。使用版本控制状态命令将始终注册一个差异,因为本地文件具有输出。)
  • 允许我从更新的清洁笔记本更新我的工作笔记本(其中包含输出)。 (更新)
  • 如前所述,如果我选择包含输出(例如在使用nbviewer时需要),那么一切都很好。 问题是我不想版本控制输出。 有一些工具和脚本用于剥离笔记本的输出,但我经常遇到以下问题:

  • 我意外地用输出提交了一个版本,从而污染了我的仓库。
  • 我清除输出以使用版本控制,但真的宁愿将输出保留在本地副本中(有时需要一段时间才能重现)。
  • Cell/All Output/Clear菜单选项相比,某些剥离输出的脚本会略微改变格式,从而在差异中产生不必要的噪音。 这是通过一些答案解决的。
  • 将更改提供给文件的干净版本时,我需要找到某种方法将这些更改合并到我的工作笔记本中,而无需重新运行所有内容。 (更新)
  • 我已经考虑了几个我将在下面讨论的选项,但还没有找到一个好的综合解决方案。 完整的解决方案可能需要对IPython进行一些更改,或者可能依赖于一些简单的外部脚本。 我目前使用的是mercurial,但想要一个也适用于git的解决方案:理想的解决方案是版本控制不可知的。

    这个问题已经被多次讨论过,但从用户的角度来看,并没有明确或明确的解决方案。 这个问题的答案应该提供明确的策略。 如果它需要最新(甚至是开发)版本的IPython或易于安装的扩展,那就好了。

    更新:我一直在玩我的修改版笔记本,其任选节省了.clean版本,每次保存使用格雷戈里Crosswhite的建议。 这满足了我的大部分约束条件,但留下了以下问题:

  • 这还不是一个标准的解决方案(需要修改ipython源代码。是否有一种方法可以通过简单的扩展来实现这种行为?需要某种形式的保存钩子。
  • 我对当前工作流程的一个问题是拉动变化。 这些将进入.clean文件,然后需要以某种方式集成到我的工作版本中。 (当然,我总是可以重新执行笔记本,但这可能会很痛苦,特别是如果某些结果取决于长计算,并行计算等)。我对如何解决这个问题还没有一个好主意。 也许像ipycache这样的扩展工作流可能会起作用,但这似乎有些复杂。
  • 笔记

    删除(剥离)输出

  • 当笔记本运行时,可以使用Cell/All Output/Clear菜单选项来删除输出。
  • 有一些用于删除输出的脚本,例如脚本nbstripout.py可以删除输出,但不会产生与使用笔记本界面相同的输出。 这最终被包含在ipython / nbconvert回购中,但是这已经被封闭,声称这些改变现在包含在ipython / ipython中,但是相应的功能似乎尚未包含在内。 (更新)这就是说,Gregory Crosswhite的解决方案表明,即使不调用ipython / nbconvert也很容易做到,因此,如果可以正确挂接,这种方法可能可行。(将其附加到每个版本控制系统上,似乎不是一个好主意 - 这应该以某种方式与笔记本机制挂钩。)
  • 新闻组

  • 关于版本控制笔记本格式的思考。
  • 问题

  • 977:笔记本功能请求(打开)。
  • 1280:清除所有保存选项(打开)。 (从这个讨论开始。)
  • 3295:自动导出的笔记本电脑:只导出明确标记的单元格(关闭)。 通过扩展解决11添加writeandexecute magic(合并)。
  • 拉取请求

  • 1621:清除“清除所有输出”(合并)中的[]提示号码。 (另见2519(合并))。
  • 1563:clear_output改进(合并)。
  • 3065:笔记本电脑的差异性(关闭)。
  • 3291:添加选项以在保存时跳过输出单元格。 (关闭)。 这看起来非常相关,但是关于使用“干净/污迹”过滤器的建议关闭了。 一个相关的问题如果你想在运行git diff之前剥离输出,你可以使用什么? 似乎没有得到回答。
  • 3312:WIP:笔记本保存挂钩(已关闭)。
  • 3747:ipynb - > ipynb变压器(闭合)。 这是重新在4175年。
  • 4175:nbconvert:Jinjaless出口商基地(合并)。
  • 142:如果没有输入(打开),则在nbstripout中使用STDIN。

  • 这是我用git的解决方案。 它允许你像平常一样添加和提交(和差异):这些操作不会改变你的工作树,并且同时(重新)运行笔记本不会改变你的git历史记录。

    尽管这可能适用于其他VCS,但我知道它不能满足您的要求(至少VSC不可知论)。 尽管这对我来说是完美的,虽然没有什么特别的辉煌,而且很多人可能已经在使用它,但我没有找到关于如何通过搜索引擎来实现它的明确说明。 所以对其他人可能有用。

  • 将某个文件保存在某个地方(对于以下内容,让我们假设~/bin/ipynb_output_filter.py
  • 使其可执行( chmod +x ~/bin/ipynb_output_filter.py
  • 使用以下内容创建文件~/.gitattributes

    *.ipynb    filter=dropoutput_ipynb
    
  • 运行以下命令:

    git config --global core.attributesfile ~/.gitattributes
    git config --global filter.dropoutput_ipynb.clean ~/bin/ipynb_output_filter.py
    git config --global filter.dropoutput_ipynb.smudge cat
    
  • 完成!

    限制:

  • 它只适用于git
  • 在混帐中,如果你在分支somebranch ,你做git checkout otherbranch; git checkout somebranch git checkout otherbranch; git checkout somebranch ,你通常期望工作树不变。 在这里,您将失去两个分支之间信号源不同的笔记本电脑的输出和单元编号。
  • 更一般的情况是,输出结果并没有版本化,就像Gregory的解决方案一样。 为了不会在每次执行任何涉及签出的操作时抛弃它,可以通过将其存储在单独的文件中来更改该方法(但请注意,在上面的代码运行时,提交ID是未知的!),并可能对它们进行版本控制(但注意这需要比git commit notebook_file.ipynb更多的东西,尽管它至少可以让git diff notebook_file.ipynb免于base64垃圾)。
  • 这就是说,顺便说一句,如果你拉代码(即由不使用这种方法的人承诺)包含一些输出,则输出通常被检出。 只有本地生产的产品才会丢失。
  • 我的解决方案反映了我个人不喜欢保留生成的版本的事实 - 请注意,执行涉及输出的合并几乎可以保证使输出或您的生产力无效或两者兼而有之。

    编辑:

  • 如果您按照我的建议采用解决方案 - 也就是全球范围内的解决方案,那么您会遇到麻烦,因为某些git repo 需要版本输出。 因此,如果您想禁用特定git存储库的输出过滤,只需在其中创建一个文件.git / info / attributes,

    **。ipynb filter =

  • 作为内容。 显然,以相同的方式可以做相反的事情:只为特定的存储库启用过滤。

  • 代码现在保存在它自己的git仓库中

  • 如果上述指令导致ImportErrors,请尝试在脚本路径前添加“ipython”:

    git config --global filter.dropoutput_ipynb.clean ipython ~/bin/ipynb_output_filter.py
    
  • 编辑 :2016年5月(2017年2月更新):我的脚本有几种选择 - 为了完整性,这里是我知道的那些列表:nbstripout(其他变体),nbstrip,jq。


    我们有一个产品为Jupyter笔记本的合作项目,我们在过去的六个月中采用了一种行之有效的方法:我们激活自动保存.py文件并跟踪.ipynb文件和.py文件。

    这样,如果有人想查看/下载最新的笔记本,他们可以通过github或nbviewer来做到这一点,如果有人想看看笔记本代码是如何改变的,他们可以看看.py文件的变化。

    对于Jupyter笔记本电脑服务器 ,这可以通过添加线路来完成

    import os
    from subprocess import check_call
    
    def post_save(model, os_path, contents_manager):
        """post-save hook for converting notebooks to .py scripts"""
        if model['type'] != 'notebook':
            return # only do this for notebooks
        d, fname = os.path.split(os_path)
        check_call(['jupyter', 'nbconvert', '--to', 'script', fname], cwd=d)
    
    c.FileContentsManager.post_save_hook = post_save
    

    jupyter_notebook_config.py文件并重新启动笔记本服务器。

    如果您不确定在哪个目录中找到您的jupyter_notebook_config.py文件,可以键入jupyter --config-dir ,如果您没有在其中找到该文件,可以通过键入jupyter notebook --generate-config

    对于Ipython 3笔记本服务器 ,可以通过添加这些行来完成

    import os
    from subprocess import check_call
    
    def post_save(model, os_path, contents_manager):
        """post-save hook for converting notebooks to .py scripts"""
        if model['type'] != 'notebook':
            return # only do this for notebooks
        d, fname = os.path.split(os_path)
        check_call(['ipython', 'nbconvert', '--to', 'script', fname], cwd=d)
    
    c.FileContentsManager.post_save_hook = post_save
    

    ipython_notebook_config.py文件并重新启动笔记本服务器。 这些行来自@minrk提供的github问题答案,@dror也包含在他的SO答案中。

    对于Ipython 2笔记本服务器 ,这可以通过使用以下命令启动服务器来完成:

    ipython notebook --script
    

    或者通过添加该行

    c.FileNotebookManager.save_script = True
    

    ipython_notebook_config.py文件并重新启动笔记本服务器。

    如果您不确定在哪个目录中找到您的ipython_notebook_config.py文件,则可以键入ipython locate profile default ,如果您没有在其中找到该文件,可以通过键入ipython profile create来创建它。

    这是我们在github上使用这种方法的项目:这里有一个探索笔记本最近变化的github例子。

    我们对此非常满意。


    我已经创建nbstripout ,基于MinRKs要点,同时支持Git和水银(感谢mforbes)。 它可以在命令行上单独使用,也可以作为过滤器使用,通过nbstripout install / nbstripout uninstall可轻松(未)安装到当前存储库中。

    从PyPI或简单地获取它

    pip install nbstripout
    
    链接地址: http://www.djcxy.com/p/35487.html

    上一篇: Using IPython notebooks under version control

    下一篇: Should composer.lock be committed to version control?