¿Cómo convierto un cuaderno de IPython en un archivo de Python a través de la línea de comandos?

258

Estoy mirando el uso de los archivos * .ipynb como la fuente de la verdad y programáticamente 'compilándolos' en archivos .py para trabajos / tareas programadas.

La única forma en que entiendo hacer esto es a través de la GUI. ¿Hay alguna manera de hacerlo a través de la línea de comando?

Stefan Krawczyk
fuente
1
¿Qué quieres decir con "fuente de verdad"? Las notebooks IPython son solo archivos json. Puede cargarlos y manipularlos como diccionarios de Python. Para el código fuente, debe iterar inputclaves donde sea cell_typeigual a 'código'. Echa un vistazo a este esquema
theta
1
Bueno, quiero almacenar el .ipynb en un repositorio y no los archivos .py. Entonces, como 'paso de compilación', convertiría los archivos .ipynb a .py para uso real del sistema automatizado. Tienes razón, podría cargar el json y generar solo las celdas de código, pero me preguntaba si ya había algo por ahí que me hiciera eso :)
Stefan Krawczyk
1
@StefanKrawczyk ¿Puede marcar una respuesta como aceptada? Recomendaría la respuesta de wwwilliam
pedram bashiri

Respuestas:

414

Si no desea generar un script Python cada vez que guarda, o no desea reiniciar el kernel de IPython:

En la línea de comando , puede usar nbconvert:

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

Como un truco, incluso puede llamar al comando anterior en un cuaderno de IPython pre-pendiente !(usado para cualquier argumento de línea de comando). Dentro de un cuaderno:

!jupyter nbconvert --to script config_template.ipynb

Antes --to scriptse agregaba , la opción era --to pythono --to=python, pero se renombró en el movimiento hacia un sistema de cuaderno independiente del idioma.

wwwilliam
fuente
8
Si desea uno cada vez que guarde, jupyterpuede activarlo nbconvertmediante ganchos previos o posteriores al guardado: ContentsManager.pre_save_hookabd FileContentsManager.post_save_hook. jupyter nbconvert --to script [notebook]
Agregaría un
3
¿Hay alguna manera de hacer lo contrario, es decir, convertir un script de Python en un cuaderno? Por ejemplo, ¿tener algunas cadenas de documentos especializadas que se analizan en celdas?
Sujen Shah
3
convertir todos los cuadernos en una carpetajupyter nbconvert --to script /path/to/notebooks/*.ipynb
openwonk
8
¡Gracias, funciona! Pero, ¿y si no quiero el # In[ ]:tipo de letra en el script, quiero que esté limpio? ¿Hay alguna manera de hacerlo?
Rishabh Agrahari
1
@RishabhAgrahari echa un vistazo aquí, sólo puede personalizar la borra de jupyter-notebook.readthedocs.io/en/stable/extending/...
MichaelChirico
77

Si desea convertir todos los *.ipynbarchivos del directorio actual a la secuencia de comandos de Python, puede ejecutar el comando de esta manera:

jupyter nbconvert --to script *.ipynb
Břetislav Hájek
fuente
19

Aquí hay una manera rápida y sucia de extraer el código de V3 o V4 ipynb sin usar ipython. No verifica los tipos de celdas, 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
fuente
1
La mejor respuesta si no desea instalar ninguna de las herramientas de Jupyter.
dacracot
1
Me gusta esto. Pero descubrí que cuando descargo el formato .py de los cuadernos Jupyter, usa las terminaciones de línea UNIX aunque estoy en Windows. Para generar lo mismo, agregue el newlines='\n'como tercer argumento en la llamada al archivo de salida abierto. (Python 3.x)
RufusVS
16

Siguiendo el ejemplo anterior pero con la nueva versión nbformat lib :

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'))
Jinete de engendros
fuente
La última línea de código, fh.writelines (source.encode ('utf-8')) da 'TypeError: el argumento write () debe ser str, no int' fh.writelines (fuente) funciona.
BarryC
6

Puede hacerlo desde la API de IPython.

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)
justanr
fuente
4

Es bueno tener Jupytext en su cadena de herramientas para tales conversiones. No solo permite la conversión de una libreta a una secuencia de comandos, sino que también puede volver de nuevo de la secuencia de comandos a la libreta. E incluso tener ese cuaderno producido en forma ejecutada.

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
fuente
Aparentemente también hay ipynb-py-convert, mira aquí .
Wayne
'jupytext' no se reconoce como un comando interno o externo, programa operativo o archivo por lotes.
Amine Chadi
¿Lo has instalado @AmineChadi? Vea aquí cómo hacerlo. Si lo está utilizando a través de una computadora portátil como interfaz de línea de comandos, puede ejecutarlo %pip install jupytexten su computadora portátil.
Wayne
3

Para convertir todos los archivos de formato * .ipynb en el directorio actual a scripts de python de forma recursiva:

for i in *.ipynb **/*.ipynb; do 
    echo "$i"
    jupyter nbconvert  "$i" "$i"
done
Don Smythe
fuente
3
Tuve que agregar el --to scriptargumento para evitar la salida HTML predeterminada en Jupiter 4.4.0.
trojjer
0

Tuve este problema e intenté encontrar la solución en línea. Aunque encontré algunas soluciones, todavía tienen algunos problemas, por ejemplo, la molesta Untitled.txtcreación automática cuando inicia un nuevo cuaderno desde el tablero.

Finalmente, escribí mi propia solución :

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

Para usar este script, puede agregarlo a ~/.jupyter/jupyter_notebook_config.py:)

Tenga en cuenta que es posible que deba reiniciar el jupyter notebook / lab para que funcione.

Jiren Jin
fuente
0

Hay un paquete muy agradable llamado nb_dev que está diseñado para crear paquetes de Python en Jupyter Notebooks. Al igual nbconvert,que puede convertir una computadora portátil en un archivo .py, pero es más flexible y potente porque tiene muchas características adicionales de autoría adicionales para ayudarlo a desarrollar pruebas, documentación y registrar paquetes en PyPI. Fue desarrollado por la gente de fast.ai.

Tiene un poco de curva de aprendizaje, pero la documentación es buena y no es difícil en general.

Juan
fuente