|
164 | 164 | "outputs": [], |
165 | 165 | "source": [ |
166 | 166 | "#| export\n", |
167 | | - "def _clean_cell_output(cell, clean_ids):\n", |
| 167 | + "def _clean_cell_output(cell, clean_ids, allowed_out_meta_keys):\n", |
168 | 168 | " \"Remove `cell` output execution count and optionally ids from text reprs\"\n", |
169 | 169 | " outputs = cell.get('outputs', [])\n", |
170 | 170 | " for o in outputs:\n", |
|
175 | 175 | " if k.startswith('text') and clean_ids: data[k] = _clean_cell_output_id(data[k])\n", |
176 | 176 | " if k.startswith('image') and \"svg\" not in k: data[k] = data[k].rstrip()\n", |
177 | 177 | " if 'text' in o and clean_ids: o['text'] = _clean_cell_output_id(o['text'])\n", |
178 | | - "# o.get('metadata', {}).pop('tags', None)" |
| 178 | + " if 'metadata' in o: o['metadata'] = {k:v for k,v in o['metadata'].items() if k in allowed_out_meta_keys}" |
179 | 179 | ] |
180 | 180 | }, |
181 | 181 | { |
|
186 | 186 | "outputs": [], |
187 | 187 | "source": [ |
188 | 188 | "#| export\n", |
189 | | - "def _clean_cell(cell, clear_all, allowed_metadata_keys, clean_ids):\n", |
| 189 | + "def _clean_cell(cell, clear_all, allowed_metadata_keys, clean_ids, allowed_out_meta_keys):\n", |
190 | 190 | " \"Clean `cell` by removing superfluous metadata or everything except the input if `clear_all`\"\n", |
191 | 191 | " if 'execution_count' in cell: cell['execution_count'] = None\n", |
192 | 192 | " if 'outputs' in cell:\n", |
193 | 193 | " if clear_all: cell['outputs'] = []\n", |
194 | | - " else: _clean_cell_output(cell, clean_ids)\n", |
| 194 | + " else: _clean_cell_output(cell, clean_ids, allowed_out_meta_keys)\n", |
195 | 195 | " if cell['source'] == ['']: cell['source'] = []\n", |
196 | 196 | " cell['metadata'] = {} if clear_all else {\n", |
197 | 197 | " k:v for k,v in cell['metadata'].items() if k in allowed_metadata_keys}\n", |
|
212 | 212 | " allowed_metadata_keys:list=None, # Preserve the list of keys in the main notebook metadata\n", |
213 | 213 | " allowed_cell_metadata_keys:list=None, # Preserve the list of keys in cell level metadata\n", |
214 | 214 | " clean_ids=True, # Remove ids from plaintext reprs?\n", |
| 215 | + " allowed_out_metadata_keys:list=None, # Preserve the list of keys in output metadata\n", |
215 | 216 | "):\n", |
216 | 217 | " \"Clean `nb` from superfluous metadata\"\n", |
217 | 218 | " metadata_keys = {\"kernelspec\", \"jekyll\", \"jupytext\", \"doc\", \"widgets\"}\n", |
218 | 219 | " if allowed_metadata_keys: metadata_keys.update(allowed_metadata_keys)\n", |
219 | 220 | " cell_metadata_keys = {\"hide_input\"}\n", |
220 | 221 | " if allowed_cell_metadata_keys: cell_metadata_keys.update(allowed_cell_metadata_keys)\n", |
221 | | - " for c in nb['cells']: _clean_cell(c, clear_all, cell_metadata_keys, clean_ids)\n", |
| 222 | + " out_meta_keys = set()\n", |
| 223 | + " if allowed_out_metadata_keys: out_meta_keys.update(allowed_out_metadata_keys)\n", |
| 224 | + " for c in nb['cells']: _clean_cell(c, clear_all, cell_metadata_keys, clean_ids, out_meta_keys)\n", |
222 | 225 | " if nb.get('metadata', {}).get('kernelspec', {}).get('name', None):\n", |
223 | 226 | " nb['metadata']['kernelspec']['display_name'] = nb[\"metadata\"][\"kernelspec\"][\"name\"]\n", |
224 | 227 | " nb['metadata'] = {k:v for k,v in nb['metadata'].items() if k in metadata_keys}\n", |
|
369 | 372 | { |
370 | 373 | "data": { |
371 | 374 | "text/plain": [ |
372 | | - "'b3c0571e'" |
| 375 | + "'88ba1c41'" |
373 | 376 | ] |
374 | 377 | }, |
375 | | - "execution_count": null, |
| 378 | + "execution_count": 77, |
376 | 379 | "metadata": {}, |
377 | 380 | "output_type": "execute_result" |
378 | 381 | } |
379 | 382 | ], |
380 | 383 | "source": [ |
381 | 384 | "test_cell = {'source': 'x=1', 'cell_type': 'code', 'metadata': {}}\n", |
382 | | - "_clean_cell(test_cell, False, set(), True)\n", |
| 385 | + "_clean_cell(test_cell, False, set(), True, set())\n", |
383 | 386 | "test_cell['id']" |
384 | 387 | ] |
385 | 388 | }, |
|
438 | 441 | " clear_all = clear_all or cfg.clear_all\n", |
439 | 442 | " allowed_metadata_keys = cfg.get(\"allowed_metadata_keys\") or []\n", |
440 | 443 | " allowed_cell_metadata_keys = cfg.get(\"allowed_cell_metadata_keys\") or []\n", |
441 | | - " clean_nb(nb, clear_all, allowed_metadata_keys, allowed_cell_metadata_keys, cfg.clean_ids)\n", |
| 444 | + " allowed_out_metadata_keys = cfg.get(\"allowed_out_metadata_keys\") or []\n", |
| 445 | + " clean_nb(nb, clear_all, allowed_metadata_keys, allowed_cell_metadata_keys, cfg.clean_ids, allowed_out_metadata_keys)\n", |
442 | 446 | " if path: nbdev_trust.__wrapped__(path)" |
443 | 447 | ] |
444 | 448 | }, |
|
474 | 478 | "By default (`fname` left to `None`), all the notebooks in `config.nbs_path` are cleaned. You can opt in to fully clean the notebook by removing every bit of metadata and the cell outputs by passing `clear_all=True`.\n", |
475 | 479 | "\n", |
476 | 480 | "If you want to keep some keys in the main notebook metadata you can set `allowed_metadata_keys` in `[tool.nbdev]` in `pyproject.toml`.\n", |
477 | | - "Similarly for cell level metadata use: `allowed_cell_metadata_keys`. For example, to preserve both `k1` and `k2` at both the notebook and cell level add the following to `pyproject.toml`:\n", |
| 481 | + "Similarly for cell level metadata use `allowed_cell_metadata_keys`, and for output metadata use `allowed_out_metadata_keys`. For example, to preserve both `k1` and `k2` at both the notebook and cell level add the following to `pyproject.toml`:\n", |
478 | 482 | "```toml\n", |
479 | 483 | "[tool.nbdev]\n", |
480 | 484 | "allowed_metadata_keys = [\"k1\", \"k2\"]\n", |
481 | 485 | "allowed_cell_metadata_keys = [\"k1\", \"k2\"]\n", |
| 486 | + "allowed_out_metadata_keys = [\"k1\", \"k2\"]\n", |
482 | 487 | "```" |
483 | 488 | ] |
484 | 489 | }, |
|
620 | 625 | { |
621 | 626 | "data": { |
622 | 627 | "text/markdown": [ |
| 628 | + "<div class=\"prose\">\n", |
| 629 | + "\n", |
623 | 630 | "```python\n", |
624 | 631 | "an_existing_line = True\n", |
625 | 632 | "\n", |
|
629 | 636 | " clean_jupyter(**kwargs)\n", |
630 | 637 | "\n", |
631 | 638 | "c.ContentsManager.pre_save_hook = nbdev_clean_jupyter\n", |
632 | | - "```" |
| 639 | + "```\n", |
| 640 | + "\n", |
| 641 | + "</div>" |
633 | 642 | ], |
634 | 643 | "text/plain": [ |
635 | | - "<IPython.core.display.Markdown object>" |
| 644 | + "Markdown(```python\n", |
| 645 | + "an_existing_line = True\n", |
| 646 | + "\n", |
| 647 | + "def nbdev_clean_jupyter(**kwargs):\n", |
| 648 | + " try: from nbdev.clean import clean_jupyter\n", |
| 649 | + " except ModuleNotFoundError: return\n", |
| 650 | + " clean_jupyter(**kwargs)\n", |
| 651 | + "\n", |
| 652 | + "c.ContentsManager.pre_save_hook = nbdev_clean_jupyter\n", |
| 653 | + "```)" |
636 | 654 | ] |
637 | 655 | }, |
638 | | - "execution_count": null, |
| 656 | + "execution_count": 89, |
639 | 657 | "metadata": {}, |
640 | 658 | "output_type": "execute_result" |
641 | 659 | } |
|
711 | 729 | " os.chmod(fn, os.stat(fn).st_mode | stat.S_IEXEC)\n", |
712 | 730 | "\n", |
713 | 731 | " cmd = 'git config --local include.path ../.gitconfig'\n", |
714 | | - " (repo_path/'.gitconfig').write_text(f'''# Generated by nbdev_install_hooks\n", |
| 732 | + " (repo_path/'.gitconfig').write_text(f'''# Generated by nbdev-install-hooks\n", |
715 | 733 | "#\n", |
716 | 734 | "# If you need to disable this instrumentation do:\n", |
717 | 735 | "# git config --local --unset include.path\n", |
|
863 | 881 | " nbs_path = Path('nbs')\n", |
864 | 882 | " nbs_path.mkdir()\n", |
865 | 883 | " Path('pyproject.toml').write_text('[tool.nbdev]\\\\nnbs_path = \"nbs\"')\n", |
866 | | - " _run('nbdev_install_hooks')\n", |
| 884 | + " _run('nbdev-install-hooks')\n", |
867 | 885 | " \n", |
868 | 886 | " fn = 'random.ipynb'\n", |
869 | 887 | " p = nbs_path/fn\n", |
|
917 | 935 | ] |
918 | 936 | } |
919 | 937 | ], |
920 | | - "metadata": {}, |
| 938 | + "metadata": { |
| 939 | + "solveit_dialog_mode": "concise", |
| 940 | + "solveit_ver": 2 |
| 941 | + }, |
921 | 942 | "nbformat": 4, |
922 | 943 | "nbformat_minor": 5 |
923 | 944 | } |
0 commit comments