ipython notebook --script deprecated. How to replace with post save hook?

非 Y 不嫁゛ 提交于 2019-11-28 06:58:11
Tristan Reid

[UPDATED per comment by @mobius dumpling]

Find your config files:

Jupyter / ipython >= 4.0

jupyter --config-dir

ipython <4.0

ipython locate profile default

If you need a new config:

Jupyter / ipython >= 4.0

jupyter notebook --generate-config

ipython <4.0

ipython profile create

Within this directory, there will be a file called [jupyter | ipython]_notebook_config.py, put the following code from ipython's GitHub issues page in that file:

import os
from subprocess import check_call

c = get_config()

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

For Jupyter, replace ipython with jupyter in check_call.

Note that there's a corresponding 'pre-save' hook, and also that you can call any subprocess or run any arbitrary code there...if you want to do any thing fancy like checking some condition first, notifying API consumers, or adding a git commit for the saved script.

Cheers,

-t.

Here is another approach that doesn't invoke a new thread (with check_call). Add the following to jupyter_notebook_config.py as in Tristan's answer:

import io
import os
from notebook.utils import to_api_path

_script_exporter = None

def script_post_save(model, os_path, contents_manager, **kwargs):
    """convert notebooks to Python script after save with nbconvert

    replaces `ipython notebook --script`
    """
    from nbconvert.exporters.script import ScriptExporter

    if model['type'] != 'notebook':
        return

    global _script_exporter
    if _script_exporter is None:
        _script_exporter = ScriptExporter(parent=contents_manager)
    log = contents_manager.log

    base, ext = os.path.splitext(os_path)
    py_fname = base + '.py'
    script, resources = _script_exporter.from_filename(os_path)
    script_fname = base + resources.get('output_extension', '.txt')
    log.info("Saving script /%s", to_api_path(script_fname, contents_manager.root_dir))
    with io.open(script_fname, 'w', encoding='utf-8') as f:
        f.write(script)

c.FileContentsManager.post_save_hook = script_post_save

Disclaimer: I'm pretty sure I got this from SO somwhere, but can't find it now. Putting it here so it's easier to find in future (:

I just encountered a problem where I didn't have rights to restart my Jupyter instance, and so the post-save hook I wanted couldn't be applied.

So, I extracted the key parts and could run this with python manual_post_save_hook.py:

from io import open
from re import sub
from os.path import splitext
from nbconvert.exporters.script import ScriptExporter

for nb_path in ['notebook1.ipynb', 'notebook2.ipynb']:
    base, ext = splitext(nb_path)
    script, resources = ScriptExporter().from_filename(nb_path)
    # mine happen to all be in Python so I needn't bother with the full flexibility
    script_fname = base + '.py'
    with open(script_fname, 'w', encoding='utf-8') as f:
        # remove 'In [ ]' commented lines peppered about
        f.write(sub(r'[\n]{2}# In\[[0-9 ]+\]:\s+[\n]{2}', '\n', script))

You can add your own bells and whistles as you would with the standard post save hook, and the config is the correct way to proceed; sharing this for others who might end up in a similar pinch where they can't get the config edits to go into action.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!