From 172cafcc84622fc6b029622f2985727ba15ce6e8 Mon Sep 17 00:00:00 2001 From: Radek Osmulski Date: Fri, 31 Jan 2025 08:20:56 +1000 Subject: [PATCH] Add exporting single notebook outside nbdev project To export a notebook to a .py file outside an nbdev project: ``` import nbdev nbdev.export.nb_export('./example.ipynb', '.', solo_nb=True) ``` Key change: added `solo_nb` arg that propagates the intent through functionality involved in exported module generation. --- nbdev/config.py | 4 ++-- nbdev/export.py | 3 ++- nbdev/maker.py | 6 +++--- nbs/api/01_config.ipynb | 4 ++-- nbs/api/02_maker.ipynb | 6 +++--- nbs/api/04_export.ipynb | 3 ++- 6 files changed, 14 insertions(+), 12 deletions(-) diff --git a/nbdev/config.py b/nbdev/config.py index f0f7921f9..b51eb7b83 100644 --- a/nbdev/config.py +++ b/nbdev/config.py @@ -249,12 +249,12 @@ def add_init(path=None): if get_config().get('put_version_in_init', True): update_version(path) # %% ../nbs/api/01_config.ipynb -def write_cells(cells, hdr, file, offset=0, cell_number=True): +def write_cells(cells, hdr, file, offset=0, cell_number=True, solo_nb=False): "Write `cells` to `file` along with header `hdr` starting at index `offset` (mainly for nbdev internal use)." for cell in cells: if cell.cell_type=='code' and cell.source.strip(): idx = f" {cell.idx_+offset}" if cell_number else "" - file.write(f'\n\n{hdr}{idx}\n{cell.source}') + file.write(f'\n\n{hdr}{idx}\n{cell.source}') if not solo_nb else file.write(f'\n\n{cell.source}') # %% ../nbs/api/01_config.ipynb def _basic_export_nb(fname, name, dest=None): diff --git a/nbdev/export.py b/nbdev/export.py index 6d32e1c20..b8436527e 100644 --- a/nbdev/export.py +++ b/nbdev/export.py @@ -73,6 +73,7 @@ def nb_export(nbname:str, # Filename of notebook name:str=None, # Name of python script {name}.py to create. mod_maker=ModuleMaker, debug:bool=False, # Debug mode + solo_nb:bool=False # Export single notebook outside of an nbdev project. ): "Create module(s) from notebook" if lib_path is None: lib_path = get_config().lib_path if is_nbdev() else '.' @@ -88,5 +89,5 @@ def nb_export(nbname:str, # Filename of notebook "Note nbdev2 no longer supports nbdev1 syntax. Run `nbdev_migrate` to upgrade.\n" "See https://nbdev.fast.ai/getting_started.html for more information.") return - mm = mod_maker(dest=lib_path, name=nm, nb_path=nbname, is_new=bool(name) or mod=='#') + mm = mod_maker(dest=lib_path, name=nm, nb_path=nbname, is_new=bool(name) or mod=='#', solo_nb=solo_nb) mm.make(cells, all_cells, lib_path=lib_path) diff --git a/nbdev/maker.py b/nbdev/maker.py index b7b018cdf..63c08acb3 100644 --- a/nbdev/maker.py +++ b/nbdev/maker.py @@ -63,7 +63,7 @@ def update_var(varname, func, fn=None, code=None): # %% ../nbs/api/02_maker.ipynb class ModuleMaker: "Helper class to create exported library from notebook source cells" - def __init__(self, dest, name, nb_path, is_new=True, parse=True): + def __init__(self, dest, name, nb_path, is_new=True, parse=True, solo_nb=False): dest,nb_path = Path(dest),Path(nb_path) store_attr() self.fname = dest/(name.replace('.','/') + ".py") @@ -208,8 +208,8 @@ def make(self:ModuleMaker, cells, all_cells=None, lib_path=None): f.write(_retr_mdoc(cells)) f.write(f"# AUTOGENERATED! DO NOT EDIT! File to edit: {self.dest2nb}.") if last_future > 0: write_cells(cells[:last_future], self.hdr, f) - if self.parse: f.write(f"\n\n# %% auto 0\n__all__ = {all_str}") - write_cells(cells[last_future:], self.hdr, f, cell_number=get_config().cell_number) + if self.parse and not self.solo_nb: f.write(f"\n\n# %% auto 0\n__all__ = {all_str}") + write_cells(cells[last_future:], self.hdr, f, cell_number=get_config().cell_number, solo_nb=self.solo_nb) f.write('\n') # %% ../nbs/api/02_maker.ipynb diff --git a/nbs/api/01_config.ipynb b/nbs/api/01_config.ipynb index be6379743..c5d06224c 100644 --- a/nbs/api/01_config.ipynb +++ b/nbs/api/01_config.ipynb @@ -735,12 +735,12 @@ "outputs": [], "source": [ "#|export\n", - "def write_cells(cells, hdr, file, offset=0, cell_number=True):\n", + "def write_cells(cells, hdr, file, offset=0, cell_number=True, solo_nb=False):\n", " \"Write `cells` to `file` along with header `hdr` starting at index `offset` (mainly for nbdev internal use).\"\n", " for cell in cells:\n", " if cell.cell_type=='code' and cell.source.strip():\n", " idx = f\" {cell.idx_+offset}\" if cell_number else \"\"\n", - " file.write(f'\\n\\n{hdr}{idx}\\n{cell.source}')" + " file.write(f'\\n\\n{hdr}{idx}\\n{cell.source}') if not solo_nb else file.write(f'\\n\\n{cell.source}')" ] }, { diff --git a/nbs/api/02_maker.ipynb b/nbs/api/02_maker.ipynb index 3b9c54627..084e2d5e8 100644 --- a/nbs/api/02_maker.ipynb +++ b/nbs/api/02_maker.ipynb @@ -201,7 +201,7 @@ "#|export\n", "class ModuleMaker:\n", " \"Helper class to create exported library from notebook source cells\"\n", - " def __init__(self, dest, name, nb_path, is_new=True, parse=True):\n", + " def __init__(self, dest, name, nb_path, is_new=True, parse=True, solo_nb=False):\n", " dest,nb_path = Path(dest),Path(nb_path)\n", " store_attr()\n", " self.fname = dest/(name.replace('.','/') + \".py\")\n", @@ -518,8 +518,8 @@ " f.write(_retr_mdoc(cells))\n", " f.write(f\"# AUTOGENERATED! DO NOT EDIT! File to edit: {self.dest2nb}.\")\n", " if last_future > 0: write_cells(cells[:last_future], self.hdr, f)\n", - " if self.parse: f.write(f\"\\n\\n# %% auto 0\\n__all__ = {all_str}\")\n", - " write_cells(cells[last_future:], self.hdr, f, cell_number=get_config().cell_number)\n", + " if self.parse and not self.solo_nb: f.write(f\"\\n\\n# %% auto 0\\n__all__ = {all_str}\")\n", + " write_cells(cells[last_future:], self.hdr, f, cell_number=get_config().cell_number, solo_nb=self.solo_nb)\n", " f.write('\\n')" ] }, diff --git a/nbs/api/04_export.ipynb b/nbs/api/04_export.ipynb index 5e2f9fc91..b3698c684 100644 --- a/nbs/api/04_export.ipynb +++ b/nbs/api/04_export.ipynb @@ -244,6 +244,7 @@ " name:str=None, # Name of python script {name}.py to create.\n", " mod_maker=ModuleMaker,\n", " debug:bool=False, # Debug mode\n", + " solo_nb:bool=False # Export single notebook outside of an nbdev project.\n", " ):\n", " \"Create module(s) from notebook\"\n", " if lib_path is None: lib_path = get_config().lib_path if is_nbdev() else '.'\n", @@ -259,7 +260,7 @@ " \"Note nbdev2 no longer supports nbdev1 syntax. Run `nbdev_migrate` to upgrade.\\n\"\n", " \"See https://nbdev.fast.ai/getting_started.html for more information.\")\n", " return\n", - " mm = mod_maker(dest=lib_path, name=nm, nb_path=nbname, is_new=bool(name) or mod=='#')\n", + " mm = mod_maker(dest=lib_path, name=nm, nb_path=nbname, is_new=bool(name) or mod=='#', solo_nb=solo_nb)\n", " mm.make(cells, all_cells, lib_path=lib_path)" ] },