{ "cells": [ { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "#|hide\n", "#|default_exp export" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# export\n", "> Exporting a notebook to a library" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "#|export\n", "from nbdev.config import *\n", "from nbdev.maker import *\n", "from nbdev.imports import *\n", "from nbdev.process import *\n", "\n", "from fastcore.script import *\n", "from fastcore.basics import *\n", "from fastcore.imports import *\n", "\n", "from collections import defaultdict" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "#|hide\n", "from fastcore.test import *\n", "from pdb import set_trace\n", "from importlib import reload\n", "from fastcore import shutil\n", "from execnb.nbio import read_nb" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "#|export\n", "class ExportModuleProc:\n", " \"A processor which exports code to a module\"\n", " def begin(self): self.modules,self.in_all = defaultdict(L),defaultdict(L)\n", " def _default_exp_(self, cell, exp_to): self.default_exp = exp_to\n", " def _exporti_(self, cell, exp_to=None): self.modules[ifnone(exp_to, '#')].append(cell)\n", " def _export_(self, cell, exp_to=None):\n", " self._exporti_(cell, exp_to)\n", " self.in_all[ifnone(exp_to, '#')].append(cell)\n", " _exports_=_export_" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Specify `dest` where the module(s) will be exported to, and optionally a class to use to create the module (`ModuleMaker`, by default).\n", "\n", "Exported cells are stored in a `dict` called `modules`, where the keys are the modules exported to. Those without an explicit module are stored in the `'#'` key, which will be exported to `default_exp`." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "everything_fn = '..//tests/01_everything.ipynb'\n", "\n", "exp = ExportModuleProc()\n", "proc = NBProcessor(everything_fn, exp)\n", "proc.process()\n", "test_eq(exp.default_exp, 'everything')\n", "assert 'print_function' in exp.modules['#'][0].source\n", "assert 'h_n' in exp.in_all['some.thing'][0].source" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "#|export\n", "def black_format(cell, # Cell to format\n", " force=False): # Turn black formatting on regardless of settings.ini\n", " \"Processor to format code with `black`\"\n", " try: cfg = get_config()\n", " except FileNotFoundError: return\n", " if (str(cfg.get('black_formatting')).lower() != 'true' and not force) or cell.cell_type != 'code': return\n", " try: import black\n", " except: raise ImportError(\"You must install black: `pip install black` if you wish to use black formatting with nbdev\")\n", " else:\n", " _format_str = partial(black.format_str, mode = black.Mode())\n", " try: cell.source = _format_str(cell.source).strip()\n", " except: pass" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "_cell = read_nb('..//tests/black.ipynb')['cells'][0]\n", "black_format(_cell, force=True)\n", "test_eq(_cell.source, 'j = [1, 2, 3]')" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "#|export\n", "def nb_export(nbname, lib_path=None, procs=black_format, debug=False, mod_maker=ModuleMaker):\n", " \"Create module(s) from notebook\"\n", " if lib_path is None: lib_path = get_config().path('lib_path')\n", " exp = ExportModuleProc()\n", " nb = NBProcessor(nbname, [exp]+L(procs), debug=debug)\n", " nb.process()\n", " for mod,cells in exp.modules.items():\n", " all_cells = exp.in_all[mod]\n", " name = getattr(exp, 'default_exp', None) if mod=='#' else mod\n", " if not name:\n", " warn(f\"Notebook '{nbname}' uses `#|export` without `#|default_exp` cell.\\n\"\n", " \"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=name, nb_path=nbname, is_new=mod=='#')\n", " mm.make(cells, all_cells, lib_path=lib_path)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's check we can import a test file:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "#|eval: false\n", "shutil.rmtree('tmp', ignore_errors=True)\n", "nb_export('..//tests/00_some.thing.ipynb', 'tmp')\n", "\n", "g = exec_new('import tmp.some.thing')\n", "test_eq(g['tmp'].some.thing.__all__, ['a'])\n", "test_eq(g['tmp'].some.thing.a, 1)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We'll also check that our 'everything' file exports correctly:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "#|eval: false\n", "nb_export(everything_fn, 'tmp')\n", "\n", "g = exec_new('import tmp.everything; from tmp.everything import *')\n", "_alls = L(\"a b d e m n o p q\".split())\n", "for s in _alls.map(\"{}_y\"): assert s in g, s\n", "for s in \"c_y_nall _f_y_nall g_n h_n i_n j_n k_n l_n\".split(): assert s not in g, s\n", "for s in _alls.map(\"{}_y\") + [\"c_y_nall\", \"_f_y_nall\"]: assert hasattr(g['tmp'].everything,s), s" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "That notebook should also export one extra function to `tmp.some.thing`:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "#|eval: false\n", "del(sys.modules['tmp.some.thing']) # remove from module cache\n", "g = exec_new('import tmp.some.thing')\n", "test_eq(g['tmp'].some.thing.__all__, ['a','h_n'])\n", "test_eq(g['tmp'].some.thing.h_n(), None)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Export -" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "#|eval: false\n", "Path('../nbdev/export.py').unlink(missing_ok=True)\n", "nb_export('04a_export.ipynb')\n", "\n", "g = exec_new('import nbdev.export')\n", "assert hasattr(g['nbdev'].export, 'nb_export')" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" } }, "nbformat": 4, "nbformat_minor": 4 }