Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP Add option to remove cell header comment lines on export, fixes #965 #1257

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 10 additions & 3 deletions nbdev/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -250,11 +250,18 @@ def add_init(path=None):

# %% ../nbs/api/01_config.ipynb 51
def write_cells(cells, hdr, file, offset=0):
"Write `cells` to `file` along with header `hdr` starting at index `offset` (mainly for nbdev internal use)."
"""Write `cells` to `file` along with header `hdr` starting at index `offset`
(mainly for nbdev internal use). If `hdr` is not specified, neither the header
nor the cell index will be written"""
for cell in cells:
if cell.source.strip(): file.write(f'\n\n{hdr} {cell.idx_+offset}\n{cell.source}')
if cell.source.strip():
full_hdr = ''
if (hdr is not None):
full_hdr = f'{hdr} {cell.idx_+offset}\n'

file.write(f'\n\n{full_hdr}{cell.source}')

# %% ../nbs/api/01_config.ipynb 52
# %% ../nbs/api/01_config.ipynb 56
def _basic_export_nb(fname, name, dest=None):
"Basic exporter to bootstrap nbdev."
if dest is None: dest = get_config().lib_path
Expand Down
16 changes: 13 additions & 3 deletions nbdev/maker.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,14 +61,18 @@ def update_var(varname, func, fn=None, code=None):
# %% ../nbs/api/02_maker.ipynb 15
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,
write_cell_hdrs=True):
dest,nb_path = Path(dest),Path(nb_path)
store_attr()
self.fname = dest/(name.replace('.','/') + ".py")
if is_new: dest.mkdir(parents=True, exist_ok=True)
else: assert self.fname.exists(), f"{self.fname} does not exist"
self.dest2nb = nb_path.relpath(self.fname.parent).as_posix()
self.hdr = f"# %% {self.dest2nb}"
if write_cell_hdrs is True:
self.hdr = f"# %% {self.dest2nb}"
else:
self.hdr = None

# %% ../nbs/api/02_maker.ipynb 18
def decor_id(d):
Expand Down Expand Up @@ -210,7 +214,7 @@ def make(self:ModuleMaker, cells, all_cells=None, lib_path=None):
write_cells(cells[last_future:], self.hdr, f)
f.write('\n')

# %% ../nbs/api/02_maker.ipynb 38
# %% ../nbs/api/02_maker.ipynb 45
@patch
def _update_all(self:ModuleMaker, all_cells, alls):
return pformat(alls + self.make_all(all_cells), width=160)
Expand All @@ -222,7 +226,13 @@ def _make_exists(self:ModuleMaker, cells, all_cells=None):
update_var('__all__', partial(self._update_all, all_cells), fn=self.fname)
with self.fname.open('a', encoding="utf-8") as f: write_cells(cells, self.hdr, f)

