Skip to content
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
2 changes: 2 additions & 0 deletions fastcore/_modidx.py
Original file line number Diff line number Diff line change
Expand Up @@ -587,6 +587,7 @@
'fastcore.nbio.Notebook.meta': ('nbio.html#notebook.meta', 'fastcore/nbio.py'),
'fastcore.nbio.Notebook.move': ('nbio.html#notebook.move', 'fastcore/nbio.py'),
'fastcore.nbio.Notebook.open': ('nbio.html#notebook.open', 'fastcore/nbio.py'),
'fastcore.nbio.Notebook.remove': ('nbio.html#notebook.remove', 'fastcore/nbio.py'),
'fastcore.nbio.Notebook.save': ('nbio.html#notebook.save', 'fastcore/nbio.py'),
'fastcore.nbio.Notebook.summary': ('nbio.html#notebook.summary', 'fastcore/nbio.py'),
'fastcore.nbio.Notebook.to_dict': ('nbio.html#notebook.to_dict', 'fastcore/nbio.py'),
Expand Down Expand Up @@ -622,6 +623,7 @@
'fastcore.nbio.cells2xml': ('nbio.html#cells2xml', 'fastcore/nbio.py'),
'fastcore.nbio.concat_streams': ('nbio.html#concat_streams', 'fastcore/nbio.py'),
'fastcore.nbio.deep_merge': ('nbio.html#deep_merge', 'fastcore/nbio.py'),
'fastcore.nbio.del_cells': ('nbio.html#del_cells', 'fastcore/nbio.py'),
'fastcore.nbio.dict2nb': ('nbio.html#dict2nb', 'fastcore/nbio.py'),
'fastcore.nbio.diff_cells': ('nbio.html#diff_cells', 'fastcore/nbio.py'),
'fastcore.nbio.dir_tag': ('nbio.html#dir_tag', 'fastcore/nbio.py'),
Expand Down
6 changes: 3 additions & 3 deletions fastcore/editskill.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
## What's where

- `fastcore.tools`: text primitives, file tools, and `line_hash`/`lnhash`/`lnhash_at` for creating addresses without exhash installed.
- `fastcore.nbio`: notebook read/write/validate/repair, cell construction, cell editors, and the `Notebook`/`NbCell` session objects with their snapshot queries (`find_cells`, `summary_nb`).
- `fastcore.nbio`: notebook read/write/validate/repair, cell construction, cell editors, and the `Notebook`/`NbCell` session objects with their snapshot queries (`find_cells`, `summary_nb`), plus `nb.remove`/`del_cells` for taking cells out.
- `exhash.skill`: hash-verified editing for files and cells, plus `open_doc` section outlines for Markdown, code, and notebooks; prefer it for edits where installed.
- `rgapi.skill`: `rg`/`fd`/`ls`/`nbrg` search with lnhash output, and `rgstr` to search text already in hand.
- `remold`: structural search and rewrite for Python source (declarative ast-grep rules, LibCST matcher transforms, symbol queries); the engine behind `ast_replace`.
Expand All @@ -56,12 +56,12 @@
file_insert_line, file_str_replace, file_strs_replace, file_replace_lines, file_del_lines, file_ast_replace,
view_file, create_file, line_hash, lnhash, lnhash_at)
from fastcore.nbio import (read_nb, write_nb, new_nb, mk_cell, validate_nb, validate_cell, repair_nb, repair_cell,
view_cell, cell_insert_line, cell_str_replace, cell_strs_replace, cell_replace_lines, cell_del_lines, cell_ast_replace, Notebook, NbCell, find_cells, summary_nb)
view_cell, cell_insert_line, cell_str_replace, cell_strs_replace, cell_replace_lines, cell_del_lines, cell_ast_replace, Notebook, NbCell, find_cells, summary_nb, del_cells)

__all__ = ['insert_line', 'str_replace', 'strs_replace', 'replace_lines', 'del_lines', 'ast_replace',
'file_insert_line', 'file_str_replace', 'file_strs_replace', 'file_replace_lines', 'file_del_lines', 'file_ast_replace',
'view_file', 'create_file', 'line_hash', 'lnhash', 'lnhash_at',
'read_nb', 'write_nb', 'new_nb', 'mk_cell', 'validate_nb', 'validate_cell', 'repair_nb', 'repair_cell',
'view_cell', 'cell_insert_line', 'cell_str_replace', 'cell_strs_replace', 'cell_replace_lines', 'cell_del_lines', 'cell_ast_replace', 'Notebook', 'NbCell', 'find_cells', 'summary_nb']
'view_cell', 'cell_insert_line', 'cell_str_replace', 'cell_strs_replace', 'cell_replace_lines', 'cell_del_lines', 'cell_ast_replace', 'Notebook', 'NbCell', 'find_cells', 'summary_nb', 'del_cells']

__pyskill_params__ = {'replace_params': ('start_line', 'end_line', 'n_matches', 're_filter', 'invert_filter', 'use_regex')}
26 changes: 22 additions & 4 deletions fastcore/nbio.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@
'repair_cell', 'repair_nb', 'preferred_out', 'join_out', 'mk_stream', 'mk_result', 'mk_display', 'mk_error',
'concat_streams', 'preferred_msg_out', 'render_output', 'render_outputs', 'render_text', 'item2xml',
'cell2xml', 'cells2xml', 'Notebook', 'CellRow', 'CellRows', 'summary_nb', 'Found', 'FoundCells',
'find_cells', 'deep_merge', 'update_cell', 'fm_default_eval', 'does_cell_eval', 'select_cells', 'run_cell',
'msg2out', 'msgs2outs']
'find_cells', 'del_cells', 'deep_merge', 'update_cell', 'fm_default_eval', 'does_cell_eval', 'select_cells',
'run_cell', 'msg2out', 'msgs2outs']

