370

I'm looking at using the *.ipynb files as the source of truth and programmatically 'compiling' them into .py files for scheduled jobs/tasks.

The only way I understand to do this is via the GUI. Is there a way to do it via command line?

Cristian Ciupitu
  • 19,240
  • 7
  • 48
  • 73
Stefan Krawczyk
  • 3,733
  • 3
  • 13
  • 6
  • 1
    What do you mean by "source of truth"? IPython notebooks are just json files. You can load them and manipulate as Python dictionaries. For source code you should be iterating `input` keys where `cell_type` equals 'code'. Have a look at this [scheme](http://i.imgur.com/Z0jSc.png) – theta Jun 13 '13 at 01:03
  • 1
    Well I want to store the .ipynb in a repository and not the .py files. So then as a 'build step' I would convert the .ipynb to .py files for actual use by the automated system. You're right, I could just load the json and output only the code cells, but I was wondering whether there was something out there already that did that for me :) – Stefan Krawczyk Jun 13 '13 at 01:17

14 Answers14

564

If you don't want to output a Python script every time you save, or you don't want to restart the IPython kernel:

On the command line, you can use nbconvert:

$ jupyter nbconvert --to script [YOUR_NOTEBOOK].ipynb

As a bit of a hack, you can even call the above command in an IPython notebook by pre-pending ! (used for any command line argument). Inside a notebook:

!jupyter nbconvert --to script config_template.ipynb

Before --to script was added, the option was --to python or --to=python, but it was renamed in the move toward a language-agnostic notebook system.

Matt
  • 26,019
  • 6
  • 79
  • 73
wwwilliam
  • 8,582
  • 7
  • 29
  • 32
  • 12
    If you DO want one every save, in `jupyter` you can trigger `nbconvert` via pre- or post-save hooks: `ContentsManager.pre_save_hook` abd `FileContentsManager.post_save_hook`. You would add a post-save hook `jupyter nbconvert --to script [notebook]` – jaimedash May 03 '16 at 16:35
  • 3
    Is there a way to do the reverse i.e convert from a python script to a notebook. For ex - having some specialized docstrings that are parsed into cells ? – Sujen Shah Jan 17 '17 at 17:40
  • 3
    convert all notebooks in a folder `jupyter nbconvert --to script /path/to/notebooks/*.ipynb` – openwonk Jul 22 '17 at 00:00
  • Does anyone know how to provide [TemplateExporter](https://nbconvert.readthedocs.io/en/latest/config_options.html) options to nbconvert? I'm using `!jupyter nbconvert --to python 'jupi_demo.ipynb' --stdout --TemplateExporter.exclude_markdown=True` on Jupyter 4.1.0 but it's complaining `Config option exclude_markdown not recognized by PythonExporter.` – Some Noob Student Sep 20 '17 at 01:42
  • 11
    Thanks, it works!, but what if I don't want the `# In[ ]:` type stuff in the script, I want it to be clean. Is there any way to do that? – Rishabh Agrahari Jan 31 '18 at 10:48
  • @RishabhAgrahari did you find a way for that? – matanster Aug 07 '18 at 09:57
  • 1
    @RishabhAgrahari check out here, you can just customize the linter https://jupyter-notebook.readthedocs.io/en/stable/extending/savehooks.html – MichaelChirico Sep 12 '18 at 07:34
  • 4
    @RishabhAgrahari Following seems to work for me. `!jupyter nbconvert --to script --no-prompt notebook.ipynb` – bytestorm May 27 '19 at 07:09
  • Thanks to openwonk for the suggestion. It worked like a charm: convert all notebooks in a folder `jupyter nbconvert --to script /path/to/notebooks/*.ipynb` – Rich Lysakowski PhD Jul 17 '19 at 06:58
  • @bytestorm, `--no-prompt` didn't work for me via command line (`# In[ ]:` still there) – alancalvitti Aug 02 '19 at 14:40
  • @bytestorm, also it is possible to convert the very notebook from which `nbconvert` is called? – alancalvitti Aug 02 '19 at 20:15
  • @alancalvitti @RishabhAgrahari have you found a way to generate the python script of jupyter notebook without `# In[ ]:`? – naman Aug 19 '19 at 12:15
  • @naman, not yet. Also default auto-convert in JupyterLab similarly retains prompts. – alancalvitti Aug 19 '19 at 13:46
  • 1
    @Sujen Shah, see [Jupytext](https://github.com/mwouts/jupytext#command-line-conversion) for the reverse conversion. – Wayne Jan 02 '20 at 18:51
  • @alancalvitti @bytestorm the `--no-prompt` worked for me as expected, removing the `# In[ ]:`... using `nbconvert==6.0.7` – Greg Hilston Oct 26 '21 at 01:36
  • Can I rename the python file it is going to be saved into? – Eduardo Pignatelli Dec 06 '21 at 16:10
127

If you want to convert all *.ipynb files from current directory to python script, you can run the command like this:

jupyter nbconvert --to script *.ipynb
Břetislav Hájek
  • 2,438
  • 1
  • 13
  • 17
  • Or you can run: ipython nbconvert --to script *.ipynb – Andrey Dec 23 '20 at 11:28
  • to convert programmatically as in a function use this syntax : subprocess.run(['jupyter', 'nbconvert',ipynb_file,"--to", "script","--output",r'temp_converted_py'],shell=True) note that ipynb_file is a variable – user15420598 Dec 28 '21 at 18:49
26

Here is a quick and dirty way to extract the code from V3 or V4 ipynb without using ipython. It does not check cell types, etc.

import sys,json

f = open(sys.argv[1], 'r') #input.ipynb
j = json.load(f)
of = open(sys.argv[2], 'w') #output.py
if j["nbformat"] >=4:
        for i,cell in enumerate(j["cells"]):
                of.write("#cell "+str(i)+"\n")
                for line in cell["source"]:
                        of.write(line)
                of.write('\n\n')
else:
        for i,cell in enumerate(j["worksheets"][0]["cells"]):
                of.write("#cell "+str(i)+"\n")
                for line in cell["input"]:
                        of.write(line)
                of.write('\n\n')

of.close()
Valentas
  • 1,744
  • 17
  • 23
  • 3
    Best answer if you do not want to install any of the Jupyter tools. – dacracot Oct 03 '16 at 14:38
  • 2
    I like this. But I found out when I download .py format from Jupyter notebooks, it uses UNIX line endings even though I'm on windows. To generate the same, add the `newlines='\n'` as a third argument in the open output file call. (Python 3.x) – RufusVS May 30 '19 at 19:19
  • This answer opens the possibility to read tags and extract only those cells that have it. Harder to do via the command line alone. – Pablo Adames Aug 09 '20 at 23:57
20

Following the previous example but with the new nbformat lib version :

import nbformat
from nbconvert import PythonExporter

def convertNotebook(notebookPath, modulePath):

  with open(notebookPath) as fh:
    nb = nbformat.reads(fh.read(), nbformat.NO_CONVERT)

  exporter = PythonExporter()
  source, meta = exporter.from_notebook_node(nb)

  with open(modulePath, 'w+') as fh:
    fh.writelines(source.encode('utf-8'))
Spawnrider
  • 1,657
  • 1
  • 19
  • 30
  • 1
    's last line of code, fh.writelines(source.encode('utf-8')) gives 'TypeError: write() argument must be str, not int' fh.writelines(source) works though. – BarryC Oct 18 '16 at 05:43
  • Had the same issue, fixed by dropping the `.encode('utf-8')` piece on the last line. – LFoos24 Jun 28 '21 at 17:18
  • I solved the last line problem writing `fh.write(source)` instead of `fh.writelines(...)`. – mosc9575 Nov 24 '21 at 14:33
15

Jupytext is nice to have in your toolchain for such conversions. It allows not only conversion from a notebook to a script, but you can go back again from the script to notebook as well. And even have that notebook produced in executed form.

jupytext --to py notebook.ipynb                 # convert notebook.ipynb to a .py file
jupytext --to notebook notebook.py              # convert notebook.py to an .ipynb file with no outputs
jupytext --to notebook --execute notebook.py    # convert notebook.py to an .ipynb file and run it 
Wayne
  • 3,203
  • 6
  • 25
  • 61
  • Apparently there is also ipynb-py-convert, see [here](https://stackoverflow.com/a/59685825/8508004). – Wayne Jan 10 '20 at 18:34
  • 1
    'jupytext' is not recognized as an internal or external command, operable program or batch file.??? – Amine Chadi Mar 31 '20 at 15:53
  • Have you installed it @AmineChadi . See [here](https://github.com/mwouts/jupytext#installation) for how to do that. If you are using it via a notebook as your command line interface, you can just run `%pip install jupytext` in your notebook. – Wayne Mar 31 '20 at 20:16
8

You can do this from the IPython API.

from IPython.nbformat import current as nbformat
from IPython.nbconvert import PythonExporter

filepath = 'path/to/my_notebook.ipynb'
export_path = 'path/to/my_notebook.py'

with open(filepath) as fh:
    nb = nbformat.reads_json(fh.read())

exporter = PythonExporter()

# source is a tuple of python source code
# meta contains metadata
source, meta = exporter.from_notebook_node(nb)

with open(export_path, 'w+') as fh:
    fh.writelines(source)
wwwslinger
  • 866
  • 7
  • 14
justanr
  • 680
  • 7
  • 13
7

I understand this is an old thread. I have faced the same issue and wanted to convert the .pynb file to .py file via command line.

My search took me to ipynb-py-convert

By following below steps I was able to get .py file

  1. Install "pip install ipynb-py-convert"
  2. Go to the directory where the ipynb file is saved via command prompt
  3. Enter the command

> ipynb-py-convert YourFileName.ipynb YourFilename.py

Eg:. ipynb-py-convert getting-started-with-kaggle-titanic-problem.ipynb getting-started-with-kaggle-titanic-problem.py

Above command will create a python script with the name "YourFileName.py" and as per our example it will create getting-started-with-kaggle-titanic-problem.py file

5

For converting all *.ipynb format files in current directory to python scripts recursively:

for i in *.ipynb **/*.ipynb; do 
    echo "$i"
    jupyter nbconvert  "$i" "$i"
done
Don Smythe
  • 8,096
  • 14
  • 58
  • 100
3

The following example turns an Iron Python Notebook called a_notebook.ipynb into a python script called a_python_script.py leaving out the cells tagged with the keyword remove, which I add manually to the cells that I don't want to end up in the script, leaving out visualizations and other steps that once I am done with the notebook I don't need to be executed by the script.

import nbformat as nbf
from nbconvert.exporters import PythonExporter
from nbconvert.preprocessors import TagRemovePreprocessor

with open("a_notebook.ipynb", 'r', encoding='utf-8') as f:
    the_notebook_nodes = nbf.read(f, as_version = 4)

trp = TagRemovePreprocessor()

trp.remove_cell_tags = ("remove",)

pexp = PythonExporter()

pexp.register_preprocessor(trp, enabled= True)

the_python_script, meta = pexp.from_notebook_node(the_notebook_nodes)

with open("a_python_script.py", 'w', encoding='utf-8') as f:
    f.writelines(the_python_script)
coproc
  • 5,697
  • 2
  • 18
  • 31
Pablo Adames
  • 439
  • 4
  • 9
3

Using nbconvert 6.07 and jupyter client 6.1.12:

Convert jupyter notebook to python script

$ jupyter nbconvert mynotebook.ipynb --to python

Convert jupyter notebook to python script specifying output filename

$ jupyter nbconvert mynotebook.ipnb --to python --output myscript.py
yaach
  • 121
  • 3
2

There's a very nice package called nb_dev which is designed for authoring Python packages in Jupyter Notebooks. Like nbconvert, it can turn a notebook into a .py file, but it is more flexible and powerful because it has a lot of nice additional authoring features to help you develop tests, documentation, and register packages on PyPI. It was developed by the fast.ai folks.

It has a bit of a learning curve, but the documentation is good and it is not difficult overall.

John
  • 888
  • 8
  • 19
0

I had this problem and tried to find the solution online. Though I found some solutions, they still have some problems, e.g., the annoying Untitled.txt auto-creation when you start a new notebook from the dashboard.

So eventually I wrote my own solution:

import io
import os
import re
from nbconvert.exporters.script import ScriptExporter
from notebook.utils import to_api_path


def script_post_save(model, os_path, contents_manager, **kwargs):
    """Save a copy of notebook to the corresponding language source script.

    For example, when you save a `foo.ipynb` file, a corresponding `foo.py`
    python script will also be saved in the same directory.

    However, existing config files I found online (including the one written in
    the official documentation), will also create an `Untitile.txt` file when
    you create a new notebook, even if you have not pressed the "save" button.
    This is annoying because we usually will rename the notebook with a more
    meaningful name later, and now we have to rename the generated script file,
    too!

    Therefore we make a change here to filter out the newly created notebooks
    by checking their names. For a notebook which has not been given a name,
    i.e., its name is `Untitled.*`, the corresponding source script will not be
    saved. Note that the behavior also applies even if you manually save an
    "Untitled" notebook. The rationale is that we usually do not want to save
    scripts with the useless "Untitled" names.
    """
    # only process for notebooks
    if model["type"] != "notebook":
        return

    script_exporter = ScriptExporter(parent=contents_manager)
    base, __ = os.path.splitext(os_path)

    # do nothing if the notebook name ends with `Untitled[0-9]*`
    regex = re.compile(r"Untitled[0-9]*$")
    if regex.search(base):
        return

    script, resources = script_exporter.from_filename(os_path)
    script_fname = base + resources.get('output_extension', '.txt')

    log = contents_manager.log
    log.info("Saving script at /%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

To use this script, you can add it to ~/.jupyter/jupyter_notebook_config.py :)

Note that you may need to restart the jupyter notebook / lab for it to work.

Jiren Jin
  • 319
  • 2
  • 5
0

On my mint [ubuntu] system at work, even though jupyter was already installed and notebooks worked, jupyter nbconvert --to script gave the error no file/directory until I did a separate

sudo apt-get install jupyter-nbconvert

Then all was fine with the conversion. I just wanted to add this in case anyone hits the same error (for me it was confusing as I thought the no file error referred to the notebook, which was definitely there in the local directory, took me a while to realize the subcommand was not installed).

Adrian Tompkins
  • 5,816
  • 3
  • 29
  • 72
-2

The %notebook foo.ipynb magic command will export the current IPython to "foo.ipynb".

More info by typing %notebook?