<<<<<<< HEAD
# %% ../nbs/api/02_maker.ipynb 44
||||||| parent of 414c5f7 (WIP Add option to remove cell header comment lines on export, partly fixes #965)
# %% ../nbs/api/maker.ipynb 44
=======
# %% ../nbs/api/maker.ipynb 51
>>>>>>> 414c5f7 (WIP Add option to remove cell header comment lines on export, partly fixes #965)
def _basic_export_nb2(fname, name, dest=None):
"A basic exporter to bootstrap nbdev using `ModuleMaker`"
if dest is None: dest = get_config().lib_path
Expand Down
56 changes: 54 additions & 2 deletions nbs/api/01_config.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
"source": [
"#|hide\n",
"from fastcore.test import *\n",
"from nbdev.maker import make_code_cells\n",
"import tempfile"
]
},
Expand Down Expand Up @@ -725,9 +726,60 @@
"source": [
"#|export\n",
"def write_cells(cells, hdr, file, offset=0):\n",
" \"Write `cells` to `file` along with header `hdr` starting at index `offset` (mainly for nbdev internal use).\"\n",
" \"\"\"Write `cells` to `file` along with header `hdr` starting at index `offset`\n",
" (mainly for nbdev internal use). If `hdr` is not specified, neither the header\n",
" nor the cell index will be written\"\"\"\n",
" for cell in cells:\n",
" if cell.source.strip(): file.write(f'\\n\\n{hdr} {cell.idx_+offset}\\n{cell.source}')"
" if cell.source.strip():\n",
" full_hdr = ''\n",
" if (hdr is not None):\n",
" full_hdr = f'{hdr} {cell.idx_+offset}\\n'\n",
" \n",
" file.write(f'\\n\\n{full_hdr}{cell.source}')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"If `hdr` has a real value, include it along with the offset index:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"#|hide\n",
"with tempfile.TemporaryFile(mode='w+t') as f:\n",
" c = make_code_cells(\"a = 'b'\\n_doc_ = 'hi'\")\n",
" write_cells(c, \"#\", f)\n",
"\n",
" f.seek(0)\n",
" test_eq(f.read(), \"\\n\\n# 0\\na = 'b'\\n_doc_ = 'hi'\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"If `hdr` doesn't have a real value, omit the line entirely:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"#|hide\n",
"with tempfile.TemporaryFile(mode='w+t') as f:\n",
" c = make_code_cells(\"a = 'b'\\n_doc_ = 'hi'\")\n",
" write_cells(c, None, f)\n",
"\n",
" f.seek(0)\n",
" test_eq(f.read(), \"\\n\\na = 'b'\\n_doc_ = 'hi'\")"
]
},
{
Expand Down
112 changes: 110 additions & 2 deletions nbs/api/02_maker.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -201,14 +201,18 @@
"#|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, \n",
" write_cell_hdrs=True):\n",
" dest,nb_path = Path(dest),Path(nb_path)\n",
" store_attr()\n",
" self.fname = dest/(name.replace('.','/') + \".py\")\n",
" if is_new: dest.mkdir(parents=True, exist_ok=True)\n",
" else: assert self.fname.exists(), f\"{self.fname} does not exist\"\n",
" self.dest2nb = nb_path.relpath(self.fname.parent).as_posix()\n",
" self.hdr = f\"# %% {self.dest2nb}\""
" if write_cell_hdrs is True:\n",
" self.hdr = f\"# %% {self.dest2nb}\"\n",
" else:\n",
" self.hdr = None"
]
},
{
Expand Down Expand Up @@ -645,6 +649,110 @@
"show_src(Path('tmp/test/testing_noall.py').read_text())"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Check that the default header is written correctly:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"file_lines = Path('tmp/test/testing_noall.py').read_text().splitlines()\n",
"\n",
"comment_lines = (line for line in file_lines if line.startswith(\"# %% \"))\n",
"\n",
"for index, line in enumerate(comment_lines):\n",
" test_eq(line, f'# %% ../../01_export.ipynb {index}')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Test making a module with `write_cell_hdrs`= `False`:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"Path('tmp/test/testing_noall.py')"
]
},
"execution_count": null,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"am = ModuleMaker(dest='tmp', name='test.testing_noall', nb_path=Path.cwd()/'01_export.ipynb',\n",
" is_new=True, parse=False, write_cell_hdrs=False)\n",
"am.fname"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [
{
"data": {
"text/markdown": [
"```python\n",
"# AUTOGENERATED! DO NOT EDIT! File to edit: ../../01_export.ipynb.\n",
"\n",
"from __future__ import print_function\n",
"\n",
"#|export\n",
"def a(): ...\n",
"\n",
"#|export\n",
"class A:\n",
"\n",
"```"
],
"text/plain": [
"<IPython.core.display.Markdown object>"
]
},
"execution_count": null,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"cells = make_code_cells(\"from __future__ import print_function\", \"#|export\\ndef a(): ...\", \"#|export\\nclass A:\")\n",
"am.make(cells)\n",
"show_src(Path('tmp/test/testing_noall.py').read_text())"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Check that cell headers are omitted when `write_cell_hdrs` is `False`:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"file_lines = Path('tmp/test/testing_noall.py').read_text().splitlines()\n",
"comment_lines = list(line for line in file_lines if line.startswith(\"# %% \"))\n",
"test_eq(len(comment_lines), 0)\n"
]
},
{
"cell_type": "code",
"execution_count": null,
Expand Down