# %% ../nbs/13_nbio.ipynb #954ca1aa
from .basics import *
Expand Down Expand Up @@ -715,12 +715,19 @@ def md(self:Notebook, source, idx=None, after=None, before=None, **kwargs):
"Add a new cell with `source` at `idx` (default: end), or `after`/`before` a cell id"
return self.add(source, cell_type='markdown', idx=idx, after=after, before=before, **kwargs)

# %% ../nbs/13_nbio.ipynb #dac137e1
@patch
def remove(self:Notebook, *ids):
"Remove cells by id (exact or unique prefix), index, or held cell, returning them"
cells = [k if isinstance(k, dict) else self[k] for k in ids]
for c in cells: self.cells.remove(c)
return cells

# %% ../nbs/13_nbio.ipynb #63ba4a93
@patch
def move(self:Notebook, src_ids, after=None, before=None):
"Move cells with `src_ids` after/before a cell id, or to end"
cells = [self[k] for k in listify(src_ids)]
for c in cells: self.cells.remove(c)
cells = self.remove(*listify(src_ids))
if after: idx = next((i+1 for i,c in enumerate(self.cells) if c.id==after), None)
elif before: idx = next((i for i,c in enumerate(self.cells) if c.id==before), None)
else: idx = len(self.cells)
Expand Down Expand Up @@ -825,6 +832,17 @@ def find_cells(
fc = Notebook.open(path).find_cells(pat, cell_type, ids=ids, context=context)
return FoundCells([CellRow(c) for c in fc], matched=fc.matched)

# %% ../nbs/13_nbio.ipynb #2a645b36
def del_cells(
path, # Notebook file to modify
*ids, # Cell ids (exact or unique prefix) or indexes
):
"Delete cells from the notebook at `path`, returning `CellRow` snapshots of the removed cells"
nb = Notebook.open(path)
res = nb.remove(*ids)
nb.save()
return CellRows(CellRow(c) for c in res)

# %% ../nbs/13_nbio.ipynb #202a29f1
def deep_merge(
d:dict, # Base dict
Expand Down
105 changes: 103 additions & 2 deletions nbs/13_nbio.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -3093,6 +3093,54 @@
"len(nbo) == prev_len - 1\n"
]
},
{
"cell_type": "markdown",
"id": "bcc758dd",
"metadata": {},
"source": [
"`remove` takes any number of ids, or held cells, and returns what it removed. Passing a cell rather than an id is how to pick one of two cells that share an id, as nbdev's merge driver leaves them after a conflict:"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "dac137e1",
"metadata": {},
"outputs": [],
"source": [
"#| export\n",
"@patch\n",
"def remove(self:Notebook, *ids):\n",
" \"Remove cells by id (exact or unique prefix), index, or held cell, returning them\"\n",
" cells = [k if isinstance(k, dict) else self[k] for k in ids]\n",
" for c in cells: self.cells.remove(c)\n",
" return cells"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "9eee34a1",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"['e2147a69', '801558df']"
]
},
"execution_count": 138,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"nbo = Notebook.open(minimal_fn)\n",
"removed = nbo.remove('e214', nbo[0])\n",
"test_eq(len(nbo), 0)\n",
"[c.id for c in removed]"
]
},
{
"cell_type": "code",
"execution_count": null,
Expand All @@ -3104,8 +3152,7 @@
"@patch\n",
"def move(self:Notebook, src_ids, after=None, before=None):\n",
" \"Move cells with `src_ids` after/before a cell id, or to end\"\n",
" cells = [self[k] for k in listify(src_ids)]\n",
" for c in cells: self.cells.remove(c)\n",
" cells = self.remove(*listify(src_ids))\n",
" if after: idx = next((i+1 for i,c in enumerate(self.cells) if c.id==after), None)\n",
" elif before: idx = next((i for i,c in enumerate(self.cells) if c.id==before), None)\n",
" else: idx = len(self.cells)\n",
Expand Down Expand Up @@ -3444,6 +3491,60 @@
"rows"
]
},
{
"cell_type": "markdown",
"id": "9ddf85ef",
"metadata": {},
"source": [
"`del_cells` is the transaction form of `remove`: it deletes by id in the notebook at `path`, saves, and returns `CellRow` snapshots of the removed cells:"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "2a645b36",
"metadata": {},
"outputs": [],
"source": [
"#| export\n",
"def del_cells(\n",
" path, # Notebook file to modify\n",
" *ids, # Cell ids (exact or unique prefix) or indexes\n",
"):\n",
" \"Delete cells from the notebook at `path`, returning `CellRow` snapshots of the removed cells\"\n",
" nb = Notebook.open(path)\n",
" res = nb.remove(*ids)\n",
" nb.save()\n",
" return CellRows(CellRow(c) for c in res)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "b3995434",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"aa11:c:a=1\n",
"cc33:c:c=3"
]
},
"execution_count": 139,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"tp = Path('tmp_del.ipynb')\n",
"write_nb(new_nb([mk_cell('a=1', id='aa11'), mk_cell('b=2', id='bb22'), mk_cell('c=3', id='cc33')]), tp)\n",
"rows = del_cells(tp, 'aa11', 'cc')\n",
"test_eq([c.id for c in read_nb(tp).cells], ['bb22'])\n",
"tp.unlink()\n",
"rows"
]
},
{
"cell_type": "markdown",
"id": "f215aa99",
Expand Down