6

I have a Jupyter notebook and I'd like to convert it into a Python script using the nbconvert command from within the Jupyter notebook.

I have included the following line at the end of the notebook:

!jupyter nbconvert --to script <filename>.ipynb

This creates a Python script. However, I'd like the resulting .py file to have the following properties:

  1. No input statements, such as:

    # In[27]:

  2. No markdown, including statements such as:

    # coding: utf-8

  3. Ignore %magic commands such as:

    1. %matplotlib inline
    2. !jupyter nbconvert --to script <filename>.ipynb, i.e. the command within the notebook that executes the Python conversion

    Currently, the %magic commands get translated to the form: get_ipython().magic(...), but these are not necessarily recognized in Python.

profj
  • 311
  • 3
  • 10

4 Answers4

9

One way to get control of what appears in the output is to tag the cells that you don't want in the output and then use the TagRemovePreprocessor to remove the cells.

enter image description here

The code below also uses the exclude_markdown function in the TemplateExporter to remove markdown.

!jupyter nbconvert \
    --TagRemovePreprocessor.enabled=True \
    --TagRemovePreprocessor.remove_cell_tags="['parameters']" \
    --TemplateExporter.exclude_markdown=True \
    --to python "notebook_with_parameters_removed.ipynb"

To remove the commented lines and the input statement markets (like # [1]), I believe you'll need to post-process the Python file with something like the following in the cell after the cell you call !jupyter nbconvert from (note that this is Python 3 code):

import re
from pathlib import Path
filename = Path.cwd() / 'notebook_with_parameters_removed.py'
code_text = filename.read_text().split('\n')
lines = [line for line in code_text if len(line) == 0 or 
        (line[0] != '#' and 'get_ipython()' not in line)]
clean_code = '\n'.join(lines)
clean_code = re.sub(r'\n{2,}', '\n\n', clean_code)
filename.write_text(clean_code.strip())
user6481870
  • 1,289
  • 13
  • 9
3

The most obvious solution seems to work for me:

 jupyter nbconvert --to python a_notebook.ipynb --stdout | grep -v -e "^get_ipython" | python

Of course, you can't use something like dirs = !ls in your notebooks for this to work.

krvkir
  • 771
  • 7
  • 12
3

Hopefully this will spare people from wasting 2 hours trying to use nbconvert template structure. This is what did the job for me:

nbconvert --to python --RegexRemovePreprocessor.patterns="^%" analysis.ipynb
  • 1
    Better regex: --RegexRemovePreprocessor.patterns="^[!%]", this will also remove lines starting with "!". – Sander Apr 17 '23 at 09:30
2

Jupyter nbconvert has made this a little bit easier with a new template structure.

Templates should be placed in the template path. This can be found by running jupyter --paths

Each template should be placed in its own directory within the template directory and must contain a conf.json and index.py.j2 file.

This solution covers all the details for adding a template.

This template will remove all the of the markdown, magic and cell numbers leaving a "runnable" .py file. Run this template from within a notebook with !jupyter nbconvert --to python --template my_clean_python_template my_notebook.ipynb

index.py.j2

{%- extends 'null.j2' -%}

## set to python3
{%- block header -%}
#!/usr/bin/env python3
# coding: utf-8
{% endblock header %}

## remove cell counts entirely
{% block in_prompt %}
{% if resources.global_content_filter.include_input_prompt -%}
{% endif %}
{% endblock in_prompt %}

## remove markdown cells entirely
{% block markdowncell %}
{% endblock markdowncell %}

{% block input %}
{{ cell.source | ipython2python }}
{% endblock input %}


## remove magic statement completely
{% block codecell %}
{{'' if "get_ipython" in super() else super() }}
{% endblock codecell%}
Aaron Ciuffo
  • 804
  • 8
  • 22
  • People say those templates stopped working in new versions of `nbconvert`, see https://github.com/ipython/ipython/issues/3707/. – krvkir Dec 08 '21 at 15:39
  • @krvkir: Can you be more specific? The link you provided is almost a year old. This solution appears to work for nbconvert > 6.0. This is what I'm using in 6.2.0 and 6.1.7 across several platforms and it appears to be OK. I haven't tried it with 6.3.0 yet. The entire structure of the templates have changed between V5 and V6. Check this solution for details: https://stackoverflow.com/a/64144224/5530152 – Aaron Ciuffo Dec 09 '21 at 08:58
  • My bad, I overlooked that your solution is for the new template system. Sorry for misinformation. – krvkir Dec 13 '21 at 13:02