├── myfile ├── nbs ├── nbdev ├── .gitattributes ├── images │ ├── logo.png │ ├── merge.PNG │ ├── att_00000.png │ ├── att_00001.png │ ├── att_00002.png │ ├── att_00003.png │ ├── att_00004.png │ ├── att_00005.png │ ├── att_00006.png │ ├── att_00007.png │ ├── att_00008.png │ ├── att_00009.png │ ├── att_00010.png │ ├── att_00011.png │ ├── att_00012.png │ ├── att_00013.png │ ├── att_00014.png │ ├── att_00015.png │ ├── att_00016.png │ ├── att_00017.png │ ├── att_00018.png │ ├── att_00019.png │ ├── att_00020.png │ ├── att_00021.png │ ├── att_00022.png │ ├── att_00023.png │ ├── att_00024.png │ ├── att_00025.png │ ├── att_00026.png │ ├── att_00027.png │ ├── doc_example.png │ ├── nbdev_source.gif │ ├── export_example.png │ ├── inspect_magics.png │ ├── split_flags_and_code.png │ └── split_flags_and_code_magic.png ├── 99_search.ipynb ├── index.ipynb ├── nbdev_comments.ipynb └── 07_clean.ipynb ├── docs ├── CNAME ├── .gitignore ├── googlece7909add426d938.html ├── images │ ├── merge.PNG │ ├── merge.jpg │ ├── favicon.ico │ ├── att_00010.png │ ├── att_00011.png │ ├── att_00012.png │ ├── att_00016.png │ ├── att_00017.png │ ├── att_00018.png │ ├── att_00019.png │ ├── att_00021.png │ ├── att_00022.png │ ├── att_00023.png │ ├── att_00024.png │ ├── att_00025.png │ ├── att_00026.png │ ├── att_00027.png │ ├── company_logo.png │ ├── doc_example.png │ ├── nbdev_source.gif │ ├── export_example.png │ ├── inspect_magics.png │ ├── workflowarrow.png │ ├── company_logo_big.png │ ├── split_flags_and_code.png │ ├── split_flags_and_code_magic.png │ └── colab.svg ├── _data │ ├── topnav.yml │ └── sidebars │ │ └── home_sidebar.yml ├── Gemfile ├── tooltips.json ├── Untitled.ipynb ├── sitemap.xml ├── sidebar.json ├── search-template.txt ├── _config.yml ├── feed.xml ├── search.html ├── try_save.html ├── index.html └── test.html ├── PRE_README.md ├── nbdev ├── version.py ├── all.py ├── __init__.py ├── templates │ ├── md.tpl │ ├── autogen.tpl │ ├── hide-md.tpl │ ├── jekyll.tpl │ ├── jekyll-md.tpl │ └── hide.tpl ├── nbdev_comments.py ├── tutorial.py ├── template.py ├── imports.py ├── clean.py ├── merge.py ├── cli.py ├── test.py ├── _nbdev.py └── sync.py ├── MANIFEST.in ├── tests ├── print_in_ipython.py ├── single-cell-index.ipynb └── 07_clean.ipynb ├── .github └── workflows │ ├── changelog.yml │ ├── welcome.yml.off │ └── main.yml ├── .devcontainer.json ├── Makefile ├── docker-compose.yml ├── settings.ini ├── .gitignore ├── setup.py ├── CODE_OF_CONDUCT.md ├── README.md ├── CONTRIBUTING.md ├── CHANGELOG.md └── LICENSE /myfile: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /nbs/nbdev: -------------------------------------------------------------------------------- 1 | ../nbdev -------------------------------------------------------------------------------- /docs/CNAME: -------------------------------------------------------------------------------- 1 | nbdev1.fast.ai 2 | -------------------------------------------------------------------------------- /docs/.gitignore: -------------------------------------------------------------------------------- 1 | _site/ 2 | .netlify/ 3 | Gemfile.lock 4 | -------------------------------------------------------------------------------- /nbs/.gitattributes: -------------------------------------------------------------------------------- 1 | **/*.ipynb filter=clean-nbs 2 | **/*.ipynb diff=ipynb 3 | -------------------------------------------------------------------------------- /PRE_README.md: -------------------------------------------------------------------------------- 1 | ![](https://github.com/fastai/nbdev/workflows/CI/badge.svg) 2 | 3 | -------------------------------------------------------------------------------- /docs/googlece7909add426d938.html: -------------------------------------------------------------------------------- 1 | google-site-verification: googlece7909add426d938.html -------------------------------------------------------------------------------- /docs/images/merge.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastai/nbdev1/master/docs/images/merge.PNG -------------------------------------------------------------------------------- /docs/images/merge.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastai/nbdev1/master/docs/images/merge.jpg -------------------------------------------------------------------------------- /nbs/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastai/nbdev1/master/nbs/images/logo.png -------------------------------------------------------------------------------- /nbs/images/merge.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastai/nbdev1/master/nbs/images/merge.PNG -------------------------------------------------------------------------------- /docs/images/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastai/nbdev1/master/docs/images/favicon.ico -------------------------------------------------------------------------------- /docs/images/att_00010.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastai/nbdev1/master/docs/images/att_00010.png -------------------------------------------------------------------------------- /docs/images/att_00011.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastai/nbdev1/master/docs/images/att_00011.png -------------------------------------------------------------------------------- /docs/images/att_00012.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastai/nbdev1/master/docs/images/att_00012.png -------------------------------------------------------------------------------- /docs/images/att_00016.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastai/nbdev1/master/docs/images/att_00016.png -------------------------------------------------------------------------------- /docs/images/att_00017.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastai/nbdev1/master/docs/images/att_00017.png -------------------------------------------------------------------------------- /docs/images/att_00018.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastai/nbdev1/master/docs/images/att_00018.png -------------------------------------------------------------------------------- /docs/images/att_00019.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastai/nbdev1/master/docs/images/att_00019.png -------------------------------------------------------------------------------- /docs/images/att_00021.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastai/nbdev1/master/docs/images/att_00021.png -------------------------------------------------------------------------------- /docs/images/att_00022.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastai/nbdev1/master/docs/images/att_00022.png -------------------------------------------------------------------------------- /docs/images/att_00023.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastai/nbdev1/master/docs/images/att_00023.png -------------------------------------------------------------------------------- /docs/images/att_00024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastai/nbdev1/master/docs/images/att_00024.png -------------------------------------------------------------------------------- /docs/images/att_00025.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastai/nbdev1/master/docs/images/att_00025.png -------------------------------------------------------------------------------- /docs/images/att_00026.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastai/nbdev1/master/docs/images/att_00026.png -------------------------------------------------------------------------------- /docs/images/att_00027.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastai/nbdev1/master/docs/images/att_00027.png -------------------------------------------------------------------------------- /nbs/images/att_00000.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastai/nbdev1/master/nbs/images/att_00000.png -------------------------------------------------------------------------------- /nbs/images/att_00001.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastai/nbdev1/master/nbs/images/att_00001.png -------------------------------------------------------------------------------- /nbs/images/att_00002.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastai/nbdev1/master/nbs/images/att_00002.png -------------------------------------------------------------------------------- /nbs/images/att_00003.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastai/nbdev1/master/nbs/images/att_00003.png -------------------------------------------------------------------------------- /nbs/images/att_00004.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastai/nbdev1/master/nbs/images/att_00004.png -------------------------------------------------------------------------------- /nbs/images/att_00005.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastai/nbdev1/master/nbs/images/att_00005.png -------------------------------------------------------------------------------- /nbs/images/att_00006.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastai/nbdev1/master/nbs/images/att_00006.png -------------------------------------------------------------------------------- /nbs/images/att_00007.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastai/nbdev1/master/nbs/images/att_00007.png -------------------------------------------------------------------------------- /nbs/images/att_00008.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastai/nbdev1/master/nbs/images/att_00008.png -------------------------------------------------------------------------------- /nbs/images/att_00009.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastai/nbdev1/master/nbs/images/att_00009.png -------------------------------------------------------------------------------- /nbs/images/att_00010.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastai/nbdev1/master/nbs/images/att_00010.png -------------------------------------------------------------------------------- /nbs/images/att_00011.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastai/nbdev1/master/nbs/images/att_00011.png -------------------------------------------------------------------------------- /nbs/images/att_00012.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastai/nbdev1/master/nbs/images/att_00012.png -------------------------------------------------------------------------------- /nbs/images/att_00013.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastai/nbdev1/master/nbs/images/att_00013.png -------------------------------------------------------------------------------- /nbs/images/att_00014.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastai/nbdev1/master/nbs/images/att_00014.png -------------------------------------------------------------------------------- /nbs/images/att_00015.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastai/nbdev1/master/nbs/images/att_00015.png -------------------------------------------------------------------------------- /nbs/images/att_00016.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastai/nbdev1/master/nbs/images/att_00016.png -------------------------------------------------------------------------------- /nbs/images/att_00017.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastai/nbdev1/master/nbs/images/att_00017.png -------------------------------------------------------------------------------- /nbs/images/att_00018.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastai/nbdev1/master/nbs/images/att_00018.png -------------------------------------------------------------------------------- /nbs/images/att_00019.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastai/nbdev1/master/nbs/images/att_00019.png -------------------------------------------------------------------------------- /nbs/images/att_00020.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastai/nbdev1/master/nbs/images/att_00020.png -------------------------------------------------------------------------------- /nbs/images/att_00021.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastai/nbdev1/master/nbs/images/att_00021.png -------------------------------------------------------------------------------- /nbs/images/att_00022.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastai/nbdev1/master/nbs/images/att_00022.png -------------------------------------------------------------------------------- /nbs/images/att_00023.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastai/nbdev1/master/nbs/images/att_00023.png -------------------------------------------------------------------------------- /nbs/images/att_00024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastai/nbdev1/master/nbs/images/att_00024.png -------------------------------------------------------------------------------- /nbs/images/att_00025.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastai/nbdev1/master/nbs/images/att_00025.png -------------------------------------------------------------------------------- /nbs/images/att_00026.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastai/nbdev1/master/nbs/images/att_00026.png -------------------------------------------------------------------------------- /nbs/images/att_00027.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastai/nbdev1/master/nbs/images/att_00027.png -------------------------------------------------------------------------------- /nbs/images/doc_example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastai/nbdev1/master/nbs/images/doc_example.png -------------------------------------------------------------------------------- /docs/images/company_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastai/nbdev1/master/docs/images/company_logo.png -------------------------------------------------------------------------------- /docs/images/doc_example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastai/nbdev1/master/docs/images/doc_example.png -------------------------------------------------------------------------------- /docs/images/nbdev_source.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastai/nbdev1/master/docs/images/nbdev_source.gif -------------------------------------------------------------------------------- /nbs/images/nbdev_source.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastai/nbdev1/master/nbs/images/nbdev_source.gif -------------------------------------------------------------------------------- /docs/images/export_example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastai/nbdev1/master/docs/images/export_example.png -------------------------------------------------------------------------------- /docs/images/inspect_magics.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastai/nbdev1/master/docs/images/inspect_magics.png -------------------------------------------------------------------------------- /docs/images/workflowarrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastai/nbdev1/master/docs/images/workflowarrow.png -------------------------------------------------------------------------------- /nbs/images/export_example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastai/nbdev1/master/nbs/images/export_example.png -------------------------------------------------------------------------------- /nbs/images/inspect_magics.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastai/nbdev1/master/nbs/images/inspect_magics.png -------------------------------------------------------------------------------- /docs/images/company_logo_big.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastai/nbdev1/master/docs/images/company_logo_big.png -------------------------------------------------------------------------------- /docs/images/split_flags_and_code.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastai/nbdev1/master/docs/images/split_flags_and_code.png -------------------------------------------------------------------------------- /nbdev/version.py: -------------------------------------------------------------------------------- 1 | from . import imports 2 | __all__ = ['__version__'] 3 | __version__ = imports.get_config().version 4 | -------------------------------------------------------------------------------- /nbs/images/split_flags_and_code.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastai/nbdev1/master/nbs/images/split_flags_and_code.png -------------------------------------------------------------------------------- /nbs/images/split_flags_and_code_magic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastai/nbdev1/master/nbs/images/split_flags_and_code_magic.png -------------------------------------------------------------------------------- /docs/images/split_flags_and_code_magic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fastai/nbdev1/master/docs/images/split_flags_and_code_magic.png -------------------------------------------------------------------------------- /nbdev/all.py: -------------------------------------------------------------------------------- 1 | from fastcore.utils import IN_IPYTHON 2 | 3 | if IN_IPYTHON: 4 | from .flags import * 5 | from .showdoc import * 6 | from .export import * 7 | 8 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include CONTRIBUTING.md 2 | include LICENSE 3 | include README.md 4 | include nbdev/templates/*tpl 5 | include settings.ini 6 | 7 | recursive-exclude * __pycache__ 8 | -------------------------------------------------------------------------------- /nbdev/__init__.py: -------------------------------------------------------------------------------- 1 | __version__ = "1.2.12" 2 | 3 | from fastcore.imports import IN_IPYTHON 4 | from .imports import * 5 | 6 | if IN_IPYTHON: 7 | from .showdoc import show_doc 8 | -------------------------------------------------------------------------------- /tests/print_in_ipython.py: -------------------------------------------------------------------------------- 1 | from nbdev.imports import IN_IPYTHON 2 | # 1st print in ipython gets appended with rubbish like \x1b[22;0t\x1b]0;IPython 3 | print('ignore') 4 | # so we'll only pay attention to the 2nd print 5 | print(IN_IPYTHON) -------------------------------------------------------------------------------- /docs/_data/topnav.yml: -------------------------------------------------------------------------------- 1 | topnav: 2 | - title: Topnav 3 | items: 4 | - title: github 5 | external_url: https://github.com/fastai/nbdev/tree/master/ 6 | 7 | #Topnav dropdowns 8 | topnav_dropdowns: 9 | - title: Topnav dropdowns 10 | folders: -------------------------------------------------------------------------------- /docs/Gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | 3 | gem 'github-pages', group: :jekyll_plugins 4 | 5 | # Added at 2019-11-25 10:11:40 -0800 by jhoward: 6 | gem "jekyll", ">= 3.7" 7 | gem "kramdown", ">= 2.3.1" 8 | gem "jekyll-remote-theme" 9 | 10 | gem "webrick", "~> 1.7" 11 | -------------------------------------------------------------------------------- /nbdev/templates/md.tpl: -------------------------------------------------------------------------------- 1 | {%- extends 'hide-md.tpl' -%}{% block body %} 2 | {% if resources.title != "" and resources.title != nil %}# {{resources.title}}{% endif %} 3 | {% if resources.summary != "" and resources.summary != nil %}> {{resources.summary}}{% endif %} 4 | 5 | {{ super() }} 6 | {%- endblock body %} 7 | 8 | -------------------------------------------------------------------------------- /nbdev/templates/autogen.tpl: -------------------------------------------------------------------------------- 1 | 10 | -------------------------------------------------------------------------------- /docs/tooltips.json: -------------------------------------------------------------------------------- 1 | --- 2 | layout: null 3 | search: exclude 4 | --- 5 | 6 | { 7 | "entries": 8 | [ 9 | {% for page in site.tooltips %} 10 | { 11 | "doc_id": "{{ page.doc_id }}", 12 | "body": "{{ page.content | strip_newlines | replace: '\', '\\\\' | replace: '"', '\\"' }}" 13 | } {% unless forloop.last %},{% endunless %} 14 | {% endfor %} 15 | ] 16 | } 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /.github/workflows/changelog.yml: -------------------------------------------------------------------------------- 1 | #.github/workflows/changelog.yaml 2 | name: changelog 3 | on: workflow_dispatch 4 | jobs: 5 | build: 6 | runs-on: ubuntu-latest 7 | steps: 8 | - uses: actions/checkout@v2 9 | - name: Update CHANGELOG.md 10 | uses: fastai/fastrelease/action/changelog@master 11 | with: 12 | TOKEN: ${{ secrets.GITHUB_TOKEN }} 13 | -------------------------------------------------------------------------------- /nbdev/nbdev_comments.py: -------------------------------------------------------------------------------- 1 | # AUTOGENERATED! DO NOT EDIT! File to edit: nbs/nbdev_comments.ipynb (unless otherwise specified). 2 | 3 | __all__ = ['S1', 'S2'] 4 | 5 | # Cell 6 | class S1(): 7 | def __init__(self, *args, **kwargs): 8 | pass 9 | 10 | # Cell 11 | class S2(): 12 | def __init__(self, *args, **kwargs): 13 | pass 14 | 15 | # Internal Cell 16 | class S3(): 17 | def __init__(self, *args, **kwargs): 18 | pass -------------------------------------------------------------------------------- /nbdev/tutorial.py: -------------------------------------------------------------------------------- 1 | # AUTOGENERATED! DO NOT EDIT! File to edit: nbs/tutorial.ipynb (unless otherwise specified). 2 | 3 | __all__ = ['say_hello', 'HelloSayer'] 4 | 5 | # Cell 6 | def say_hello(to): 7 | "Say hello to somebody" 8 | return f'Hello {to}!' 9 | 10 | # Cell 11 | class HelloSayer: 12 | "Say hello to `to` using `say_hello`" 13 | def __init__(self, to): self.to = to 14 | 15 | def say(self): 16 | "Do the saying" 17 | return say_hello(self.to) -------------------------------------------------------------------------------- /tests/single-cell-index.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Index page with no markdown cells to write to README.md\n", 8 | "\n", 9 | "> See: https://github.com/fastai/nbdev/issues/175" 10 | ] 11 | } 12 | ], 13 | "metadata": { 14 | "kernelspec": { 15 | "display_name": "Python 3", 16 | "language": "python", 17 | "name": "python3" 18 | } 19 | }, 20 | "nbformat": 4, 21 | "nbformat_minor": 4 22 | } 23 | -------------------------------------------------------------------------------- /docs/Untitled.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": null, 6 | "id": "f9e21b4f-1b14-4dbc-abd0-d2d8bdbf543f", 7 | "metadata": {}, 8 | "outputs": [], 9 | "source": [] 10 | } 11 | ], 12 | "metadata": { 13 | "kernelspec": { 14 | "display_name": "Python 3.9.7 ('base')", 15 | "language": "python", 16 | "name": "python397jvsc74a57bd042fd40e048e0585f88ec242f050f7ef0895cf845a8dd1159352394e5826cd102" 17 | } 18 | }, 19 | "nbformat": 4, 20 | "nbformat_minor": 5 21 | } 22 | -------------------------------------------------------------------------------- /.devcontainer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nbdev-codespaces", 3 | "dockerComposeFile": "docker-compose.yml", 4 | "service": "watcher", 5 | "settings": {"terminal.integrated.shell.linux": "/bin/bash"}, 6 | "mounts": [ "source=/var/run/docker.sock,target=/var/run/docker.sock,type=bind" ], 7 | "forwardPorts": [4000, 8080], 8 | "appPort": [4000, 8080], 9 | "extensions": ["ms-python.python", 10 | "ms-azuretools.vscode-docker"], 11 | "runServices": ["notebook", "jekyll", "watcher"], 12 | "postStartCommand": "pip install -e ." 13 | } 14 | -------------------------------------------------------------------------------- /docs/sitemap.xml: -------------------------------------------------------------------------------- 1 | --- 2 | layout: none 3 | search: exclude 4 | --- 5 | 6 | 7 | 8 | {% for post in site.posts %} 9 | {% unless post.search == "exclude" %} 10 | 11 | {{site.url}}{{post.url}} 12 | 13 | {% endunless %} 14 | {% endfor %} 15 | 16 | 17 | {% for page in site.pages %} 18 | {% unless page.search == "exclude" %} 19 | 20 | {{site.url}}{{ page.url}} 21 | 22 | {% endunless %} 23 | {% endfor %} 24 | -------------------------------------------------------------------------------- /docs/sidebar.json: -------------------------------------------------------------------------------- 1 | { 2 | "nbdev": { 3 | "Overview": "/", 4 | "": { 5 | "Tutorials": { 6 | "General Tutorial":"tutorial.html", 7 | "Google Colaboratory":"tutorial_colab.html" 8 | } 9 | }, 10 | "A minimal example": "example.html", 11 | "Export to modules": "export.html", 12 | "Synchronize and diff": "sync.html", 13 | "Show doc": "showdoc.html", 14 | "Convert to html": "export2html.html", 15 | "Extract tests": "test.html", 16 | "Fix merge conflicts": "merge.html", 17 | "Command line functions": "cli.html", 18 | "Clean notebooks": "clean.html", 19 | "nbdev comments": "nbdev_comments.html", 20 | "Setting up Search": "search.html" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .ONESHELL: 2 | SHELL := /bin/bash 3 | 4 | SRC = $(wildcard nbs/*.ipynb) 5 | 6 | all: nbdev docs 7 | 8 | nbdev: $(SRC) 9 | nbdev_build_lib 10 | touch nbdev 11 | 12 | docs_serve: docs 13 | cd docs && bundle exec jekyll serve 14 | 15 | docs: $(SRC) 16 | nbdev_build_docs 17 | touch docs 18 | 19 | test: 20 | nbdev_test_nbs --flags '' 21 | 22 | release: pypi 23 | fastrelease_conda_package --mambabuild --upload_user fastai --build_args '-c fastai' 24 | fastrelease_bump_version 25 | 26 | conda_release: 27 | fastrelease_conda_package --mambabuild --upload_user fastai --build_args '-c fastai' 28 | 29 | pypi: dist 30 | twine upload --repository pypi dist/* 31 | 32 | dist: clean 33 | python setup.py sdist bdist_wheel 34 | 35 | clean: 36 | rm -rf dist 37 | 38 | -------------------------------------------------------------------------------- /nbdev/templates/hide-md.tpl: -------------------------------------------------------------------------------- 1 | {%- extends 'markdown/index.md.j2' -%} 2 | 3 | {% block input_group -%} 4 | {%- if cell.metadata.collapse_show -%} 5 |
6 | Code details ... 7 | {{ super() }} 8 |
9 | {{ '' }} 10 | {%- elif cell.metadata.collapse_hide -%} 11 |
12 | Code details ... 13 | {{ super() }} 14 |
15 | {{ '' }} 16 | {%- elif cell.metadata.hide_input or nb.metadata.hide_input -%} 17 | {%- else -%} 18 | {{ super() }} 19 | {%- endif -%} 20 | {% endblock input_group %} 21 | 22 | {% block output_group -%} 23 | {%- if cell.metadata.hide_output -%} 24 | {%- elif cell.metadata.collapse_output -%} 25 |
26 | Output details ... 27 | {{ super() }} 28 |
29 | {{ '' }} 30 | {%- else -%} 31 | {{ super() }} 32 | {%- endif -%} 33 | {% endblock output_group %} -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3" 2 | services: 3 | fastai: &fastai 4 | restart: unless-stopped 5 | working_dir: /data 6 | image: fastai/codespaces 7 | logging: 8 | driver: json-file 9 | options: 10 | max-size: 50m 11 | stdin_open: true 12 | tty: true 13 | volumes: 14 | - .:/data/ 15 | 16 | notebook: 17 | <<: *fastai 18 | command: bash -c "pip install -e . && jupyter notebook --allow-root --no-browser --ip=0.0.0.0 --port=8080 --NotebookApp.token='' --NotebookApp.password=''" 19 | ports: 20 | - "8080:8080" 21 | 22 | watcher: 23 | <<: *fastai 24 | command: watchmedo shell-command --command nbdev_build_docs --pattern *.ipynb --recursive --drop 25 | network_mode: host # for GitHub Codespaces https://github.com/features/codespaces/ 26 | 27 | jekyll: 28 | <<: *fastai 29 | ports: 30 | - "4000:4000" 31 | command: > 32 | bash -c "pip install . 33 | && nbdev_build_docs && cd docs 34 | && bundle i 35 | && chmod -R u+rwx . && bundle exec jekyll serve --host 0.0.0.0" 36 | -------------------------------------------------------------------------------- /.github/workflows/welcome.yml.off: -------------------------------------------------------------------------------- 1 | name: Greet New Contributors 2 | 3 | on: [pull_request_target, issues] 4 | 5 | jobs: 6 | greeting: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - uses: actions/first-interaction@v1 10 | with: 11 | repo-token: ${{ secrets.GITHUB_TOKEN }} 12 | issue-message: "👋 @${{github.actor}}! Thank you for opening your first issue in this repo. We are so happy that you have decided to contribute and value your contribution. Please read these materials before proceeding: [Contributing Guide](https://github.com/fastai/fastai/blob/master/CONTRIBUTING.md) and [Code of Conduct](https://github.com/fastai/fastai/blob/master/CODE_OF_CONDUCT.md)." 13 | pr-message: "👋 @${{github.actor}}! Thank you for opening your first pull request in this repo. We are so happy that you have decided to contribute and value your contribution. Please read these materials before proceeding: [Contributing Guide](https://github.com/fastai/fastai/blob/master/CONTRIBUTING.md) and [Code of Conduct](https://github.com/fastai/fastai/blob/master/CODE_OF_CONDUCT.md)." 14 | 15 | -------------------------------------------------------------------------------- /docs/search-template.txt: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /nbdev/templates/jekyll.tpl: -------------------------------------------------------------------------------- 1 | {%- extends 'hide.tpl' -%}{% block body %}--- 2 | {% if resources.toc != "" and resources.toc != nil %}toc: {{resources.toc}}{% endif %} 3 | {% if resources.title != "" and resources.title != nil %}title: {{resources.title}}{% endif %} 4 | {% if resources.image != "" and resources.image != nil %}image: {{resources.image}}{% endif %} 5 | {% if resources.hide_colab_badge != "" and resources.hide_colab_badge != nil %}hide_colab_badge: {{resources.hide_colab_badge}}{% endif %} 6 | keywords: {{resources.keywords}} 7 | sidebar: home_sidebar 8 | {% if resources.tags != "" and resources.tags != nil %}tags: {{resources.tags}}{% endif %} 9 | {% if resources.summary != "" and resources.summary != nil %}summary: "{{resources.summary}}"{% endif %} 10 | {% if resources.summary != "" and resources.summary != nil %}description: "{{resources.summary}}"{% endif %} 11 | {% if resources.nb_path != "" and resources.nb_path != nil %}nb_path: "{{resources.nb_path}}"{% endif %} 12 | --- 13 | {% include 'autogen.tpl' %} 14 | 15 |
16 | {{ super() }} 17 |
18 | {%- endblock body %} 19 | -------------------------------------------------------------------------------- /nbdev/templates/jekyll-md.tpl: -------------------------------------------------------------------------------- 1 | {%- extends 'hide-md.tpl' -%}{% block body %}--- 2 | {% if resources.title != "" and resources.title != nil %}title: {{resources.title}}{% endif %} 3 | {% if resources.author != "" and resources.author != nil %}author: {{resources.author}}{% endif %} 4 | {% if resources.date != "" and resources.date != nil %}date: {{resources.date}}{% endif %} 5 | {% if resources.tags != "" and resources.tags != nil %}tags: {{resources.tags}}{% endif %} 6 | {% if resources.summary != "" and resources.summary != nil %}summary: "{{resources.summary}}"{% endif %} 7 | {% if resources.summary != "" and resources.summary != nil %}description: "{{resources.summary}}"{% endif %} 8 | --- 9 | 10 | {{ super() }} 11 | {%- endblock body %} 12 | 13 | {% block codecell -%} 14 |
15 | {{ super() }} 16 |
17 | {% endblock codecell %} 18 | 19 | {% block input_group -%} 20 |
21 | {{ super() }} 22 |
23 | {% endblock input_group %} 24 | 25 | {% block output_group -%} 26 |
27 | {{ super() }} 28 |
29 | {% endblock output_group %} 30 | 31 | -------------------------------------------------------------------------------- /docs/_config.yml: -------------------------------------------------------------------------------- 1 | repository: fastai/nbdev 2 | output: web 3 | topnav_title: nbdev 4 | site_title: nbdev 5 | company_name: fast.ai 6 | description: Writing a library entirely in notebooks 7 | google_search: 000837339549978028235:vh0pq0omtgr 8 | use_math: true 9 | google_analytics: 10 | twitter_username: fastdotai 11 | 12 | host: 127.0.0.1 13 | # the preview server used. Leave as is. 14 | port: 4000 15 | # the port where the preview is rendered. 16 | 17 | exclude: 18 | - .idea/ 19 | - .gitignore 20 | - vendor 21 | 22 | exclude: [vendor] 23 | 24 | default_badges: 25 | colab: false 26 | 27 | highlighter: rouge 28 | markdown: kramdown 29 | kramdown: 30 | math_engine: katex 31 | input: GFM 32 | auto_ids: true 33 | hard_wrap: false 34 | syntax_highlighter: rouge 35 | 36 | collections: 37 | tooltips: 38 | output: false 39 | 40 | defaults: 41 | - 42 | scope: 43 | path: "" 44 | type: "pages" 45 | values: 46 | layout: "page" 47 | comments: true 48 | search: true 49 | sidebar: home_sidebar 50 | topnav: topnav 51 | - 52 | scope: 53 | path: "" 54 | type: "tooltips" 55 | values: 56 | layout: "page" 57 | comments: true 58 | search: true 59 | tooltip: true 60 | 61 | sidebars: [home_sidebar] 62 | baseurl: / 63 | plugins: 64 | - jekyll-remote-theme 65 | 66 | remote_theme: fastai/nbdev-jekyll-theme 67 | -------------------------------------------------------------------------------- /docs/feed.xml: -------------------------------------------------------------------------------- 1 | --- 2 | search: exclude 3 | layout: none 4 | --- 5 | 6 | 7 | 8 | 9 | {{ site.title | xml_escape }} 10 | {{ site.description | xml_escape }} 11 | {{ site.url }}/ 12 | 13 | {{ site.time | date_to_rfc822 }} 14 | {{ site.time | date_to_rfc822 }} 15 | Jekyll v{{ jekyll.version }} 16 | {% for post in site.posts limit:10 %} 17 | 18 | {{ post.title | xml_escape }} 19 | {{ post.content | xml_escape }} 20 | {{ post.date | date_to_rfc822 }} 21 | {{ post.url | prepend: site.url }} 22 | {{ post.url | prepend: site.url }} 23 | {% for tag in post.tags %} 24 | {{ tag | xml_escape }} 25 | {% endfor %} 26 | {% for tag in page.tags %} 27 | {{ cat | xml_escape }} 28 | {% endfor %} 29 | 30 | {% endfor %} 31 | 32 | 33 | -------------------------------------------------------------------------------- /nbdev/templates/hide.tpl: -------------------------------------------------------------------------------- 1 | {%- extends 'basic/index.html.j2' -%} 2 | 3 | {% block codecell %} 4 | {{ "{% raw %}" }} 5 | {{ super() }} 6 | {{ "{% endraw %}" }} 7 | {% endblock codecell %} 8 | 9 | {% block input_group -%} 10 | {%- if cell.metadata.collapse_show -%} 11 |
12 | 13 | {{ super() }} 14 |
15 | {%- elif cell.metadata.collapse_hide -%} 16 |
17 | 18 | 19 | {{ super() }} 20 |
21 | {%- elif cell.metadata.hide_input or nb.metadata.hide_input -%} 22 | {%- else -%} 23 | {{ super() }} 24 | {%- endif -%} 25 | {% endblock input_group %} 26 | 27 | {% block output_group -%} 28 | {%- if cell.metadata.hide_output -%} 29 | {%- elif cell.metadata.collapse_output -%} 30 |
31 | 32 | 33 | {{ super() }} 34 |
35 | {%- else -%} 36 | {{ super() }} 37 | {%- endif -%} 38 | {% endblock output_group %} 39 | 40 | {% block output_area_prompt %} 41 | {%- if cell.metadata.hide_input or nb.metadata.hide_input -%} 42 |
43 | {%- else -%} 44 | {{ super() }} 45 | {%- endif -%} 46 | {% endblock output_area_prompt %} 47 | -------------------------------------------------------------------------------- /settings.ini: -------------------------------------------------------------------------------- 1 | [DEFAULT] 2 | host = github 3 | lib_name = nbdev 4 | user = fastai 5 | branch = master 6 | version = 1.2.12 7 | description = Writing a library entirely in notebooks 8 | keywords = jupyter notebook 9 | author = Sylvain Gugger and Jeremy Howard 10 | author_email = info@fast.ai 11 | title = nbdev 12 | copyright = fast.ai 13 | license = apache2 14 | status = 4 15 | min_python = 3.7 16 | audience = Developers 17 | language = English 18 | requirements = fastcore>=1.4.5 nbformat>=4.4.0 nbconvert>=6.1 pyyaml jupyter jupyter_client<8 ipykernel ghapi fastrelease Jinja2 19 | console_scripts = nbdev_build_lib=nbdev.export2html:nbdev_build_lib 20 | nbdev_update_lib=nbdev.sync:nbdev_update_lib 21 | nbdev_diff_nbs=nbdev.sync:nbdev_diff_nbs 22 | nbdev_test_nbs=nbdev.test:nbdev_test_nbs 23 | nbdev_build_docs=nbdev.export2html:nbdev_build_docs 24 | nbdev_nb2md=nbdev.export2html:nbdev_nb2md 25 | nbdev_trust_nbs=nbdev.sync:nbdev_trust_nbs 26 | nbdev_clean_nbs=nbdev.clean:nbdev_clean_nbs 27 | nbdev_read_nbs=nbdev.test:nbdev_read_nbs 28 | nbdev_fix_merge=nbdev.merge:nbdev_fix_merge 29 | nbdev_install_git_hooks=nbdev.cli:nbdev_install_git_hooks 30 | nbdev_bump_version=nbdev.cli:nbdev_bump_version 31 | nbdev_new=nbdev.cli:nbdev_new 32 | nbdev_detach=nbdev.export2html:nbdev_detach 33 | nbs_path = nbs 34 | doc_path = docs 35 | doc_host = https://nbdev.fast.ai 36 | doc_baseurl = / 37 | git_url = https://github.com/fastai/nbdev/tree/master/ 38 | lib_path = nbdev 39 | tst_flags = fastai|slow|colab 40 | custom_sidebar = True 41 | recursive = True 42 | cell_spacing = 1 43 | monospace_docstrings = False 44 | show_all_docments = False 45 | 46 | -------------------------------------------------------------------------------- /docs/_data/sidebars/home_sidebar.yml: -------------------------------------------------------------------------------- 1 | 2 | ################################################# 3 | ### THIS FILE WAS AUTOGENERATED! DO NOT EDIT! ### 4 | ################################################# 5 | # Instead edit ../../sidebar.json 6 | entries: 7 | - folders: 8 | - folderitems: 9 | - output: web,pdf 10 | title: Overview 11 | url: / 12 | subfolders: 13 | - output: web 14 | subfolderitems: 15 | - output: web,pdf 16 | title: General Tutorial 17 | url: tutorial.html 18 | - output: web,pdf 19 | title: Google Colaboratory 20 | url: tutorial_colab.html 21 | title: Tutorials 22 | - output: web,pdf 23 | title: A minimal example 24 | url: example.html 25 | - output: web,pdf 26 | title: Export to modules 27 | url: export.html 28 | - output: web,pdf 29 | title: Synchronize and diff 30 | url: sync.html 31 | - output: web,pdf 32 | title: Show doc 33 | url: showdoc.html 34 | - output: web,pdf 35 | title: Convert to html 36 | url: export2html.html 37 | - output: web,pdf 38 | title: Extract tests 39 | url: test.html 40 | - output: web,pdf 41 | title: Fix merge conflicts 42 | url: merge.html 43 | - output: web,pdf 44 | title: Command line functions 45 | url: cli.html 46 | - output: web,pdf 47 | title: Clean notebooks 48 | url: clean.html 49 | - output: web,pdf 50 | title: nbdev comments 51 | url: nbdev_comments.html 52 | - output: web,pdf 53 | title: Setting up Search 54 | url: search.html 55 | output: web 56 | title: nbdev 57 | output: web 58 | title: Sidebar 59 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: 3 | workflow_dispatch: 4 | pull_request: 5 | push: 6 | branches: [master] 7 | 8 | defaults: 9 | run: 10 | shell: bash 11 | 12 | jobs: 13 | nb-sync: 14 | runs-on: ubuntu-latest 15 | steps: 16 | - uses: actions/checkout@v3 17 | - uses: actions/setup-python@v4 18 | with: 19 | python-version: "3.10" 20 | architecture: "x64" 21 | cache: "pip" 22 | cache-dependency-path: settings.ini 23 | - run: | 24 | pip install -qe . 25 | pip install -Uqq git+https://github.com/fastai/fastcore.git 26 | - name: Check if notebooks are synced and cleaned 27 | uses: fastai/workflows/nb@master 28 | 29 | nbdev_test_nbs: 30 | strategy: 31 | fail-fast: false 32 | matrix: 33 | os: [ubuntu, windows] 34 | py: [3.7, 3.8, 3.9] 35 | runs-on: ${{ matrix.os }}-latest 36 | steps: 37 | - uses: actions/checkout@v2 38 | - name: Set up Python 39 | uses: actions/setup-python@v2 40 | with: 41 | python-version: ${{ matrix.py }} 42 | - name: Setup Environment 43 | run: | 44 | pip install git+https://github.com/fastai/fastcore.git 45 | pip install -qe . 46 | - name: Run tests 47 | run: make test 48 | 49 | fastpages-integration: 50 | env: 51 | HOME: /root 52 | runs-on: ubuntu-latest 53 | container: fastai/jekyll 54 | steps: 55 | - uses: actions/checkout@v2 56 | - name: Install nbdev 57 | run: | 58 | pip install -qe . 59 | pip install -Uqq git+https://github.com/fastai/fastcore.git 60 | - uses: actions/checkout@v2 61 | with: 62 | repository: "fastai/fastpages" 63 | path: "data" 64 | - name: convert posts 65 | run: | 66 | cd data 67 | mkdir -p /fastpages 68 | cp -r _action_files/* /fastpages/ 69 | /fastpages/action_entrypoint.sh 70 | -------------------------------------------------------------------------------- /docs/images/colab.svg: -------------------------------------------------------------------------------- 1 | Open in ColabOpen in Colab 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | token 2 | pythonenv*/ 3 | conda/ 4 | test_settings.ini 5 | .gitconfig 6 | *.tgz 7 | .last_checked 8 | *.bak 9 | *.log 10 | *~ 11 | .pypirc 12 | ~* 13 | _tmp* 14 | tmp* 15 | tags 16 | 17 | # Byte-compiled / optimized / DLL files 18 | __pycache__/ 19 | *.py[cod] 20 | *$py.class 21 | 22 | # C extensions 23 | *.so 24 | 25 | # Distribution / packaging 26 | .Python 27 | env/ 28 | build/ 29 | develop-eggs/ 30 | dist/ 31 | downloads/ 32 | eggs/ 33 | .eggs/ 34 | lib/ 35 | lib64/ 36 | parts/ 37 | sdist/ 38 | var/ 39 | wheels/ 40 | *.egg-info/ 41 | .installed.cfg 42 | *.egg 43 | 44 | # PyInstaller 45 | # Usually these files are written by a python script from a template 46 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 47 | *.manifest 48 | *.spec 49 | 50 | # Installer logs 51 | pip-log.txt 52 | pip-delete-this-directory.txt 53 | 54 | # Unit test / coverage reports 55 | htmlcov/ 56 | .tox/ 57 | .coverage 58 | .coverage.* 59 | .cache 60 | nosetests.xml 61 | coverage.xml 62 | *.cover 63 | .hypothesis/ 64 | 65 | # Translations 66 | *.mo 67 | *.pot 68 | 69 | # Django stuff: 70 | *.log 71 | local_settings.py 72 | 73 | # Flask stuff: 74 | instance/ 75 | .webassets-cache 76 | 77 | # Scrapy stuff: 78 | .scrapy 79 | 80 | # Sphinx documentation 81 | docs/_build/ 82 | 83 | # PyBuilder 84 | target/ 85 | 86 | # Jupyter Notebook 87 | .ipynb_checkpoints 88 | 89 | # pyenv 90 | .python-version 91 | 92 | # celery beat schedule file 93 | celerybeat-schedule 94 | 95 | # SageMath parsed files 96 | *.sage.py 97 | 98 | # dotenv 99 | .env 100 | 101 | # virtualenv 102 | .venv 103 | venv/ 104 | ENV/ 105 | 106 | # Spyder project settings 107 | .spyderproject 108 | .spyproject 109 | 110 | # Rope project settings 111 | .ropeproject 112 | 113 | # mkdocs documentation 114 | /site 115 | 116 | # mypy 117 | .mypy_cache/ 118 | 119 | .vscode 120 | *.swp 121 | 122 | # osx generated files 123 | .DS_Store 124 | .DS_Store? 125 | .Trashes 126 | ehthumbs.db 127 | Thumbs.db 128 | .idea 129 | 130 | # pytest 131 | .pytest_cache 132 | 133 | # tools/trust-doc-nbs 134 | docs_src/.last_checked 135 | 136 | # symlinks to fastai 137 | docs_src/fastai 138 | tools/fastai 139 | 140 | # link checker 141 | checklink/cookies.txt 142 | 143 | # .gitconfig is now autogenerated 144 | .gitconfig 145 | 146 | -------------------------------------------------------------------------------- /nbdev/template.py: -------------------------------------------------------------------------------- 1 | makefile_tmpl = """.ONESHELL: 2 | SHELL := /bin/bash 3 | SRC = $(wildcard {nbs_path}/*.ipynb) 4 | 5 | all: {lib_name} docs 6 | 7 | {lib_name}: $(SRC) 8 | nbdev_build_lib 9 | touch {lib_name} 10 | 11 | sync: 12 | nbdev_update_lib 13 | 14 | docs_serve: docs 15 | cd docs && bundle exec jekyll serve 16 | 17 | docs: $(SRC) 18 | nbdev_build_docs 19 | touch docs 20 | 21 | test: 22 | nbdev_test_nbs 23 | 24 | release: pypi conda_release 25 | nbdev_bump_version 26 | 27 | conda_release: 28 | fastrelease_conda_package 29 | 30 | pypi: dist 31 | twine upload --repository pypi dist/* 32 | 33 | dist: clean 34 | python setup.py sdist bdist_wheel 35 | 36 | clean: 37 | rm -rf dist""" 38 | 39 | topnav_tmpl = """topnav: 40 | - title: Topnav 41 | items: 42 | - title: {host} 43 | external_url: {git_url} 44 | 45 | #Topnav dropdowns 46 | topnav_dropdowns: 47 | - title: Topnav dropdowns 48 | folders:""" 49 | 50 | config_tmpl = """repository: {user}/{lib_name} 51 | output: web 52 | topnav_title: {title} 53 | site_title: {title} 54 | company_name: {copyright} 55 | description: {description} 56 | # Set to false to disable KaTeX math 57 | use_math: true 58 | # Add Google analytics id if you have one and want to use it here 59 | google_analytics: 60 | # See http://nbdev.fast.ai/search for help with adding Search 61 | google_search: 62 | 63 | host: 127.0.0.1 64 | # the preview server used. Leave as is. 65 | port: 4000 66 | # the port where the preview is rendered. 67 | 68 | exclude: 69 | - .idea/ 70 | - .gitignore 71 | - vendor 72 | 73 | exclude: [vendor] 74 | 75 | highlighter: rouge 76 | markdown: kramdown 77 | kramdown: 78 | input: GFM 79 | auto_ids: true 80 | hard_wrap: false 81 | syntax_highlighter: rouge 82 | 83 | collections: 84 | tooltips: 85 | output: false 86 | 87 | defaults: 88 | - 89 | scope: 90 | path: "" 91 | type: "pages" 92 | values: 93 | layout: "page" 94 | comments: true 95 | search: true 96 | sidebar: home_sidebar 97 | topnav: topnav 98 | - 99 | scope: 100 | path: "" 101 | type: "tooltips" 102 | values: 103 | layout: "page" 104 | comments: true 105 | search: true 106 | tooltip: true 107 | 108 | sidebars: 109 | - home_sidebar 110 | 111 | plugins: 112 | - jekyll-remote-theme 113 | 114 | remote_theme: fastai/nbdev-jekyll-theme""" 115 | 116 | -------------------------------------------------------------------------------- /nbdev/imports.py: -------------------------------------------------------------------------------- 1 | from fastcore.imports import * 2 | from fastcore.foundation import * 3 | from fastcore.utils import * 4 | from fastcore.test import * 5 | 6 | import os,re,json,glob,collections,pickle,shutil,inspect,yaml,tempfile,enum,stat,time,random,sys 7 | import importlib.util 8 | from functools import lru_cache 9 | from pdb import set_trace 10 | from configparser import ConfigParser 11 | from pathlib import Path 12 | from textwrap import TextWrapper 13 | from typing import Union,Optional 14 | from functools import partial,lru_cache 15 | from base64 import b64decode,b64encode 16 | 17 | _defaults = {"host": "github", "doc_host": "https://%(user)s.github.io", "doc_baseurl": "/%(lib_name)s/"} 18 | 19 | def _add_new_defaults(cfg, file, **kwargs): 20 | for k,v in kwargs.items(): 21 | if cfg.get(k, None) is None: 22 | cfg[k] = v 23 | save_config_file(file, cfg) 24 | 25 | @lru_cache(maxsize=None) 26 | def get_config(cfg_name='settings.ini'): 27 | cfg_path = Path.cwd() 28 | while cfg_path != cfg_path.parent and not (cfg_path/cfg_name).exists(): cfg_path = cfg_path.parent 29 | config = Config(cfg_path, cfg_name=cfg_name) 30 | _add_new_defaults(config.d, config.config_file, 31 | host="github", doc_host="https://%(user)s.github.io", doc_baseurl="/%(lib_name)s/") 32 | return config 33 | 34 | 35 | def create_config(host, lib_name, user, path='.', cfg_name='settings.ini', branch='master', 36 | git_url="https://github.com/%(user)s/%(lib_name)s/tree/%(branch)s/", custom_sidebar=False, 37 | nbs_path='nbs', lib_path='%(lib_name)s', doc_path='docs', recursive=False, tst_flags='', version='0.0.1', 38 | doc_host="https://%(user)s.github.io", doc_baseurl="/%(lib_name)s/", **kwargs): 39 | "Creates a new config file for `lib_name` and `user` and saves it." 40 | g = locals() 41 | config = {o:g[o] for o in 'host lib_name user branch git_url lib_path nbs_path doc_path recursive tst_flags version custom_sidebar'.split()} 42 | config = {**config, **kwargs} 43 | save_config_file(Path(path)/cfg_name, config) 44 | 45 | #export 46 | class ReLibName(): 47 | "Regex expression that's compiled at first use but not before since it needs `get_config().lib_name`" 48 | def __init__(self, pat, flags=0): self._re,self.pat,self.flags = None,pat,flags 49 | @property 50 | def re(self): 51 | if not hasattr(get_config(), 'lib_name'): raise Exception("Please fill in the library name in settings.ini.") 52 | self.pat = self.pat.replace('LIB_NAME', get_config().lib_name) 53 | if self._re is None: self._re = re.compile(self.pat, self.flags) 54 | return self._re 55 | 56 | def parse_line(line): 57 | "Convert list-like string into a list" 58 | line = line.strip() 59 | if line.startswith('[') and line.endswith(']'): line=line[1:-1] 60 | return [s for s in re.split('[ ,]+', line) if s] 61 | 62 | -------------------------------------------------------------------------------- /nbs/99_search.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Setting up Search\n", 8 | "\n", 9 | "> Using Google Custom Search\n", 10 | "\n", 11 | "- toc:false" 12 | ] 13 | }, 14 | { 15 | "cell_type": "markdown", 16 | "metadata": {}, 17 | "source": [ 18 | "If you want to include Search functionality on your docs site, you need to set up a [Google Custom Search](https://cse.google.com/cse/all), and then link it to your nbdev project. Here's all the steps you need to follow (replace anything in `{}` with the value your have in `settings.ini`:" 19 | ] 20 | }, 21 | { 22 | "cell_type": "markdown", 23 | "metadata": {}, 24 | "source": [ 25 | "1. Go to [Google Custom Search](https://cse.google.com/cse/all) and click 'add'.\n", 26 | "1. In \"Sites to search\" type the URL of your docs site (e.g. `{owner}.github.io/{lib_name}`), and in \"Name of the search engine\" type \"{lib_name} docs\". Then click \"CREATE\"\n", 27 | "1. Click \"Control Panel\"\n", 28 | "1. In the \"Basics\" tab, click \"Copy to clipboard\" in the \"Search engine ID\" row\n", 29 | "1. Paste that as the value for \"google_search:\" in `docs/_config.yml` in your project. (If you don't already have this file, run `nbdev_build_lib` to create it, once you've set up your `settings.ini`)\n", 30 | "1. Click \"Advanced\" (far-right tab), then \"CSE Context\", then \"Download (XML)\"\n", 31 | "1. Open the downloaded `cse.xml` file in a text editor, and delete everything from the line starting with `=parse_version('36.2') 5 | 6 | # note: all settings are in settings.ini; edit there, not here 7 | config = ConfigParser(delimiters=['=']) 8 | config.read('settings.ini') 9 | cfg = config['DEFAULT'] 10 | 11 | cfg_keys = 'version description keywords author author_email'.split() 12 | expected = cfg_keys + "lib_name user branch license status min_python audience language".split() 13 | for o in expected: assert o in cfg, "missing expected setting: {}".format(o) 14 | setup_cfg = {o:cfg[o] for o in cfg_keys} 15 | 16 | if len(sys.argv)>1 and sys.argv[1]=='version': 17 | print(setup_cfg['version']) 18 | exit() 19 | 20 | licenses = { 21 | 'apache2': ('Apache Software License 2.0','OSI Approved :: Apache Software License'), 22 | } 23 | statuses = [ '1 - Planning', '2 - Pre-Alpha', '3 - Alpha', 24 | '4 - Beta', '5 - Production/Stable', '6 - Mature', '7 - Inactive' ] 25 | py_versions = '2.0 2.1 2.2 2.3 2.4 2.5 2.6 2.7 3.0 3.1 3.2 3.3 3.4 3.5 3.6 3.7 3.8 3.9 3.10'.split() 26 | min_python = cfg['min_python'] 27 | lic = licenses[cfg['license']] 28 | 29 | requirements = ['pip', 'packaging'] 30 | if cfg.get('requirements'): requirements += cfg.get('requirements','').split() 31 | if cfg.get('pip_requirements'): requirements += cfg.get('pip_requirements','').split() 32 | dev_requirements = (cfg.get('dev_requirements') or '').split() 33 | project_urls = {} 34 | if cfg.get('doc_host'): project_urls["Documentation"] = cfg['doc_host'] + cfg.get('doc_baseurl', '') 35 | 36 | long_description = open('README.md').read() 37 | # ![png](docs/images/output_13_0.png) 38 | for ext in ['png', 'svg']: 39 | long_description = re.sub(r'!\['+ext+'\]\((.*)\)', '!['+ext+']('+'https://raw.githubusercontent.com/{}/{}'.format(cfg['user'],cfg['lib_name'])+'/'+cfg['branch']+'/\\1)', long_description) 40 | long_description = re.sub(r'src=\"(.*)\.'+ext+'\"', 'src=\"https://raw.githubusercontent.com/{}/{}'.format(cfg['user'],cfg['lib_name'])+'/'+cfg['branch']+'/\\1.'+ext+'\"', long_description) 41 | 42 | setuptools.setup( 43 | name = 'nbdev', 44 | license = lic[0], 45 | classifiers = [ 46 | 'Development Status :: ' + statuses[int(cfg['status'])], 47 | 'Intended Audience :: ' + cfg['audience'].title(), 48 | 'License :: ' + lic[1], 49 | 'Natural Language :: ' + cfg['language'].title(), 50 | ] + ['Programming Language :: Python :: '+o for o in py_versions[py_versions.index(min_python):]], 51 | url = cfg['git_url'], 52 | packages = setuptools.find_packages(), 53 | include_package_data = True, 54 | install_requires = requirements, 55 | extras_require={ 'dev': dev_requirements }, 56 | python_requires = '>=' + cfg['min_python'], 57 | long_description = long_description, 58 | long_description_content_type = 'text/markdown', 59 | zip_safe = False, 60 | entry_points = { 'console_scripts': cfg.get('console_scripts','').split() }, 61 | project_urls = project_urls, 62 | **setup_cfg) 63 | 64 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to make participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, gender identity and expression, level of experience, 9 | education, socio-economic status, nationality, personal appearance, race, 10 | religion, or sexual identity and orientation. 11 | 12 | Examples of unacceptable behavior by participants include: 13 | 14 | * The use of sexualized language or imagery and unwelcome sexual attention or 15 | advances 16 | * Trolling, insulting/derogatory comments, and personal or political attacks 17 | * Public or private harassment 18 | * Publishing others' private information, such as a physical or electronic 19 | address, without explicit permission 20 | 21 | These examples of unacceptable behaviour are requirements; we will not allow them 22 | in any fast.ai project, including this one. 23 | 24 | ## Our Standards 25 | 26 | Examples of behavior that contributes to creating a positive environment 27 | include: 28 | 29 | * Using welcoming and inclusive language 30 | * Being respectful of differing viewpoints and experiences 31 | * Gracefully accepting constructive criticism 32 | * Focusing on what is best for the community 33 | * Showing empathy towards other community members 34 | 35 | These examples are shown only to help you participate effectively -- they are not 36 | requirements, just requests and guidance. 37 | 38 | ## Our Responsibilities 39 | 40 | Project maintainers are responsible for clarifying the standards of acceptable 41 | behavior and are expected to take appropriate and fair corrective action in 42 | response to any instances of unacceptable behavior. 43 | 44 | Project maintainers have the right and responsibility to remove, edit, or 45 | reject comments, commits, code, wiki edits, issues, and other contributions 46 | that are not aligned to this Code of Conduct, or to ban temporarily or 47 | permanently any contributor for other behaviors that they deem inappropriate, 48 | threatening, offensive, or harmful. 49 | 50 | ## Scope 51 | 52 | This Code of Conduct applies both within project spaces and in public spaces 53 | when an individual is representing the project or its community. Examples of 54 | representing a project or community include using an official project e-mail 55 | address, posting via an official social media account or acting as an appointed 56 | representative at an online or offline event. Representation of a project may be 57 | further defined and clarified by project maintainers. 58 | 59 | ## Enforcement 60 | 61 | Instances of abusive, harassing or otherwise unacceptable behavior may be 62 | reported by contacting the project team at info@fast.ai. All 63 | complaints will be reviewed and investigated and will result in a response that 64 | is deemed necessary and appropriate to the circumstances. The project team is 65 | obligated to maintain confidentiality with regard to the reporter of an incident. 66 | Further details of specific enforcement policies may be posted separately. 67 | 68 | Project maintainers who do not follow or enforce the Code of Conduct in good 69 | faith may face temporary or permanent repercussions as determined by other 70 | members of the project's leadership. 71 | 72 | ## Attribution 73 | 74 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 75 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 76 | 77 | [homepage]: https://www.contributor-covenant.org 78 | -------------------------------------------------------------------------------- /docs/search.html: -------------------------------------------------------------------------------- 1 | --- 2 | toc: false 3 | title: Setting up Search 4 | 5 | 6 | keywords: fastai 7 | sidebar: home_sidebar 8 | 9 | summary: "Using Google Custom Search" 10 | description: "Using Google Custom Search" 11 | nb_path: "nbs/99_search.ipynb" 12 | --- 13 | 22 | 23 |
24 | 25 | {% raw %} 26 | 27 |
28 | 29 |
30 | {% endraw %} 31 | 32 |
33 |
34 |

If you want to include Search functionality on your docs site, you need to set up a Google Custom Search, and then link it to your nbdev project. Here's all the steps you need to follow (replace anything in {} with the value your have in settings.ini:

35 | 36 |
37 |
38 |
39 |
40 |
41 |
    42 |
  1. Go to Google Custom Search and click 'add'.
  2. 43 |
  3. In "Sites to search" type the URL of your docs site (e.g. {owner}.github.io/{lib_name}), and in "Name of the search engine" type "{lib_name} docs". Then click "CREATE"
  4. 44 |
  5. Click "Control Panel"
  6. 45 |
  7. In the "Basics" tab, click "Copy to clipboard" in the "Search engine ID" row
  8. 46 |
  9. Paste that as the value for "google_search:" in docs/_config.yml in your project. (If you don't already have this file, run nbdev_build_lib to create it, once you've set up your settings.ini)
  10. 47 |
  11. Click "Advanced" (far-right tab), then "CSE Context", then "Download (XML)"
  12. 48 |
  13. Open the downloaded cse.xml file in a text editor, and delete everything from the line starting with <LookAndFeel onwards (including that line)
  14. 49 |
  15. Replace those lines with the contents of this file: search-template.txt, and save it
  16. 50 |
  17. In your browser, in the same "Advanced" tab you downloaded cse.xml from, click Upload XML file and upload the updated cse.xml file you just save.
  18. 51 |
52 | 53 |
54 |
55 |
56 |
57 |
58 |

Usage tips

59 |
60 |
61 |
62 |
63 |
64 |
    65 |
  • To see what documents google is currently indexing at any particular URL, use the site: operator without any search term. e.g. "site:docs.fast.ai". You can use this to sense check what a search term ought to return as the result
  • 66 |
  • If Google isn't indexing your docs site, you can ask it to do so by following these instructions.
  • 67 |
68 | 69 |
70 |
71 |
72 |
73 | 74 | 75 | -------------------------------------------------------------------------------- /nbdev/clean.py: -------------------------------------------------------------------------------- 1 | # AUTOGENERATED! DO NOT EDIT! File to edit: nbs/07_clean.ipynb (unless otherwise specified). 2 | 3 | __all__ = ['rm_execution_count', 'clean_output_data_vnd', 'colab_json', 'clean_cell_output', 'cell_metadata_keep', 4 | 'nb_metadata_keep', 'clean_cell', 'clean_nb', 'nbdev_clean_nbs'] 5 | 6 | # Cell 7 | import io,sys,json,glob,re 8 | from fastcore.script import call_parse,Param,bool_arg 9 | from fastcore.utils import ifnone 10 | from .imports import Config 11 | from .export import nbglob 12 | from pathlib import Path 13 | 14 | # Cell 15 | def rm_execution_count(o): 16 | "Remove execution count in `o`" 17 | if 'execution_count' in o: o['execution_count'] = None 18 | 19 | # Cell 20 | colab_json = "application/vnd.google.colaboratory.intrinsic+json" 21 | def clean_output_data_vnd(o): 22 | "Remove `application/vnd.google.colaboratory.intrinsic+json` in data entries" 23 | if 'data' in o: 24 | data = o['data'] 25 | if colab_json in data: 26 | new_data = {k:v for k,v in data.items() if k != colab_json} 27 | o['data'] = new_data 28 | 29 | # Cell 30 | def clean_cell_output(cell): 31 | "Remove execution count in `cell`" 32 | if 'outputs' in cell: 33 | for o in cell['outputs']: 34 | rm_execution_count(o) 35 | clean_output_data_vnd(o) 36 | o.get('metadata', o).pop('tags', None) 37 | 38 | # Cell 39 | cell_metadata_keep = ["hide_input"] 40 | nb_metadata_keep = ["kernelspec", "jekyll", "jupytext", "doc"] 41 | 42 | # Cell 43 | def clean_cell(cell, clear_all=False): 44 | "Clean `cell` by removing superfluous metadata or everything except the input if `clear_all`" 45 | rm_execution_count(cell) 46 | if 'outputs' in cell: 47 | if clear_all: cell['outputs'] = [] 48 | else: clean_cell_output(cell) 49 | if cell['source'] == ['']: cell['source'] = [] 50 | cell['metadata'] = {} if clear_all else {k:v for k,v in cell['metadata'].items() if k in cell_metadata_keep} 51 | 52 | # Cell 53 | def clean_nb(nb, clear_all=False): 54 | "Clean `nb` from superfluous metadata, passing `clear_all` to `clean_cell`" 55 | for c in nb['cells']: clean_cell(c, clear_all=clear_all) 56 | nb['metadata'] = {k:v for k,v in nb['metadata'].items() if k in nb_metadata_keep } 57 | 58 | # Cell 59 | def _print_output(nb): 60 | "Print `nb` in stdout for git things" 61 | _output_stream = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8') 62 | x = json.dumps(nb, sort_keys=True, indent=1, ensure_ascii=False) 63 | _output_stream.write(x) 64 | _output_stream.write("\n") 65 | _output_stream.flush() 66 | 67 | # Cell 68 | @call_parse 69 | def nbdev_clean_nbs( 70 | fname:str=None, # A notebook name or glob to convert 71 | clear_all:bool_arg=False, # Clean all metadata and outputs 72 | disp:bool_arg=False, # Print the cleaned outputs 73 | read_input_stream:bool_arg=False # Read input stram and not nb folder 74 | ): 75 | "Clean all notebooks in `fname` to avoid merge conflicts" 76 | #Git hooks will pass the notebooks in the stdin 77 | if read_input_stream and sys.stdin: 78 | input_stream = io.TextIOWrapper(sys.stdin.buffer, encoding='utf-8') 79 | nb = json.load(input_stream) 80 | clean_nb(nb, clear_all=clear_all) 81 | _print_output(nb) 82 | return 83 | path = None 84 | if fname is None: 85 | try: path = get_config().path("nbs_path") 86 | except Exception as e: path = Path.cwd() 87 | 88 | files = nbglob(fname=ifnone(fname,path)) 89 | for f in files: 90 | if not str(f).endswith('.ipynb'): continue 91 | nb = json.loads(open(f, 'r', encoding='utf-8').read()) 92 | clean_nb(nb, clear_all=clear_all) 93 | if disp: _print_output(nb) 94 | else: 95 | x = json.dumps(nb, sort_keys=True, indent=1, ensure_ascii=False) 96 | with io.open(f, 'w', encoding='utf-8') as f: 97 | f.write(x) 98 | f.write("\n") -------------------------------------------------------------------------------- /nbdev/merge.py: -------------------------------------------------------------------------------- 1 | # AUTOGENERATED! DO NOT EDIT! File to edit: nbs/05_merge.ipynb (unless otherwise specified). 2 | 3 | __all__ = ['extract_cells', 'get_md_cell', 'conflicts', 'same_inputs', 'analyze_cell', 'nbdev_fix_merge'] 4 | 5 | # Cell 6 | from .imports import * 7 | from fastcore.script import * 8 | 9 | # Cell 10 | def extract_cells(raw_txt): 11 | "Manually extract cells in potential broken json `raw_txt`" 12 | lines = raw_txt.split('\n') 13 | cells = [] 14 | i = 0 15 | while not lines[i].startswith(' "cells"'): i+=1 16 | i += 1 17 | start = '\n'.join(lines[:i]) 18 | while lines[i] != ' ],': 19 | while lines[i] != ' {': i+=1 20 | j = i 21 | while not lines[j].startswith(' }'): j+=1 22 | c = '\n'.join(lines[i:j+1]) 23 | if not c.endswith(','): c = c + ',' 24 | cells.append(c) 25 | i = j+1 26 | end = '\n'.join(lines[i:]) 27 | return start,cells,end 28 | 29 | # Cell 30 | def get_md_cell(txt): 31 | "A markdown cell with `txt`" 32 | return ''' { 33 | "cell_type": "markdown", 34 | "metadata": {}, 35 | "source": [ 36 | "''' + txt + '''" 37 | ] 38 | },''' 39 | 40 | # Cell 41 | conflicts = '<<<<<<< ======= >>>>>>>'.split() 42 | 43 | # Cell 44 | def _split_cell(cell, cf, names): 45 | "Split `cell` between `conflicts` given state in `cf`, save `names` of branches if seen" 46 | res1,res2 = [],[] 47 | for line in cell.split('\n'): 48 | if line.startswith(conflicts[cf]): 49 | if names[cf//2] is None: names[cf//2] = line[8:] 50 | cf = (cf+1)%3 51 | continue 52 | if cf<2: res1.append(line) 53 | if cf%2==0: res2.append(line) 54 | return '\n'.join(res1),'\n'.join(res2),cf,names 55 | 56 | # Cell 57 | _re_conflict = re.compile(r'^<<<<<<<', re.MULTILINE) 58 | 59 | # Cell 60 | def same_inputs(t1, t2): 61 | "Test if the cells described in `t1` and `t2` have the same inputs" 62 | if len(t1)==0 or len(t2)==0: return False 63 | try: 64 | c1,c2 = json.loads(t1[:-1]),json.loads(t2[:-1]) 65 | return c1['source']==c2['source'] 66 | except Exception as e: return False 67 | 68 | # Cell 69 | def analyze_cell(cell, cf, names, prev=None, added=False, fast=True, trust_us=True): 70 | "Analyze and solve conflicts in `cell`" 71 | if cf==0 and _re_conflict.search(cell) is None: return cell,cf,names,prev,added 72 | old_cf = cf 73 | v1,v2,cf,names = _split_cell(cell, cf, names) 74 | if fast and same_inputs(v1,v2): 75 | if old_cf==0 and cf==0: return (v2 if trust_us else v1),cf,names,prev,added 76 | v1,v2 = (v2,v2) if trust_us else (v1,v1) 77 | res = [] 78 | if old_cf == 0: 79 | added=True 80 | res.append(get_md_cell(f'`{conflicts[0]} {names[0]}`')) 81 | res.append(v1) 82 | if cf ==0: 83 | res.append(get_md_cell(f'`{conflicts[1]}`')) 84 | if prev is not None: res += prev 85 | res.append(v2) 86 | res.append(get_md_cell(f'`{conflicts[2]} {names[1]}`')) 87 | prev = None 88 | else: prev = [v2] if prev is None else prev + [v2] 89 | return '\n'.join([r for r in res if len(r) > 0]),cf,names,prev,added 90 | 91 | # Cell 92 | @call_parse 93 | def nbdev_fix_merge( 94 | fname:str, # A notebook filename to fix 95 | fast:bool=True, # Fast fix: automatically fix the merge conflicts in outputs or metadata 96 | trust_us:bool=True # Use local outputs/metadata when fast merging 97 | ): 98 | "Fix merge conflicts in notebook `fname`" 99 | fname=Path(fname) 100 | shutil.copy(fname, fname.with_suffix('.ipynb.bak')) 101 | with open(fname, 'r') as f: raw_text = f.read() 102 | start,cells,end = extract_cells(raw_text) 103 | res = [start] 104 | cf,names,prev,added = 0,[None,None],None,False 105 | for cell in cells: 106 | c,cf,names,prev,added = analyze_cell(cell, cf, names, prev, added, fast=fast, trust_us=trust_us) 107 | res.append(c) 108 | if res[-1].endswith(','): res[-1] = res[-1][:-1] 109 | with open(f'{fname}', 'w') as f: f.write('\n'.join([r for r in res+[end] if len(r) > 0])) 110 | if fast and not added: print("Successfully merged conflicts!") 111 | else: print("One or more conflict remains in the notebook, please inspect manually.") -------------------------------------------------------------------------------- /docs/try_save.html: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | title: Title 4 | 5 | 6 | keywords: fastai 7 | sidebar: home_sidebar 8 | 9 | 10 | 11 | nb_path: "nbs/try_save.ipynb" 12 | --- 13 | 22 | 23 |
24 | 25 | {% raw %} 26 | 27 |
28 | 29 |
30 | {% endraw %} 31 | 32 | {% raw %} 33 | 34 |
35 |
36 | 37 |
38 |
39 |
import pandas as pd
 40 | df = pd.DataFrame({'A': range(100), 'B': range(100)})
 41 | 
42 | 43 |
44 |
45 |
46 | 47 |
48 | {% endraw %} 49 | 50 | {% raw %} 51 | 52 |
53 |
54 | 55 |
56 |
57 |
import pickle
 58 | 
 59 | with open('saved_state', 'w') as f:
 60 |     stuff = globals()
 61 |     pickle.dump(stuff, f)
 62 | 
63 | 64 |
65 |
66 |
67 | 68 |
69 |
70 | 71 |
72 | 73 |
74 |
 75 | ---------------------------------------------------------------------------
 76 | TypeError                                 Traceback (most recent call last)
 77 | <ipython-input-4-50448fe77fd2> in <module>
 78 |       3 with open('saved_state', 'w') as f:
 79 |       4     stuff = globals()
 80 | ----> 5     pickle.dump(stuff, f)
 81 | 
 82 | TypeError: cannot pickle 'module' object
83 |
84 |
85 | 86 |
87 |
88 | 89 |
90 | {% endraw %} 91 | 92 | {% raw %} 93 | 94 |
95 |
96 | 97 |
98 |
99 |
globals()
100 | 
101 | 102 |
103 |
104 |
105 | 106 |
107 | {% endraw %} 108 | 109 |
110 | 111 | 112 | -------------------------------------------------------------------------------- /nbdev/cli.py: -------------------------------------------------------------------------------- 1 | # AUTOGENERATED! DO NOT EDIT! File to edit: nbs/06_cli.ipynb (unless otherwise specified). 2 | 3 | __all__ = ['bump_version', 'nbdev_bump_version', 'nbdev_install_git_hooks', 'extract_tgz', 'nbdev_new'] 4 | 5 | # Cell 6 | from .imports import * 7 | from .export import * 8 | from .sync import * 9 | from .merge import * 10 | from .export2html import * 11 | from .clean import * 12 | from .test import * 13 | from fastcore.script import * 14 | from ghapi.all import GhApi 15 | from urllib.error import HTTPError 16 | 17 | # Cell 18 | def bump_version(version, part=2): 19 | version = version.split('.') 20 | version[part] = str(int(version[part]) + 1) 21 | for i in range(part+1, 3): version[i] = '0' 22 | return '.'.join(version) 23 | 24 | # Cell 25 | @call_parse 26 | def nbdev_bump_version( 27 | part:int=2 # Part of version to bump 28 | ): 29 | "Increment version in `settings.py` by one" 30 | cfg = get_config() 31 | print(f'Old version: {cfg.version}') 32 | cfg.d['version'] = bump_version(get_config().version, part) 33 | cfg.save() 34 | update_version() 35 | print(f'New version: {cfg.version}') 36 | 37 | # Cell 38 | @call_parse 39 | def nbdev_install_git_hooks(): 40 | "Install git hooks to clean/trust notebooks automatically" 41 | try: path = get_config().config_file.parent 42 | except: path = Path.cwd() 43 | hook_path = path/'.git'/'hooks' 44 | fn = hook_path/'post-merge' 45 | hook_path.mkdir(parents=True, exist_ok=True) 46 | #Trust notebooks after merge 47 | fn.write_text("#!/bin/bash\necho 'Trusting notebooks'\nnbdev_trust_nbs") 48 | os.chmod(fn, os.stat(fn).st_mode | stat.S_IEXEC) 49 | #Clean notebooks on commit/diff 50 | (path/'.gitconfig').write_text("""# Generated by nbdev_install_git_hooks 51 | # 52 | # If you need to disable this instrumentation do: 53 | # git config --local --unset include.path 54 | # 55 | # To restore the filter 56 | # git config --local include.path .gitconfig 57 | # 58 | # If you see notebooks not stripped, checked the filters are applied in .gitattributes 59 | # 60 | [filter "clean-nbs"] 61 | clean = nbdev_clean_nbs --read_input_stream True 62 | smudge = cat 63 | required = true 64 | [diff "ipynb"] 65 | textconv = nbdev_clean_nbs --disp True --fname 66 | """) 67 | cmd = "git config --local include.path ../.gitconfig" 68 | print(f"Executing: {cmd}") 69 | run(cmd) 70 | print("Success: hooks are installed and repo's .gitconfig is now trusted") 71 | try: nb_path = get_config().path("nbs_path") 72 | except: nb_path = Path.cwd() 73 | (nb_path/'.gitattributes').write_text("**/*.ipynb filter=clean-nbs\n**/*.ipynb diff=ipynb\n") 74 | 75 | # Cell 76 | _template_git_repo = "https://github.com/fastai/nbdev_template.git" 77 | 78 | # Cell 79 | import tarfile 80 | 81 | # Cell 82 | def extract_tgz(url, dest='.'): 83 | with urlopen(url) as u: tarfile.open(mode='r:gz', fileobj=u).extractall(dest) 84 | 85 | # Cell 86 | def _get_branch(owner, repo, default='main'): 87 | api = GhApi(owner=owner, repo=repo, token=os.getenv('GITHUB_TOKEN')) 88 | try: return api.repos.get().default_branch 89 | except HTTPError: 90 | msg= [f"Could not access repo: {owner}/{repo} to find your default branch - `{default} assumed.\n", 91 | "Edit `settings.ini` if this is incorrect.\n" 92 | "In the future, you can allow nbdev to see private repos by setting the environment variable GITHUB_TOKEN as described here: https://nbdev.fast.ai/cli.html#Using-nbdev_new-with-private-repos \n", ] 93 | print(''.join(msg)) 94 | return default 95 | 96 | # Cell 97 | @call_parse 98 | def nbdev_new(): 99 | "Create a new nbdev project from the current git repo" 100 | url = run('git config --get remote.origin.url') 101 | if not url: raise Exception('This does not appear to be a cloned git directory with a remote') 102 | author = run('git config --get user.name').strip() 103 | email = run('git config --get user.email').strip() 104 | if not (author and email): raise Exception('User name and email not configured in git') 105 | 106 | # download and untar template, and optionally notebooks 107 | tgnm = urljson('https://api.github.com/repos/fastai/nbdev_template/releases/latest')['tag_name'] 108 | FILES_URL = f"https://github.com/fastai/nbdev_template/archive/{tgnm}.tar.gz" 109 | extract_tgz(FILES_URL) 110 | path = Path() 111 | nbexists = True if first(path.glob('*.ipynb')) else False 112 | for o in (path/f'nbdev_template-{tgnm}').ls(): 113 | if o.name == '00_core.ipynb': 114 | if not nbexists: shutil.move(str(o), './') 115 | elif not Path(f'./{o.name}').exists(): shutil.move(str(o), './') 116 | shutil.rmtree(f'nbdev_template-{tgnm}') 117 | 118 | # auto-config settings.ini from git 119 | settings_path = Path('settings.ini') 120 | settings = settings_path.read_text() 121 | owner,repo = repo_details(url) 122 | branch = _get_branch(owner, repo) 123 | settings = settings.format(lib_name=repo, user=owner, author=author, author_email=email, branch=branch) 124 | settings_path.write_text(settings) 125 | nbdev_install_git_hooks() -------------------------------------------------------------------------------- /nbdev/test.py: -------------------------------------------------------------------------------- 1 | # AUTOGENERATED! DO NOT EDIT! File to edit: nbs/04_test.ipynb (unless otherwise specified). 2 | 3 | __all__ = ['get_all_flags', 'get_cell_flags', 'NoExportPreprocessor', 'test_nb', 'nbdev_test_nbs', 'nbdev_read_nbs'] 4 | 5 | # Cell 6 | from .imports import * 7 | from .sync import * 8 | from .export import * 9 | from .export import _mk_flag_re 10 | from .export2html import _re_notebook2script 11 | from fastcore.script import * 12 | from fastcore.parallel import * 13 | 14 | from nbconvert.preprocessors import ExecutePreprocessor 15 | import nbformat 16 | 17 | # Cell 18 | class _ReTstFlags(): 19 | "Test flag matching regular expressions" 20 | def __init__(self, all_flag): 21 | "match flags applied to all cells?" 22 | self.all_flag = all_flag 23 | 24 | def _deferred_init(self): 25 | "Compile at first use but not before since patterns need `get_config().tst_flags`" 26 | if hasattr(self, '_re'): return 27 | tst_flags = get_config().get('tst_flags', '') 28 | tst_flags += f'|skip' if tst_flags else 'skip' 29 | _re_all = 'all_' if self.all_flag else '' 30 | self._re = _mk_flag_re(f"{_re_all}({tst_flags})", 0, "Any line with a test flag") 31 | 32 | def findall(self, source): 33 | self._deferred_init() 34 | return self._re.findall(source) 35 | 36 | def search(self, source): 37 | self._deferred_init() 38 | return self._re.search(source) 39 | 40 | # Cell 41 | _re_all_flag = _ReTstFlags(True) 42 | 43 | # Cell 44 | def get_all_flags(cells): 45 | "Check for all test flags in `cells`" 46 | result = [] 47 | for cell in cells: 48 | if cell['cell_type'] == 'code': result.extend(_re_all_flag.findall(cell['source'])) 49 | return set(result) 50 | 51 | # Cell 52 | _re_flags = _ReTstFlags(False) 53 | 54 | # Cell 55 | def get_cell_flags(cell): 56 | "Check for any special test flag in `cell`" 57 | if cell['cell_type'] != 'code' or len(get_config().get('tst_flags',''))==0: return [] 58 | return _re_flags.findall(cell['source']) 59 | 60 | # Cell 61 | class NoExportPreprocessor(ExecutePreprocessor): 62 | "An `ExecutePreprocessor` that executes cells that don't have a flag in `flags`" 63 | def __init__(self, flags, **kwargs): 64 | self.flags = flags 65 | super().__init__(**kwargs) 66 | 67 | def preprocess_cell(self, cell, resources, index): 68 | if 'source' not in cell or cell['cell_type'] != "code": return cell, resources 69 | for f in get_cell_flags(cell): 70 | if f not in self.flags: return cell, resources 71 | if check_re(cell, _re_notebook2script): return cell, resources 72 | return super().preprocess_cell(cell, resources, index) 73 | 74 | # Cell 75 | def test_nb(fn, flags=None): 76 | "Execute tests in notebook in `fn` with `flags`" 77 | os.environ["IN_TEST"] = '1' 78 | if flags is None: flags = [] 79 | try: 80 | nb = read_nb(fn) 81 | for f in get_all_flags(nb['cells']): 82 | if f not in flags: return 83 | ep = NoExportPreprocessor(flags, timeout=600, kernel_name='python3') 84 | pnb = nbformat.from_dict(nb) 85 | ep.preprocess(pnb, {}) 86 | finally: os.environ.pop("IN_TEST") 87 | 88 | # Cell 89 | def _test_one(fname, flags=None, verbose=True): 90 | print(f"testing {fname}") 91 | start = time.time() 92 | try: 93 | test_nb(fname, flags=flags) 94 | return True,time.time()-start 95 | except Exception as e: 96 | if "ZMQError" in str(e): _test_one(item, flags=flags, verbose=verbose) 97 | if verbose: print(f'Error in {fname}:\n{e}') 98 | return False,time.time()-start 99 | 100 | # Cell 101 | @call_parse 102 | def nbdev_test_nbs( 103 | fname:str=None, # A notebook name or glob to convert 104 | flags:str=None, # Space separated list of flags 105 | n_workers:int=None, # Number of workers to use 106 | verbose:bool_arg=True, # Print errors along the way 107 | timing:bool=False, # Timing each notebook to see the ones are slow 108 | pause:float=0.5 # Pause time (in secs) between notebooks to avoid race conditions 109 | ): 110 | "Test in parallel the notebooks matching `fname`, passing along `flags`" 111 | if flags is not None: flags = flags.split(' ') 112 | files = nbglob(fname) 113 | files = [Path(f).absolute() for f in sorted(files)] 114 | assert len(files) > 0, "No files to test found." 115 | if n_workers is None: n_workers = 0 if len(files)==1 else min(num_cpus(), 8) 116 | # make sure we are inside the notebook folder of the project 117 | os.chdir(get_config().path("nbs_path")) 118 | results = parallel(_test_one, files, flags=flags, verbose=verbose, n_workers=n_workers, pause=pause) 119 | passed,times = [r[0] for r in results],[r[1] for r in results] 120 | if all(passed): print("All tests are passing!") 121 | else: 122 | msg = "The following notebooks failed:\n" 123 | raise Exception(msg + '\n'.join([f.name for p,f in zip(passed,files) if not p])) 124 | if timing: 125 | for i,t in sorted(enumerate(times), key=lambda o:o[1], reverse=True): 126 | print(f"Notebook {files[i].name} took {int(t)} seconds") 127 | 128 | # Cell 129 | @call_parse 130 | def nbdev_read_nbs( 131 | fname:str=None # A notebook name or glob to convert 132 | ): 133 | "Check all notebooks matching `fname` can be opened" 134 | files = nbglob(fname) 135 | for nb in files: 136 | try: _ = read_nb(nb) 137 | except Exception as e: 138 | print(f"{nb} is corrupted and can't be opened.") 139 | raise e -------------------------------------------------------------------------------- /nbdev/_nbdev.py: -------------------------------------------------------------------------------- 1 | # AUTOGENERATED BY NBDEV! DO NOT EDIT! 2 | 3 | __all__ = ["index", "modules", "custom_doc_links", "git_url"] 4 | 5 | index = {"read_nb": "00_export.ipynb", 6 | "check_re": "00_export.ipynb", 7 | "check_re_multi": "00_export.ipynb", 8 | "is_export": "00_export.ipynb", 9 | "find_default_export": "00_export.ipynb", 10 | "export_names": "00_export.ipynb", 11 | "extra_add": "00_export.ipynb", 12 | "relative_import": "00_export.ipynb", 13 | "reset_nbdev_module": "00_export.ipynb", 14 | "get_nbdev_module": "00_export.ipynb", 15 | "save_nbdev_module": "00_export.ipynb", 16 | "split_flags_and_code": "00_export.ipynb", 17 | "create_mod_file": "00_export.ipynb", 18 | "create_mod_files": "00_export.ipynb", 19 | "add_init": "00_export.ipynb", 20 | "update_version": "00_export.ipynb", 21 | "update_baseurl": "00_export.ipynb", 22 | "nbglob": "00_export.ipynb", 23 | "notebook2script": "00_export.ipynb", 24 | "DocsTestClass": "00_export.ipynb", 25 | "update_lib_with_exporti_testfn": "00_export.ipynb", 26 | "get_name": "01_sync.ipynb", 27 | "qual_name": "01_sync.ipynb", 28 | "source_nb": "01_sync.ipynb", 29 | "relimport2name": "01_sync.ipynb", 30 | "nbdev_update_lib": "01_sync.ipynb", 31 | "nbdev_diff_nbs": "01_sync.ipynb", 32 | "nbdev_trust_nbs": "01_sync.ipynb", 33 | "is_enum": "02_showdoc.ipynb", 34 | "is_lib_module": "02_showdoc.ipynb", 35 | "re_digits_first": "02_showdoc.ipynb", 36 | "try_external_doc_link": "02_showdoc.ipynb", 37 | "is_doc_name": "02_showdoc.ipynb", 38 | "doc_link": "02_showdoc.ipynb", 39 | "add_doc_links": "02_showdoc.ipynb", 40 | "colab_link": "02_showdoc.ipynb", 41 | "get_nb_source_link": "02_showdoc.ipynb", 42 | "nb_source_link": "02_showdoc.ipynb", 43 | "type_repr": "02_showdoc.ipynb", 44 | "format_param": "02_showdoc.ipynb", 45 | "is_source_available": "02_showdoc.ipynb", 46 | "show_doc": "02_showdoc.ipynb", 47 | "md2html": "02_showdoc.ipynb", 48 | "get_doc_link": "02_showdoc.ipynb", 49 | "doc": "02_showdoc.ipynb", 50 | "HTMLParseAttrs": "03_export2html.ipynb", 51 | "remove_widget_state": "03_export2html.ipynb", 52 | "upd_metadata": "03_export2html.ipynb", 53 | "hide_cells": "03_export2html.ipynb", 54 | "clean_exports": "03_export2html.ipynb", 55 | "treat_backticks": "03_export2html.ipynb", 56 | "add_jekyll_notes": "03_export2html.ipynb", 57 | "copy_images": "03_export2html.ipynb", 58 | "adapt_img_path": "03_export2html.ipynb", 59 | "escape_latex": "03_export2html.ipynb", 60 | "collapse_cells": "03_export2html.ipynb", 61 | "remove_hidden": "03_export2html.ipynb", 62 | "find_default_level": "03_export2html.ipynb", 63 | "nb_code_cell": "03_export2html.ipynb", 64 | "add_show_docs": "03_export2html.ipynb", 65 | "remove_fake_headers": "03_export2html.ipynb", 66 | "remove_empty": "03_export2html.ipynb", 67 | "get_metadata": "03_export2html.ipynb", 68 | "ExecuteShowDocPreprocessor": "03_export2html.ipynb", 69 | "execute_nb": "03_export2html.ipynb", 70 | "cite2link": "03_export2html.ipynb", 71 | "write_tmpl": "03_export2html.ipynb", 72 | "write_tmpls": "03_export2html.ipynb", 73 | "nbdev_build_lib": "03_export2html.ipynb", 74 | "nbdev_exporter": "03_export2html.ipynb", 75 | "process_cells": "03_export2html.ipynb", 76 | "process_cell": "03_export2html.ipynb", 77 | "convert_nb": "03_export2html.ipynb", 78 | "notebook2html": "03_export2html.ipynb", 79 | "convert_md": "03_export2html.ipynb", 80 | "nbdev_detach": "03_export2html.ipynb", 81 | "make_readme": "03_export2html.ipynb", 82 | "nbdev_build_docs": "03_export2html.ipynb", 83 | "nbdev_nb2md": "03_export2html.ipynb", 84 | "create_default_sidebar": "03_export2html.ipynb", 85 | "make_sidebar": "03_export2html.ipynb", 86 | "get_all_flags": "04_test.ipynb", 87 | "get_cell_flags": "04_test.ipynb", 88 | "NoExportPreprocessor": "04_test.ipynb", 89 | "test_nb": "04_test.ipynb", 90 | "nbdev_test_nbs": "04_test.ipynb", 91 | "nbdev_read_nbs": "04_test.ipynb", 92 | "extract_cells": "05_merge.ipynb", 93 | "get_md_cell": "05_merge.ipynb", 94 | "conflicts": "05_merge.ipynb", 95 | "same_inputs": "05_merge.ipynb", 96 | "analyze_cell": "05_merge.ipynb", 97 | "nbdev_fix_merge": "05_merge.ipynb", 98 | "bump_version": "06_cli.ipynb", 99 | "nbdev_bump_version": "06_cli.ipynb", 100 | "nbdev_install_git_hooks": "06_cli.ipynb", 101 | "extract_tgz": "06_cli.ipynb", 102 | "nbdev_new": "06_cli.ipynb", 103 | "rm_execution_count": "07_clean.ipynb", 104 | "clean_output_data_vnd": "07_clean.ipynb", 105 | "colab_json": "07_clean.ipynb", 106 | "clean_cell_output": "07_clean.ipynb", 107 | "cell_metadata_keep": "07_clean.ipynb", 108 | "nb_metadata_keep": "07_clean.ipynb", 109 | "clean_cell": "07_clean.ipynb", 110 | "clean_nb": "07_clean.ipynb", 111 | "nbdev_clean_nbs": "07_clean.ipynb", 112 | "S1": "nbdev_comments.ipynb", 113 | "S2": "nbdev_comments.ipynb", 114 | "S3": "nbdev_comments.ipynb", 115 | "say_hello": "tutorial.ipynb", 116 | "HelloSayer": "tutorial.ipynb"} 117 | 118 | modules = ["export.py", 119 | "sync.py", 120 | "showdoc.py", 121 | "export2html.py", 122 | "test.py", 123 | "merge.py", 124 | "cli.py", 125 | "clean.py", 126 | "nbdev_comments.py", 127 | "tutorial.py"] 128 | 129 | doc_url = "https://nbdev.fast.ai/" 130 | 131 | git_url = "https://github.com/fastai/nbdev/tree/master/" 132 | 133 | def custom_doc_links(name): return None 134 | -------------------------------------------------------------------------------- /nbdev/sync.py: -------------------------------------------------------------------------------- 1 | # AUTOGENERATED! DO NOT EDIT! File to edit: nbs/01_sync.ipynb (unless otherwise specified). 2 | 3 | __all__ = ['get_name', 'qual_name', 'source_nb', 'relimport2name', 'nbdev_update_lib', 'nbdev_diff_nbs', 4 | 'nbdev_trust_nbs'] 5 | 6 | # Cell 7 | from .imports import * 8 | from .export import * 9 | from fastcore.script import * 10 | import nbformat 11 | from nbformat.sign import NotebookNotary 12 | 13 | # Cell 14 | def _get_property_name(p): 15 | "Get the name of property `p`" 16 | if hasattr(p, 'fget'): 17 | return p.fget.func.__qualname__ if hasattr(p.fget, 'func') else p.fget.__qualname__ 18 | else: return next(iter(re.findall(r'\'(.*)\'', str(p)))).split('.')[-1] 19 | 20 | def get_name(obj): 21 | "Get the name of `obj`" 22 | if hasattr(obj, '__name__'): return obj.__name__ 23 | elif getattr(obj, '_name', False): return obj._name 24 | elif hasattr(obj,'__origin__'): return str(obj.__origin__).split('.')[-1] #for types 25 | elif type(obj)==property: return _get_property_name(obj) 26 | else: return str(obj).split('.')[-1] 27 | 28 | # Cell 29 | def qual_name(obj): 30 | "Get the qualified name of `obj`" 31 | if hasattr(obj,'__qualname__'): return obj.__qualname__ 32 | if inspect.ismethod(obj): return f"{get_name(obj.__self__)}.{get_name(fn)}" 33 | return get_name(obj) 34 | 35 | # Cell 36 | def source_nb(func, is_name=None, return_all=False, mod=None): 37 | "Return the name of the notebook where `func` was defined" 38 | is_name = is_name or isinstance(func, str) 39 | if mod is None: mod = get_nbdev_module() 40 | index = mod.index 41 | name = func if is_name else qual_name(func) 42 | while len(name) > 0: 43 | if name in index: return (name,index[name]) if return_all else index[name] 44 | name = '.'.join(name.split('.')[:-1]) 45 | 46 | # Cell 47 | _re_cell = re.compile(r'^# Cell|^# Internal Cell|^# Comes from\s+(\S+), cell') 48 | 49 | # Cell 50 | def _split(code): 51 | lines = code.split('\n') 52 | nbs_path = get_config().path("nbs_path").relative_to(get_config().config_file.parent) 53 | prefix = '' if nbs_path == Path('.') else f'{nbs_path}/' 54 | default_nb = re.search(f'File to edit: {prefix}(\\S+)\\s+', lines[0]).groups()[0] 55 | s,res = 1,[] 56 | while _re_cell.search(lines[s]) is None: s += 1 57 | e = s+1 58 | while e < len(lines): 59 | while e < len(lines) and _re_cell.search(lines[e]) is None: e += 1 60 | grps = _re_cell.search(lines[s]).groups() 61 | nb = grps[0] or default_nb 62 | content = lines[s+1:e] 63 | while len(content) > 1 and content[-1] == '': content = content[:-1] 64 | res.append((nb, '\n'.join(content))) 65 | s,e = e,e+1 66 | return res 67 | 68 | # Cell 69 | def relimport2name(name, mod_name): 70 | "Unwarps a relative import in `name` according to `mod_name`" 71 | mod_name = str(Path(mod_name)) 72 | if mod_name.endswith('.py'): mod_name = mod_name[:-3] 73 | mods = mod_name.split(os.path.sep) 74 | i = last_index(get_config().lib_name, mods) 75 | mods = mods[i:] 76 | if name=='.': return '.'.join(mods[:-1]) 77 | i = 0 78 | while name[i] == '.': i += 1 79 | return '.'.join(mods[:-i] + [name[i:]]) 80 | 81 | # Cell 82 | #Catches any from .bla import something and catches .bla in group 1, the imported thing(s) in group 2. 83 | _re_loc_import = re.compile(r'(\s*)from(\s+)(\.\S*)(\s+)import(\s+)(.*)$') 84 | _re_loc_import1 = re.compile(r'(\s*)import(\s+)(\.\S*)(.*)$') 85 | 86 | # Cell 87 | def _deal_loc_import(code, fname): 88 | def _replace(m): 89 | s1,s2,mod,s3,s4,obj = m.groups() 90 | return f"{s1}from{s2}{relimport2name(mod, fname)}{s3}import{s4}{obj}" 91 | def _replace1(m): 92 | s1,s2,mod,end = m.groups() 93 | return f"{s1}import{s2}{relimport2name(mod, fname)}{end}" 94 | return '\n'.join([_re_loc_import1.sub(_replace1, _re_loc_import.sub(_replace,line)) for line in code.split('\n')]) 95 | 96 | # Cell 97 | def _script2notebook(fname, dic, silent=False): 98 | "Put the content of `fname` back in the notebooks it came from." 99 | if os.environ.get('IN_TEST',0): return # don't export if running tests 100 | fname = Path(fname) 101 | with open(fname, encoding='utf8') as f: code = f.read() 102 | splits = _split(code) 103 | rel_name = fname.absolute().resolve().relative_to(get_config().path("lib_path")) 104 | key = str(rel_name.with_suffix('')) 105 | assert len(splits)==len(dic[key]), f'"{rel_name}" exported from notebooks should have {len(dic[key])} cells but has {len(splits)}.' 106 | assert all([c1[0]==c2[1]] for c1,c2 in zip(splits, dic[key])) 107 | splits = [(c2[0],c1[0],c1[1]) for c1,c2 in zip(splits, dic[key])] 108 | nb_fnames = {get_config().path("nbs_path")/s[1] for s in splits} 109 | for nb_fname in nb_fnames: 110 | nb = read_nb(nb_fname) 111 | for i,f,c in splits: 112 | c = _deal_loc_import(c, str(fname)) 113 | if f == nb_fname.name: 114 | flags = split_flags_and_code(nb['cells'][i], str)[0] 115 | nb['cells'][i]['source'] = flags + '\n' + c.replace('', '') 116 | NotebookNotary().sign(nb) 117 | nbformat.write(nb, str(nb_fname), version=4) 118 | 119 | if not silent: print(f"Converted {rel_name}.") 120 | 121 | # Cell 122 | @call_parse 123 | def nbdev_update_lib( 124 | fname:str=None, # A python filename or glob to convert 125 | silent:bool_arg=False # Dont print results 126 | ): 127 | "Propagates any change in the modules matching `fname` to the notebooks that created them" 128 | if fname and fname.endswith('.ipynb'): raise ValueError("`nbdev_update_lib` operates on .py files. If you wish to convert notebooks instead, see `nbdev_build_lib`.") 129 | if os.environ.get('IN_TEST',0): return 130 | dic = notebook2script(silent=True, to_dict=True) 131 | exported = get_nbdev_module().modules 132 | 133 | files = nbglob(fname, extension='.py', config_key='lib_path') 134 | files = files.filter(lambda x: str(x.relative_to(get_config().path("lib_path"))) in exported) 135 | files.map(partial(_script2notebook, dic=dic, silent=silent)) 136 | 137 | # Cell 138 | import subprocess 139 | from distutils.dir_util import copy_tree 140 | 141 | # Cell 142 | @call_parse 143 | def nbdev_diff_nbs(): 144 | "Prints the diff between an export of the library in notebooks and the actual modules" 145 | cfg = get_config() 146 | lib_folder = cfg.path("lib_path") 147 | with tempfile.TemporaryDirectory() as d1, tempfile.TemporaryDirectory() as d2: 148 | copy_tree(cfg.path("lib_path"), d1) 149 | notebook2script(silent=True) 150 | copy_tree(cfg.path("lib_path"), d2) 151 | shutil.rmtree(cfg.path("lib_path")) 152 | shutil.copytree(d1, str(cfg.path("lib_path"))) 153 | for d in [d1, d2]: 154 | if (Path(d)/'__pycache__').exists(): shutil.rmtree(Path(d)/'__pycache__') 155 | res = subprocess.run(['diff', '-ru', d1, d2], stdout=subprocess.PIPE) 156 | print(res.stdout.decode('utf-8')) 157 | 158 | # Cell 159 | @call_parse 160 | def nbdev_trust_nbs( 161 | fname:str=None, # A notebook name or glob to convert 162 | force_all:bool=False # Trust even notebooks that havent changed 163 | ): 164 | "Trust notebooks matching `fname`" 165 | check_fname = get_config().path("nbs_path")/".last_checked" 166 | last_checked = os.path.getmtime(check_fname) if check_fname.exists() else None 167 | files = nbglob(fname) 168 | for fn in files: 169 | if last_checked and not force_all: 170 | last_changed = os.path.getmtime(fn) 171 | if last_changed < last_checked: continue 172 | nb = read_nb(fn) 173 | if not NotebookNotary().check_signature(nb): NotebookNotary().sign(nb) 174 | check_fname.touch(exist_ok=True) -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![](https://github.com/fastai/nbdev/workflows/CI/badge.svg) 2 | 3 | 4 | # Welcome to nbdev 5 | > Create delightful python projects using Jupyter Notebooks 6 | 7 | 8 | `nbdev` is a library that allows you to develop a python library in [Jupyter Notebooks](https://jupyter.org/), putting all your code, tests and documentation in one place. That is: you now have a true [literate programming](https://en.wikipedia.org/wiki/Literate_programming) environment, as envisioned by Donald Knuth back in 1983! 9 | 10 | `nbdev` makes debugging and refactoring your code much easier relative to traditional programming environments. Furthermore, using nbdev promotes software engineering best practices because tests and documentation are first class citizens. 11 | 12 | The developers use this regularly on macOS and Linux. We have not tested it on Windows and not all features may work correctly. 13 | 14 | ## Features of Nbdev 15 | 16 | `nbdev` provides the following tools for developers: 17 | 18 | - **Automatically generate docs** from Jupyter notebooks. These docs are searchable and automatically hyperlinked to appropriate documentation pages by introspecting keywords you surround in backticks. 19 | - Utilities to **automate the publishing of pypi and conda packages** including version number management. 20 | - A robust, **two-way sync between notebooks and source code**, which allow you to use your IDE for code navigation or quick edits if desired. 21 | - **Fine-grained control on hiding/showing cells**: you can choose to hide entire cells, just the output, or just the input. Furthermore, you can embed cells in collapsible elements that are open or closed by default. 22 | - Ability to **write tests directly in notebooks** without having to learn special APIs. These tests get executed in parallel with a single CLI command. You can even define certain groups of tests such that you don't have to always run long-running tests. 23 | - Tools for **merge/conflict resolution** with notebooks in a **human readable format**. 24 | - **Continuous integration (CI) comes setup for you with [GitHub Actions](https://github.com/features/actions)** out of the box, that will run tests automatically for you. Even if you are not familiar with CI or GitHub Actions, this starts working right away for you without any manual intervention. 25 | - **Integration With GitHub Pages for docs hosting**: nbdev allows you to easily host your documentation for free, using GitHub pages. 26 | - Create Python modules, following **best practices such as automatically defining `__all__`** ([more details](http://xion.io/post/code/python-all-wild-imports.html)) with your exported functions, classes, and variables. 27 | - **Math equation support** with LaTeX. 28 | - ... and much more! See the [Getting Started](https://nbdev.fast.ai/#Getting-Started) section below for more information. 29 | 30 | ## A Motivating Example 31 | 32 | For example, lets define a class that represents a playing card, with associated docs and tests in a Jupyter Notebook: 33 | 34 | ![image.png](nbs/images/att_00027.png) 35 | 36 | In the above screenshot, we have code, tests and documentation in one context! `nbdev` renders this into searchable docs (which are optionally hosted for free on GitHub Pages). Below is an annotated screenshot of the generated docs for further explanation: 37 | 38 | ![image.png](nbs/images/att_00016.png) 39 | 40 | The above illustration is a subset of [this nbdev tutorial with a minimal example](https://nbdev.fast.ai/example.html), which uses code from [Think Python 2](https://github.com/AllenDowney/ThinkPython2) by Allen Downey. 41 | 42 | ### Explanation of annotations: 43 | 44 | 1. The heading **Card** corresponds to the first `H1` heading in a notebook with a note block _API Details_ as the summary. 45 | 2. `nbdev` automatically renders a Table of Contents for you. 46 | 3. `nbdev` automatically renders the signature of your class or function as a heading. 47 | 4. The cells where your code is defined will be hidden and replaced by standardized documentation of your function, showing its name, arguments, docstring, and link to the source code on github. 48 | 5. This part of docs is rendered automatically from the docstring. 49 | 6. The rest of the notebook is rendered as usual. You can hide entire cells, hide only cell input or hide only output by using the [flags described on this page](https://nbdev.fast.ai/export2html.html). 50 | 7. nbdev supports special block quotes that render as colored boxes in the documentation. You can read more about them [here](https://nbdev.fast.ai/export2html.html#add_jekyll_notes). In this specific example, we are using the `Note` block quote. 51 | 8. Words you surround in backticks will be automatically hyperlinked to the associated documentation where appropriate. This is a trivial case where `Card` class is defined immediately above, however this works across pages and modules. We will see another example of this in later steps. 52 | 53 | ## Installing 54 | 55 | nbdev is on PyPI and conda so you can just run `pip install nbdev` or `conda install -c fastai nbdev`. Microsoft Windows users should use `pip` instead of `conda` to install nbdev. 56 | 57 | For an [editable install](https://stackoverflow.com/questions/35064426/when-would-the-e-editable-option-be-useful-with-pip-install), use the following: 58 | ``` 59 | git clone https://github.com/fastai/nbdev 60 | pip install -e nbdev 61 | ``` 62 | 63 | nbdev is tested to work on Ubuntu, Macos and Windows, for the versions tagged with the `-latest` suffix in [these docs](https://docs.github.com/en/actions/reference/specifications-for-github-hosted-runners#supported-runners-and-hardware-resources). 64 | 65 | _Note that `nbdev` must be installed into the same python environment that you use for both your Jupyter Server and your workspace._ 66 | 67 | ## Getting Started 68 | 69 | The following are helpful resources for getting started with nbdev: 70 | 71 | - The [tutorial](https://nbdev.fast.ai/tutorial.html). 72 | - A [minimal, end-to-end example](https://nbdev.fast.ai/example.html) of using nbdev. We suggest replicating this example after reading through the tutorial to solidify your understanding. 73 | - The [docs](https://nbdev.fast.ai/). 74 | - [release notes](https://github.com/fastai/nbdev/blob/master/CHANGELOG.md). 75 | 76 | 77 | ## If Someone Tells You Should Not Use Notebooks For Software Development 78 | 79 | [Watch this video](https://youtu.be/9Q6sLbz37gk). 80 | 81 | ## Contributing 82 | 83 | If you want to contribute to `nbdev`, be sure to review the [contributions guidelines](https://github.com/fastai/nbdev/blob/master/CONTRIBUTING.md). This project adheres to fastai`s [code of conduct](https://github.com/fastai/nbdev/blob/master/CODE-OF-CONDUCT.md). By participating, you are expected to uphold this code. In general, the fastai project strives to abide by generally accepted best practices in open-source software development. 84 | 85 | Make sure you have the git hooks we use installed by running 86 | ``` 87 | nbdev_install_git_hooks 88 | ``` 89 | in the cloned repository folder. 90 | 91 | ## Copyright 92 | 93 | Copyright 2019 onwards, fast.ai, Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this project's files except in compliance with the License. A copy of the License is provided in the LICENSE file in this repository. 94 | 95 | ## Appendix 96 | 97 | ### nbdev and fastai 98 | 99 | `nbdev` has been used to build innovative software used by many developers, such as [fastai](https://docs.fast.ai/), a deep learning library which implements a [unique layered api and callback system](https://arxiv.org/abs/2002.04688), and [fastcore](https://fastcore.fast.ai/), an extension to the Python programming language. Furthermore, `nbdev` allows a very small number of developers to maintain and grow a [large ecosystem](https://github.com/fastai) of software engineering, data science, machine learning and devops tools. 100 | 101 | Here, for instance, is how `combined_cos` is defined and documented in the `fastai` library: 102 | 103 | Exporting from nbdev 104 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # How to contribute to fastai 2 | 3 | First, thanks a lot for wanting to help! Make sure you have read the [doc on code style]( 4 | https://docs.fast.ai/dev/style.html) first. (Note that we don't follow PEP8, but instead follow a coding style designed specifically for numerical and interactive programming.) For help running and building the code, see the [developers guide](https://docs.fast.ai/dev/develop.html). 5 | 6 | ## Note for new contributors from Jeremy 7 | 8 | It can be tempting to jump into a new project by questioning the stylistic decisions that have been made, such as naming, formatting, and so forth. This can be especially so for python programmers contributing to this project, which is unusual in following a number of conventions that are common in other programming communities, but not in Python. However, please don’t do this, for (amongst others) the following reasons: 9 | 10 | - Contributing to [Parkinson’s law of triviality](https://www.wikiwand.com/en/Law_of_triviality) has negative consequences for a project. Let’s focus on deep learning! 11 | - It’s exhausting to repeat the same discussion over and over again, especially when it’s been well documented already. When you have a question about the project, please check the pages in the docs website linked here. 12 | - You’re likely to get a warmer welcome from the community if you start out by contributing something that’s been requested on the forum, since you’ll be solving someone’s current problem. 13 | - If you start out by just telling us your point of view, rather than studying the background behind the decisions that have been made, you’re unlikely to be contributing anything new or useful. 14 | - I’ve been writing code for nearly 40 years now, across dozens of languages, and other folks involved have quite a bit of experience too - the approaches used are based on significant experience and research. Whilst there’s always room for improvement, it’s much more likely you’ll be making a positive contribution if you spend a few weeks studying and working within the current framework before suggesting wholesale changes. 15 | 16 | ## How to get started 17 | 18 | Here are some ways that you can learn a lot about the library, whilst also contributing to the community: 19 | 20 | - Pick a class, function, or method and write tests for it. For instance, here are the tests for [fastai.core](https://github.com/fastai/fastai1/blob/master/tests/test_core.py). Adding tests for anything without good test coverage is a great way to really understand that part of the library deeply, and have in-depth conversations with the dev team about the reasoning behind decisions in the code. 21 | - Document something that is currently undocumented. You can find them by looking for the “new methods” section in any doc notebook. Here’s a [search](https://github.com/fastai/fastai/search?q=%22new+methods%22&unscoped_q=%22new+methods%22) that lists them 22 | - Add an example of use to the docs for something that doesn’t currently have an example of use. We’d like everything soon in the docs to include an actual piece of working code demonstrating it. Currently, we’ve largely only provided working examples for stuff higher up the abstraction ladder. 23 | 24 | ## Did you find a bug? 25 | 26 | * Nobody is perfect, especially not us. But first, please double-check the bug doesn't come from something on your side. The [forum](http://forums.fast.ai/) is a tremendous source for help, and we'd advise to use it as a first step. Be sure to include as much code as you can so that other people can easily help you. 27 | * Then, ensure the bug was not already reported by searching on GitHub under [Issues](https://github.com/fastai/fastai/issues). 28 | * If you're unable to find an open issue addressing the problem, [open a new one](https://github.com/fastai/fastai/issues/new). Be sure to include a title and clear description, as much relevant information as possible, and a code sample or an executable test case demonstrating the expected behavior that is not occurring. 29 | * Be sure to add the complete error messages as well as the result of the line `import fastai.utils.collect_env; fastai.utils.collect_env.show_install(1)`. 30 | 31 | #### Did you write a patch that fixes a bug? 32 | 33 | * Open a new GitHub pull request with the patch. 34 | * Ensure that your PR includes [tests](https://docs.fast.ai/dev/test.html) that fail without your patch, and pass with it. 35 | * Ensure the PR description clearly describes the problem and solution. Include the relevant issue number if applicable. 36 | * Before submitting, please be sure you abide by our [coding style](https://docs.fast.ai/dev/style.html) and [the guide on abbreviations](https://docs.fast.ai/dev/abbr.html) and clean-up your code accordingly. 37 | 38 | ## Do you intend to add a new feature or change an existing one? 39 | 40 | **Please take note that we are in the midst of making several breaking changes with the preparation of v1.1 so we suggest you wait a little bit before starting coding it.** 41 | 42 | * You can suggest your change on the [fastai forum](http://forums.fast.ai/) to see if others are interested or want to help. [This topic](http://forums.fast.ai/t/fastai-v1-adding-features/23041/8) lists the features that will be added to fastai in the foreseeable future. Be sure to read it too! 43 | * Before implementing a non-trivial new feature, first create a notebook version of your new feature, like those in [dev_nb](https://github.com/fastai/fastai_docs/tree/master/dev_nb). It should show step-by-step what your code is doing, and why, with the result of each step. Try to simplify the code as much as possible. When you're happy with it, let us know on the forum (include a link to gist with your notebook.) 44 | * Once your approach has been discussed and confirmed on the forum, you are welcome to push a PR, including a complete description of the new feature and an example of how it's used. Be sure to document your code and read the [doc on code style](https://docs.fast.ai/dev/style.html) and [the one on abbreviations](https://docs.fast.ai/dev/abbr.html). 45 | * Ensure that your PR includes [tests](https://docs.fast.ai/dev/test.html) that exercise not only your feature, but also any other code that might be impacted. Currently we have poor test coverage of existing features, so often you'll need to add tests of existing code. Your help here is much appreciated! 46 | 47 | ## How to submit notebook PRs? 48 | 49 | * If your PR involves jupyter notebooks (`.ipynb`), then before submitting your PR you must first: run `nbdev_build_lib` if there are any library changes, and then clean the notebooks by running `nbdev_clean_nbs`. 50 | 51 | 52 | ## PR submission guidelines 53 | 54 | * Keep each PR focused. While it's more convenient, do not combine several unrelated fixes together. Create as many branches as needing to keep each PR focused. 55 | 56 | * Do not mix style changes/fixes with "functional" changes. It's very difficult to review such PRs and it most likely get rejected. 57 | 58 | * Do not add/remove vertical whitespace. Preserve the original style of the file you edit as much as you can. 59 | 60 | * Do not turn an already submitted PR into your development playground. If after you submitted PR, you discovered that more work is needed - close the PR, do the required work and then submit a new PR. Otherwise each of your commits requires attention from maintainers of the project. 61 | 62 | * If, however, you submitted a PR and received a request for changes, you should proceed with commits inside that PR, so that the maintainer can see the incremental fixes and won't need to review the whole PR again. In the exception case where you realize it'll take many many commits to complete the requests, then it's probably best to close the PR, do the work and then submit it again. Use common sense where you'd choose one way over another. 63 | 64 | 65 | ### Code PRs 66 | 67 | * If your PR is a bug fix, please also include a test that demonstrates the problem, or modifies an existing test that wasn't catching that problem already. Of course, it's not a requirement, so proceed anyway if you can't figure out how to write a test, but do try. Without having a test your fix could be lost down the road. By supplying a test, you're ensuring that your projects won't break in the future. 68 | 69 | * Same applies for PRs that implement new features - without having a test case validating this new feature, it'd be very easy for that new feature to break in the future. A test case ensures that the feature will not break. 70 | 71 | 72 | ## Do you have questions about the source code? 73 | 74 | * Please ask it on the [fastai forum](http://forums.fast.ai/) (after searching someone didn't ask the same one before with a quick search). We'd rather have the maximum of discussions there so that the largest number can benefit from it. 75 | 76 | ## Do you want to contribute to the documentation? 77 | 78 | * Docs are automatically created from the notebooks in the `/nbs` directory. 79 | * To switch the `docs` submodule to ssh, `cd docs && git remote set-url origin git@github.com:fastai/fastai-docs.git` 80 | 81 | -------------------------------------------------------------------------------- /tests/07_clean.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": null, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "#export\n", 10 | "import io,sys,json,glob\n", 11 | "from fastcore.script import call_parse,Param\n", 12 | "from nbdev.imports import Config\n", 13 | "from pathlib import Path" 14 | ] 15 | }, 16 | { 17 | "cell_type": "code", 18 | "execution_count": null, 19 | "metadata": {}, 20 | "outputs": [], 21 | "source": [ 22 | "# default_exp clean" 23 | ] 24 | }, 25 | { 26 | "cell_type": "code", 27 | "execution_count": null, 28 | "metadata": {}, 29 | "outputs": [], 30 | "source": [ 31 | "#hide\n", 32 | "#For tests only\n", 33 | "from nbdev.imports import *" 34 | ] 35 | }, 36 | { 37 | "cell_type": "markdown", 38 | "metadata": {}, 39 | "source": [ 40 | "# Clean notebooks\n", 41 | "\n", 42 | "> Strip notebooks from superfluous metadata" 43 | ] 44 | }, 45 | { 46 | "cell_type": "markdown", 47 | "metadata": {}, 48 | "source": [ 49 | "To avoid pointless conflicts while working with jupyter notebooks (with different execution counts or cell metadata), it is recommended to clean the notebooks before committing anything (done automatically if you install the git hooks with `nbdev_install_git_hooks`). The following functions are used to do that." 50 | ] 51 | }, 52 | { 53 | "cell_type": "markdown", 54 | "metadata": {}, 55 | "source": [ 56 | "## Utils" 57 | ] 58 | }, 59 | { 60 | "cell_type": "code", 61 | "execution_count": null, 62 | "metadata": {}, 63 | "outputs": [], 64 | "source": [ 65 | "# export\n", 66 | "def rm_execution_count(o):\n", 67 | " \"Remove execution count in `o`\"\n", 68 | " if 'execution_count' in o: o['execution_count'] = None" 69 | ] 70 | }, 71 | { 72 | "cell_type": "code", 73 | "execution_count": null, 74 | "metadata": {}, 75 | "outputs": [], 76 | "source": [ 77 | "# export\n", 78 | "def clean_cell_output(cell):\n", 79 | " \"Remove execution count in `cell`\"\n", 80 | " if 'outputs' in cell:\n", 81 | " for o in cell['outputs']: rm_execution_count(o)" 82 | ] 83 | }, 84 | { 85 | "cell_type": "code", 86 | "execution_count": null, 87 | "metadata": {}, 88 | "outputs": [], 89 | "source": [ 90 | "#export\n", 91 | "cell_metadata_keep = [\"hide_input\"]\n", 92 | "nb_metadata_keep = [\"kernelspec\", \"jekyll\", \"jupytext\", \"doc\"]" 93 | ] 94 | }, 95 | { 96 | "cell_type": "code", 97 | "execution_count": null, 98 | "metadata": {}, 99 | "outputs": [], 100 | "source": [ 101 | "# export\n", 102 | "def clean_cell(cell, clear_all=False):\n", 103 | " \"Clean `cell` by removing superfluous metadata or everything except the input if `clear_all`\"\n", 104 | " rm_execution_count(cell)\n", 105 | " if 'outputs' in cell:\n", 106 | " if clear_all: cell['outputs'] = []\n", 107 | " else: clean_cell_output(cell)\n", 108 | " cell['metadata'] = {} if clear_all else {k:v for k,v in cell['metadata'].items() if k in cell_metadata_keep}" 109 | ] 110 | }, 111 | { 112 | "cell_type": "code", 113 | "execution_count": null, 114 | "metadata": {}, 115 | "outputs": [], 116 | "source": [ 117 | "tst = {'cell_type': 'code',\n", 118 | " 'execution_count': 26,\n", 119 | " 'metadata': {'hide_input': True, 'meta': 23},\n", 120 | " 'outputs': [{'execution_count': 2, 'output': 'super'}],\n", 121 | " 'source': 'awesome_code'}\n", 122 | "tst1 = tst.copy()\n", 123 | "\n", 124 | "clean_cell(tst)\n", 125 | "test_eq(tst, {'cell_type': 'code',\n", 126 | " 'execution_count': None,\n", 127 | " 'metadata': {'hide_input': True},\n", 128 | " 'outputs': [{'execution_count': None, 'output': 'super'}],\n", 129 | " 'source': 'awesome_code'})\n", 130 | "\n", 131 | "clean_cell(tst1, clear_all=True)\n", 132 | "test_eq(tst1, {'cell_type': 'code',\n", 133 | " 'execution_count': None,\n", 134 | " 'metadata': {},\n", 135 | " 'outputs': [],\n", 136 | " 'source': 'awesome_code'})" 137 | ] 138 | }, 139 | { 140 | "cell_type": "code", 141 | "execution_count": null, 142 | "metadata": {}, 143 | "outputs": [], 144 | "source": [ 145 | "# export\n", 146 | "def clean_nb(nb, clear_all=False):\n", 147 | " \"Clean `nb` from superfluous metadata, passing `clear_all` to `clean_cell`\"\n", 148 | " for c in nb['cells']: clean_cell(c, clear_all=clear_all)\n", 149 | " nb['metadata'] = {k:v for k,v in nb['metadata'].items() if k in nb_metadata_keep }" 150 | ] 151 | }, 152 | { 153 | "cell_type": "code", 154 | "execution_count": null, 155 | "metadata": {}, 156 | "outputs": [], 157 | "source": [ 158 | "tst = {'cell_type': 'code',\n", 159 | " 'execution_count': 26,\n", 160 | " 'metadata': {'hide_input': True, 'meta': 23},\n", 161 | " 'outputs': [{'execution_count': 2, 'output': 'super'}],\n", 162 | " 'source': 'awesome_code'}\n", 163 | "nb = {'metadata': {'kernelspec': 'some_spec', 'jekyll': 'some_meta', 'meta': 37},\n", 164 | " 'cells': [tst]}\n", 165 | "\n", 166 | "clean_nb(nb)\n", 167 | "test_eq(nb['cells'][0], {'cell_type': 'code',\n", 168 | " 'execution_count': None,\n", 169 | " 'metadata': {'hide_input': True},\n", 170 | " 'outputs': [{'execution_count': None, 'output': 'super'}],\n", 171 | " 'source': 'awesome_code'})\n", 172 | "test_eq(nb['metadata'], {'kernelspec': 'some_spec', 'jekyll': 'some_meta'})" 173 | ] 174 | }, 175 | { 176 | "cell_type": "code", 177 | "execution_count": null, 178 | "metadata": {}, 179 | "outputs": [], 180 | "source": [ 181 | "#export\n", 182 | "import io,sys,json" 183 | ] 184 | }, 185 | { 186 | "cell_type": "code", 187 | "execution_count": null, 188 | "metadata": {}, 189 | "outputs": [], 190 | "source": [ 191 | "# export\n", 192 | "def _print_output(nb):\n", 193 | " \"Print `nb` in stdout for git things\"\n", 194 | " _output_stream = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')\n", 195 | " x = json.dumps(nb, sort_keys=True, indent=1, ensure_ascii=False)\n", 196 | " _output_stream.write(x)\n", 197 | " _output_stream.write(\"\\n\")\n", 198 | " _output_stream.flush()" 199 | ] 200 | }, 201 | { 202 | "cell_type": "markdown", 203 | "metadata": {}, 204 | "source": [ 205 | "## Main function" 206 | ] 207 | }, 208 | { 209 | "cell_type": "code", 210 | "execution_count": null, 211 | "metadata": {}, 212 | "outputs": [], 213 | "source": [ 214 | "# export\n", 215 | "@call_parse\n", 216 | "def nbdev_clean_nbs(fname:Param(\"A notebook name or glob to convert\", str)=None, \n", 217 | " clear_all:Param(\"Clean all metadata and outputs\", bool)=False,\n", 218 | " disp:Param(\"Print the cleaned outputs\", bool)=False,\n", 219 | " read_input_stream:Param(\"Read input stream and not nb folder\")=False):\n", 220 | " \"Clean all notebooks in `fname` to avoid merge conflicts\"\n", 221 | " #Git hooks will pass the notebooks in the stdin\n", 222 | " if read_input_stream and sys.stdin:\n", 223 | " input_stream = io.TextIOWrapper(sys.stdin.buffer, encoding='utf-8')\n", 224 | " nb = json.load(input_stream)\n", 225 | " clean_nb(nb, clear_all=clear_all)\n", 226 | " _print_output(nb)\n", 227 | " return\n", 228 | " if fname is None:\n", 229 | " try: path = get_config().nbs_path\n", 230 | " except Exception as e: path = Path.cwd()\n", 231 | " files = path.glob('**/*.ipynb') if fname is None else glob.glob(fname)\n", 232 | " for f in files:\n", 233 | " if not str(f).endswith('.ipynb'): continue\n", 234 | " nb = json.load(open(f, 'r', encoding='utf-8'))\n", 235 | " clean_nb(nb, clear_all=clear_all)\n", 236 | " if disp: _print_output(nb)\n", 237 | " else: \n", 238 | " x = json.dumps(nb, sort_keys=True, indent=1, ensure_ascii=False)\n", 239 | " with io.open(f, 'w', encoding='utf-8') as f:\n", 240 | " f.write(x)\n", 241 | " f.write(\"\\n\")" 242 | ] 243 | }, 244 | { 245 | "cell_type": "markdown", 246 | "metadata": {}, 247 | "source": [ 248 | "By default (`fname` left to `None`), the all the notebooks in `lib_folder` 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`. `disp` is only used for internal use with git hooks and will print the clean notebook instead of saving it. Same for `read_input_stream` that will read the notebook from the input stream instead of the file names." 249 | ] 250 | }, 251 | { 252 | "cell_type": "markdown", 253 | "metadata": {}, 254 | "source": [ 255 | "## Export -" 256 | ] 257 | }, 258 | { 259 | "cell_type": "code", 260 | "execution_count": null, 261 | "metadata": {}, 262 | "outputs": [ 263 | { 264 | "name": "stdout", 265 | "output_type": "stream", 266 | "text": [ 267 | "Converted 00_export.ipynb.\n", 268 | "Converted 01_sync.ipynb.\n", 269 | "Converted 02_showdoc.ipynb.\n", 270 | "Converted 03_export2html.ipynb.\n", 271 | "Converted 04_test.ipynb.\n", 272 | "Converted 05_merge.ipynb.\n", 273 | "Converted 06_cli.ipynb.\n", 274 | "Converted 07_clean.ipynb.\n", 275 | "Converted 99_search.ipynb.\n", 276 | "Converted index.ipynb.\n", 277 | "Converted tutorial.ipynb.\n" 278 | ] 279 | } 280 | ], 281 | "source": [ 282 | "#hide\n", 283 | "from nbdev.export import *\n", 284 | "notebook2script()" 285 | ] 286 | }, 287 | { 288 | "cell_type": "code", 289 | "execution_count": null, 290 | "metadata": {}, 291 | "outputs": [], 292 | "source": [] 293 | } 294 | ], 295 | "metadata": { 296 | "jupytext": { 297 | "split_at_heading": true 298 | }, 299 | "kernelspec": { 300 | "display_name": "Python 3", 301 | "language": "python", 302 | "name": "python3" 303 | } 304 | }, 305 | "nbformat": 4, 306 | "nbformat_minor": 2 307 | } 308 | -------------------------------------------------------------------------------- /nbs/index.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Welcome to nbdev\n", 8 | "> Create delightful python projects using Jupyter Notebooks\n", 9 | "\n", 10 | "- image:images/nbdev_source.gif" 11 | ] 12 | }, 13 | { 14 | "cell_type": "markdown", 15 | "metadata": {}, 16 | "source": [ 17 | "`nbdev` is a library that allows you to develop a python library in [Jupyter Notebooks](https://jupyter.org/), putting all your code, tests and documentation in one place. That is: you now have a true [literate programming](https://en.wikipedia.org/wiki/Literate_programming) environment, as envisioned by Donald Knuth back in 1983!\n", 18 | "\n", 19 | "`nbdev` makes debugging and refactoring your code much easier relative to traditional programming environments. Furthermore, using nbdev promotes software engineering best practices because tests and documentation are first class citizens.\n", 20 | "\n", 21 | "The developers use this regularly on macOS and Linux. We have not tested it on Windows and not all features may work correctly." 22 | ] 23 | }, 24 | { 25 | "cell_type": "markdown", 26 | "metadata": {}, 27 | "source": [ 28 | "## Features of Nbdev\n", 29 | "\n", 30 | "`nbdev` provides the following tools for developers:\n", 31 | "\n", 32 | "- **Automatically generate docs** from Jupyter notebooks. These docs are searchable and automatically hyperlinked to appropriate documentation pages by introspecting keywords you surround in backticks.\n", 33 | "- Utilities to **automate the publishing of pypi and conda packages** including version number management.\n", 34 | "- A robust, **two-way sync between notebooks and source code**, which allow you to use your IDE for code navigation or quick edits if desired.\n", 35 | "- **Fine-grained control on hiding/showing cells**: you can choose to hide entire cells, just the output, or just the input. Furthermore, you can embed cells in collapsible elements that are open or closed by default.\n", 36 | "- Ability to **write tests directly in notebooks** without having to learn special APIs. These tests get executed in parallel with a single CLI command. You can even define certain groups of tests such that you don't have to always run long-running tests. \n", 37 | "- Tools for **merge/conflict resolution** with notebooks in a **human readable format**.\n", 38 | "- **Continuous integration (CI) comes setup for you with [GitHub Actions](https://github.com/features/actions)** out of the box, that will run tests automatically for you. Even if you are not familiar with CI or GitHub Actions, this starts working right away for you without any manual intervention.\n", 39 | "- **Integration With GitHub Pages for docs hosting**: nbdev allows you to easily host your documentation for free, using GitHub pages.\n", 40 | "- Create Python modules, following **best practices such as automatically defining `__all__`** ([more details](http://xion.io/post/code/python-all-wild-imports.html)) with your exported functions, classes, and variables.\n", 41 | "- **Math equation support** with LaTeX.\n", 42 | "- ... and much more! See the [Getting Started](https://nbdev.fast.ai/#Getting-Started) section below for more information." 43 | ] 44 | }, 45 | { 46 | "cell_type": "markdown", 47 | "metadata": {}, 48 | "source": [ 49 | "## A Motivating Example\n", 50 | "\n", 51 | "For example, lets define a class that represents a playing card, with associated docs and tests in a Jupyter Notebook:\n", 52 | "\n", 53 | "![image.png](images/att_00027.png)\n", 54 | "\n", 55 | "In the above screenshot, we have code, tests and documentation in one context! `nbdev` renders this into searchable docs (which are optionally hosted for free on GitHub Pages). Below is an annotated screenshot of the generated docs for further explanation:\n", 56 | "\n", 57 | "![image.png](images/att_00016.png)\n", 58 | "\n", 59 | "The above illustration is a subset of [this nbdev tutorial with a minimal example](https://nbdev.fast.ai/example.html), which uses code from [Think Python 2](https://github.com/AllenDowney/ThinkPython2) by Allen Downey.\n", 60 | "\n", 61 | "### Explanation of annotations:\n", 62 | "\n", 63 | "1. The heading **Card** corresponds to the first `H1` heading in a notebook with a note block _API Details_ as the summary.\n", 64 | "2. `nbdev` automatically renders a Table of Contents for you.\n", 65 | "3. `nbdev` automatically renders the signature of your class or function as a heading. \n", 66 | "4. The cells where your code is defined will be hidden and replaced by standardized documentation of your function, showing its name, arguments, docstring, and link to the source code on github.\n", 67 | "5. This part of docs is rendered automatically from the docstring.\n", 68 | "6. The rest of the notebook is rendered as usual. You can hide entire cells, hide only cell input or hide only output by using the [flags described on this page](https://nbdev.fast.ai/export2html.html).\n", 69 | "7. nbdev supports special block quotes that render as colored boxes in the documentation. You can read more about them [here](https://nbdev.fast.ai/export2html.html#add_jekyll_notes). In this specific example, we are using the `Note` block quote. \n", 70 | "8. Words you surround in backticks will be automatically hyperlinked to the associated documentation where appropriate. This is a trivial case where `Card` class is defined immediately above, however this works across pages and modules. We will see another example of this in later steps." 71 | ] 72 | }, 73 | { 74 | "cell_type": "markdown", 75 | "metadata": {}, 76 | "source": [ 77 | "## Installing" 78 | ] 79 | }, 80 | { 81 | "cell_type": "markdown", 82 | "metadata": {}, 83 | "source": [ 84 | "nbdev is on PyPI and conda so you can just run `pip install nbdev` or `conda install -c fastai nbdev`. Microsoft Windows users should use `pip` instead of `conda` to install nbdev. \n", 85 | "\n", 86 | "For an [editable install](https://stackoverflow.com/questions/35064426/when-would-the-e-editable-option-be-useful-with-pip-install), use the following:\n", 87 | "```\n", 88 | "git clone https://github.com/fastai/nbdev\n", 89 | "pip install -e nbdev\n", 90 | "```\n", 91 | "\n", 92 | "nbdev is tested to work on Ubuntu, Macos and Windows, for the versions tagged with the `-latest` suffix in [these docs](https://docs.github.com/en/actions/reference/specifications-for-github-hosted-runners#supported-runners-and-hardware-resources). \n", 93 | "\n", 94 | "_Note that `nbdev` must be installed into the same python environment that you use for both your Jupyter Server and your workspace._" 95 | ] 96 | }, 97 | { 98 | "cell_type": "markdown", 99 | "metadata": {}, 100 | "source": [ 101 | "## Getting Started\n", 102 | "\n", 103 | "The following are helpful resources for getting started with nbdev:\n", 104 | "\n", 105 | "- The [tutorial](https://nbdev.fast.ai/tutorial.html).\n", 106 | "- A [minimal, end-to-end example](https://nbdev.fast.ai/example.html) of using nbdev. We suggest replicating this example after reading through the tutorial to solidify your understanding.\n", 107 | "- The [docs](https://nbdev.fast.ai/).\n", 108 | "- [release notes](https://github.com/fastai/nbdev/blob/master/CHANGELOG.md).\n", 109 | "\n", 110 | "\n", 111 | "## If Someone Tells You Should Not Use Notebooks For Software Development\n", 112 | "\n", 113 | "[Watch this video](https://youtu.be/9Q6sLbz37gk)." 114 | ] 115 | }, 116 | { 117 | "cell_type": "markdown", 118 | "metadata": {}, 119 | "source": [ 120 | "## Contributing" 121 | ] 122 | }, 123 | { 124 | "cell_type": "markdown", 125 | "metadata": {}, 126 | "source": [ 127 | "If you want to contribute to `nbdev`, be sure to review the [contributions guidelines](https://github.com/fastai/nbdev/blob/master/CONTRIBUTING.md). This project adheres to fastai`s [code of conduct](https://github.com/fastai/nbdev/blob/master/CODE-OF-CONDUCT.md). By participating, you are expected to uphold this code. In general, the fastai project strives to abide by generally accepted best practices in open-source software development.\n", 128 | "\n", 129 | "Make sure you have the git hooks we use installed by running\n", 130 | "```\n", 131 | "nbdev_install_git_hooks\n", 132 | "```\n", 133 | "in the cloned repository folder. " 134 | ] 135 | }, 136 | { 137 | "cell_type": "markdown", 138 | "metadata": {}, 139 | "source": [ 140 | "## Copyright" 141 | ] 142 | }, 143 | { 144 | "cell_type": "markdown", 145 | "metadata": {}, 146 | "source": [ 147 | "Copyright 2019 onwards, fast.ai, Inc. Licensed under the Apache License, Version 2.0 (the \"License\"); you may not use this project's files except in compliance with the License. A copy of the License is provided in the LICENSE file in this repository." 148 | ] 149 | }, 150 | { 151 | "cell_type": "markdown", 152 | "metadata": {}, 153 | "source": [ 154 | "## Appendix\n", 155 | "\n", 156 | "### nbdev and fastai" 157 | ] 158 | }, 159 | { 160 | "cell_type": "markdown", 161 | "metadata": {}, 162 | "source": [ 163 | "`nbdev` has been used to build innovative software used by many developers, such as [fastai](https://docs.fast.ai/), a deep learning library which implements a [unique layered api and callback system](https://arxiv.org/abs/2002.04688), and [fastcore](https://fastcore.fast.ai/), an extension to the Python programming language. Furthermore, `nbdev` allows a very small number of developers to maintain and grow a [large ecosystem](https://github.com/fastai) of software engineering, data science, machine learning and devops tools.\n", 164 | "\n", 165 | "Here, for instance, is how `combined_cos` is defined and documented in the `fastai` library:" 166 | ] 167 | }, 168 | { 169 | "cell_type": "markdown", 170 | "metadata": {}, 171 | "source": [ 172 | "\"Exporting" 173 | ] 174 | } 175 | ], 176 | "metadata": { 177 | "jekyll": { 178 | "keywords": "fastai", 179 | "toc": "false" 180 | }, 181 | "jupytext": { 182 | "split_at_heading": true 183 | }, 184 | "kernelspec": { 185 | "display_name": "Python 3", 186 | "language": "python", 187 | "name": "python3" 188 | } 189 | }, 190 | "nbformat": 4, 191 | "nbformat_minor": 2 192 | } 193 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Release notes 2 | 3 | 4 | 5 | ## 1.2.11 6 | 7 | ### New Features 8 | 9 | - support py310 style union annotations ([#636](https://github.com/fastai/nbdev/pull/636)), thanks to [@seeM](https://github.com/seeM) 10 | 11 | ### Bugs Squashed 12 | 13 | - fix `show_doc` for properties ([#635](https://github.com/fastai/nbdev/pull/635)), thanks to [@seeM](https://github.com/seeM) 14 | - `nbdev_nb2md` throws error when called in a notebook ([#381](https://github.com/fastai/nbdev/issues/381)) 15 | 16 | 17 | ## 1.2.10 18 | 19 | ### New Features 20 | 21 | - Added webrick spec to Gemfile. ([#615](https://github.com/fastai/nbdev/pull/615)), thanks to [@MarkB2](https://github.com/MarkB2) 22 | - Change doc() default for docments ([#611](https://github.com/fastai/nbdev/pull/611)), thanks to [@muellerzr](https://github.com/muellerzr) 23 | - Better checks for cls and self ([#596](https://github.com/fastai/nbdev/pull/596)), thanks to [@muellerzr](https://github.com/muellerzr) 24 | - Use the kernel defined in the kernelspec ([#594](https://github.com/fastai/nbdev/pull/594)), thanks to [@dleen](https://github.com/dleen) 25 | - Add in repr for delegates ([#589](https://github.com/fastai/nbdev/pull/589)), thanks to [@muellerzr](https://github.com/muellerzr) 26 | 27 | ### Bugs Squashed 28 | 29 | - Keep module in name when getting the "qualname" ([#606](https://github.com/fastai/nbdev/pull/606)), thanks to [@muellerzr](https://github.com/muellerzr) 30 | - Fix decimal bug ([#604](https://github.com/fastai/nbdev/pull/604)), thanks to [@muellerzr](https://github.com/muellerzr) 31 | - Use the kernel defined in the kernelspec ([#594](https://github.com/fastai/nbdev/pull/594)), thanks to [@dleen](https://github.com/dleen) 32 | - Misc bug fixes + tests ([#593](https://github.com/fastai/nbdev/pull/593)), thanks to [@muellerzr](https://github.com/muellerzr) 33 | 34 | 35 | ## 1.2.9 36 | 37 | ### New Features 38 | 39 | - Implement `show_doc` for dataclass ([#622](https://github.com/fastai/nbdev/pull/622)), thanks to [@MarkB2](https://github.com/MarkB2) 40 | 41 | ### Bugs Squashed 42 | 43 | - Fix show doc for object, class methods. ([#621](https://github.com/fastai/nbdev/pull/621)), thanks to [@v-ahuja](https://github.com/v-ahuja) 44 | - Fix show doc for keywords. ([#619](https://github.com/fastai/nbdev/pull/619)), thanks to [@v-ahuja](https://github.com/v-ahuja) 45 | - Including `@dataclass` breaks `nbdev_build_lib` ([#595](https://github.com/fastai/nbdev/issues/595)) 46 | - `nbdev_nb2md` throws error when called in a notebook ([#381](https://github.com/fastai/nbdev/issues/381)) 47 | 48 | 49 | ## 1.2.7 50 | 51 | ### Bugs Squashed 52 | 53 | - Don't build NBs with no `#default_exp` 54 | 55 | ## 1.2.6 56 | 57 | ### New Features 58 | 59 | - `nbdev_build_libs` now works on a single file even without a `settings.ini` or any `#default_exp` cell 60 | - Handle `#|` as directive prefix 61 | 62 | ### Bugs Squashed 63 | 64 | - nbdev_nb2md throws error when called in a notebook ([#381](https://github.com/fastai/nbdev/issues/381)) 65 | 66 | 67 | ## 1.2.5 68 | 69 | ### New Features 70 | 71 | - Update dependencies 72 | 73 | 74 | ## 1.2.3 75 | 76 | ### Bugs Squashed 77 | 78 | - Pin jinja2 due to deprecation bug in nbconvert 79 | 80 | ## 1.2.2 81 | 82 | ### New Features 83 | 84 | - Update dependencies 85 | 86 | 87 | ## 1.2.1 88 | 89 | ### New Features 90 | 91 | - Make sure docments have linking capability ([#585](https://github.com/fastai/nbdev/pull/585)), thanks to [@muellerzr](https://github.com/muellerzr) 92 | - better logging for duplicate titles ([#584](https://github.com/fastai/nbdev/pull/584)), thanks to [@hamelsmu](https://github.com/hamelsmu) 93 | 94 | ### Bugs Squashed 95 | 96 | - Fix repr issue with `show_doc` ([#588](https://github.com/fastai/nbdev/pull/588)), thanks to [@muellerzr](https://github.com/muellerzr) 97 | 98 | 99 | ## 1.2.0 100 | 101 | - upgrade nbconvert dep to v6 102 | 103 | ## 1.1.23 104 | 105 | ### Bugs Squashed 106 | 107 | - fix verbose flag 108 | 109 | ## 1.1.20 110 | 111 | ### New Features 112 | 113 | - skip symlinks in recursive glob ([#515](https://github.com/fastai/nbdev/issues/515)) 114 | 115 | 116 | ## 1.1.15 117 | 118 | ### Breaking Changes 119 | 120 | - make recursive behavior for `nbdev_build_docs` consistent with `nbdev_build_lib` ([#467](https://github.com/fastai/nbdev/pull/467)), thanks to [@hamelsmu](https://github.com/hamelsmu) 121 | 122 | ### New Features 123 | 124 | - Allow for a one-time only (potentially) .py -> .ipynb generation ([#369](https://github.com/fastai/nbdev/issues/369)) 125 | 126 | ### Bugs Squashed 127 | 128 | - Images with `attachment:` break export ([#501](https://github.com/fastai/nbdev/pull/501)), thanks to [@yacchin1205](https://github.com/yacchin1205) 129 | - Docs nav doesn't work on gitlab ([#488](https://github.com/fastai/nbdev/pull/488)), thanks to [@tcapelle](https://github.com/tcapelle) 130 | - clean up all instances of recursive ([#470](https://github.com/fastai/nbdev/pull/470)), thanks to [@hamelsmu](https://github.com/hamelsmu) 131 | - After 'conda install -c fastai nbdev', error "`HTMLExporter` object has no attribute `template_path`" ([#431](https://github.com/fastai/nbdev/issues/431)) 132 | 133 | 134 | ## 1.1.13 135 | 136 | ### New Features 137 | 138 | - support windows ([#392](https://github.com/fastai/nbdev/pull/392)), thanks to [@mszhanyi](https://github.com/mszhanyi) 139 | - `nbdev_new`: get template from latest release asset ([#382](https://github.com/fastai/nbdev/pull/382)), thanks to [@hamelsmu](https://github.com/hamelsmu) 140 | - Add more license options 141 | 142 | ### Bugs Squashed 143 | 144 | - Fix recursive flag ([#433](https://github.com/fastai/nbdev/pull/433)), thanks to [@hamelsmu](https://github.com/hamelsmu) 145 | - conda not installing nbdev properly on WSL2 ([#430](https://github.com/fastai/nbdev/issues/430)) 146 | - fix nb2md ([#424](https://github.com/fastai/nbdev/pull/424)), thanks to [@hamelsmu](https://github.com/hamelsmu) 147 | - `nbdev_build_lib` seems to convert more notebooks than expected ([#423](https://github.com/fastai/nbdev/issues/423)) 148 | - fix default arg issue with `nbdev_update_lib` ([#416](https://github.com/fastai/nbdev/pull/416)), thanks to [@hamelsmu](https://github.com/hamelsmu) 149 | - `nbdev_update_lib` errors out when fname not supplied ([#415](https://github.com/fastai/nbdev/issues/415)) 150 | - `nbdev_new` fails on calling the GitHub API without guidance ([#404](https://github.com/fastai/nbdev/issues/404)) 151 | - fix recurse issue ([#391](https://github.com/fastai/nbdev/pull/391)), thanks to [@hamelsmu](https://github.com/hamelsmu) 152 | - `nbdev_build_docs`----ModuleNotFoundError: No module named 'fastcore' ([#390](https://github.com/fastai/nbdev/issues/390)) 153 | - `nbdev_test_nbs` --fname broke in 1.1.7 ([#388](https://github.com/fastai/nbdev/issues/388)) 154 | - set recursive=True for docs ([#387](https://github.com/fastai/nbdev/pull/387)), thanks to [@hamelsmu](https://github.com/hamelsmu) 155 | - fix url for getting branch ([#386](https://github.com/fastai/nbdev/pull/386)), thanks to [@hamelsmu](https://github.com/hamelsmu) 156 | - `nbdev_nb2md` throws error when called in a notebook ([#381](https://github.com/fastai/nbdev/issues/381)) 157 | 158 | 159 | ## 1.1.12 160 | 161 | ### New Features 162 | 163 | - `nbdev_new` should grab files from a release asset in `nbdev_template` ([#383](https://github.com/fastai/nbdev/issues/383)) 164 | - Use Jekyll Theme instead of vendoring all required files ([#379](https://github.com/fastai/nbdev/issues/379)) 165 | - Create relevant directories in `docs/_data` if do not already exist ([#377](https://github.com/fastai/nbdev/issues/377)) 166 | 167 | 168 | ## 1.1.6 169 | 170 | ### New Features 171 | 172 | - Clean Google Colab metadata and line endings ([#364](https://github.com/fastai/nbdev/pull/364)), thanks to [@muellerzr](https://github.com/muellerzr) 173 | - add ability to find notebooks recursively ([#359](https://github.com/fastai/nbdev/pull/359)), thanks to [@hamelsmu](https://github.com/hamelsmu) 174 | - Add `bare` flag to `nbdev_build_lib` ([#336](https://github.com/fastai/nbdev/issues/336)) 175 | - install git hooks in `nbdev_new` ([#308](https://github.com/fastai/nbdev/issues/308)) 176 | - `nbdev_new` now works on an existing cloned repo, instead of creating a new repo ([#307](https://github.com/fastai/nbdev/issues/307)) 177 | 178 | ### Bugs Squashed 179 | 180 | - `nbdev_update_lib --fname notebook.ipynb` crashes (while `nbdev_update_lib` works) ([#341](https://github.com/fastai/nbdev/issues/341)) 181 | - Copy new files only if they don't exist for nbdev_new ([#309](https://github.com/fastai/nbdev/issues/309)) 182 | 183 | 184 | ## 1.1.3 185 | 186 | ### New Features 187 | 188 | - Place source code below heading on #exports ([#265](https://github.com/fastai/nbdev/pull/265)), thanks to [@hamelsmu](https://github.com/hamelsmu) 189 | 190 | 191 | ## 1.1.2 192 | 193 | ### Bugs Squashed 194 | 195 | - update fastcore requirement ([#281](https://github.com/fastai/nbdev/issues/281)) 196 | 197 | 198 | ## 1.1.1 199 | 200 | ### New Features 201 | 202 | - Make CLI faster by removing unneeded imports and moving CLI commands to source modules ([#271](https://github.com/fastai/nbdev/issues/271)) 203 | - Move `Config` to fastcore ([#280](https://github.com/fastai/nbdev/issues/280)) 204 | 205 | ## 1.1.0 206 | ### Breaking Changes 207 | 208 | - Remove magics ([#269](https://github.com/fastai/nbdev/issues/269)) 209 | - Removed callbacks ([#253](https://github.com/fastai/nbdev/pull/253)), thanks to [@pete88b](https://github.com/pete88b) 210 | - move conda packager to `fastrelease` ([#252](https://github.com/fastai/nbdev/issues/252)) 211 | 212 | ### New Features 213 | 214 | - Place source code below heading on #exports ([#265](https://github.com/fastai/nbdev/pull/265)), thanks to [@hamelsmu](https://github.com/hamelsmu) 215 | - always skip cells labeled "skip" in test ([#257](https://github.com/fastai/nbdev/issues/257)) 216 | 217 | ## 1.0.17 218 | 219 | ### Bugs Squashed 220 | 221 | - restrict nbconvert<6 to avoid upgrade problems ([#249](https://github.com/fastai/nbdev/issues/249)) 222 | 223 | ## 1.0.16 224 | 225 | ### Bugs Squashed 226 | 227 | - When generating docs, import cells are run even if not exported ([#248](https://github.com/fastai/nbdev/issues/248)) 228 | 229 | ## 1.0.15 230 | 231 | ### New Features 232 | 233 | - add option to not exec nb for fastpages ([#244](https://github.com/fastai/nbdev/issues/244)) 234 | - Enable Codespaces for nbdev ([#243](https://github.com/fastai/nbdev/issues/243)) 235 | 236 | ### Bugs Squashed 237 | 238 | - Fix: correct notebook2html path operation for Windows. ([#239](https://github.com/fastai/nbdev/issues/239)) 239 | 240 | ## 1.0.13 241 | 242 | ### New Features 243 | 244 | - remove numpy conda dep and update to fastcore 1.0.5 ([#241](https://github.com/fastai/nbdev/issues/241)) 245 | 246 | ### Bugs Squashed 247 | 248 | - allow nbdev imports when not in an nbdev project ([#238](https://github.com/fastai/nbdev/issues/238)) 249 | 250 | ## 1.0.10 251 | 252 | ### New Features 253 | 254 | - Magic flags for tests ([#232](https://github.com/fastai/nbdev/pull/232)) 255 | - Add ability to have Colab badges on pages ([#210](https://github.com/fastai/nbdev/pull/210)) 256 | - Support for `doc_path` ([#235](https://github.com/fastai/nbdev/pull/235)) 257 | 258 | ### Bugs Squashed 259 | 260 | - Remove colab vendor specific tags which cause `nbdev_build_docs` to fail ([#207](https://github.com/fastai/nbdev/pull/207)) 261 | - hooks folder inside .git must be manually created before `nbdev_install_git_hooks` ([#230](https://github.com/fastai/nbdev/pull/230)) 262 | - updates to how backtick names are converted to doc links ([#218](https://github.com/fastai/nbdev/pull/218)) 263 | 264 | ## Version 1.0.0 265 | 266 | - Initial release 267 | 268 | 269 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright 2019 onwards, fast.ai, Inc 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | title: Welcome to nbdev 4 | image: images/nbdev_source.gif 5 | 6 | keywords: fastai 7 | sidebar: home_sidebar 8 | 9 | summary: "Create delightful python projects using Jupyter Notebooks" 10 | description: "Create delightful python projects using Jupyter Notebooks" 11 | nb_path: "nbs/index.ipynb" 12 | --- 13 | 22 | 23 |
24 | 25 | {% raw %} 26 | 27 |
28 | 29 |
30 | {% endraw %} 31 | 32 |
33 |
34 |

nbdev is a library that allows you to develop a python library in Jupyter Notebooks, putting all your code, tests and documentation in one place. That is: you now have a true literate programming environment, as envisioned by Donald Knuth back in 1983!

35 |

nbdev makes debugging and refactoring your code much easier relative to traditional programming environments. Furthermore, using nbdev promotes software engineering best practices because tests and documentation are first class citizens.

36 |

The developers use this regularly on macOS and Linux. We have not tested it on Windows and not all features may work correctly.

37 | 38 |
39 |
40 |
41 |
42 |
43 |

Features of Nbdev

nbdev provides the following tools for developers:

44 |
    45 |
  • Automatically generate docs from Jupyter notebooks. These docs are searchable and automatically hyperlinked to appropriate documentation pages by introspecting keywords you surround in backticks.
  • 46 |
  • Utilities to automate the publishing of pypi and conda packages including version number management.
  • 47 |
  • A robust, two-way sync between notebooks and source code, which allow you to use your IDE for code navigation or quick edits if desired.
  • 48 |
  • Fine-grained control on hiding/showing cells: you can choose to hide entire cells, just the output, or just the input. Furthermore, you can embed cells in collapsible elements that are open or closed by default.
  • 49 |
  • Ability to write tests directly in notebooks without having to learn special APIs. These tests get executed in parallel with a single CLI command. You can even define certain groups of tests such that you don't have to always run long-running tests.
  • 50 |
  • Tools for merge/conflict resolution with notebooks in a human readable format.
  • 51 |
  • Continuous integration (CI) comes setup for you with GitHub Actions out of the box, that will run tests automatically for you. Even if you are not familiar with CI or GitHub Actions, this starts working right away for you without any manual intervention.
  • 52 |
  • Integration With GitHub Pages for docs hosting: nbdev allows you to easily host your documentation for free, using GitHub pages.
  • 53 |
  • Create Python modules, following best practices such as automatically defining __all__ (more details) with your exported functions, classes, and variables.
  • 54 |
  • Math equation support with LaTeX.
  • 55 |
  • ... and much more! See the Getting Started section below for more information.
  • 56 |
57 | 58 |
59 |
60 |
61 |
62 |
63 |

A Motivating Example

For example, lets define a class that represents a playing card, with associated docs and tests in a Jupyter Notebook:

64 |

image.png

65 |

In the above screenshot, we have code, tests and documentation in one context! nbdev renders this into searchable docs (which are optionally hosted for free on GitHub Pages). Below is an annotated screenshot of the generated docs for further explanation:

66 |

image.png

67 |

The above illustration is a subset of this nbdev tutorial with a minimal example, which uses code from Think Python 2 by Allen Downey.

68 |

Explanation of annotations:

    69 |
  1. The heading Card corresponds to the first H1 heading in a notebook with a note block API Details as the summary.
  2. 70 |
  3. nbdev automatically renders a Table of Contents for you.
  4. 71 |
  5. nbdev automatically renders the signature of your class or function as a heading.
  6. 72 |
  7. The cells where your code is defined will be hidden and replaced by standardized documentation of your function, showing its name, arguments, docstring, and link to the source code on github.
  8. 73 |
  9. This part of docs is rendered automatically from the docstring.
  10. 74 |
  11. The rest of the notebook is rendered as usual. You can hide entire cells, hide only cell input or hide only output by using the flags described on this page.
  12. 75 |
  13. nbdev supports special block quotes that render as colored boxes in the documentation. You can read more about them here. In this specific example, we are using the Note block quote.
  14. 76 |
  15. Words you surround in backticks will be automatically hyperlinked to the associated documentation where appropriate. This is a trivial case where Card class is defined immediately above, however this works across pages and modules. We will see another example of this in later steps.
  16. 77 |
78 | 79 |
80 |
81 |
82 |
83 |
84 |

Installing

85 |
86 |
87 |
88 |
89 |
90 |

nbdev is on PyPI and conda so you can just run pip install nbdev or conda install -c fastai nbdev. Microsoft Windows users should use pip instead of conda to install nbdev.

91 |

For an editable install, use the following:

92 | 93 |
git clone https://github.com/fastai/nbdev
 94 | pip install -e nbdev
95 |

nbdev is tested to work on Ubuntu, Macos and Windows, for the versions tagged with the -latest suffix in these docs.

96 |

Note that nbdev must be installed into the same python environment that you use for both your Jupyter Server and your workspace.

97 | 98 |
99 |
100 |
101 |
102 |
103 |

Getting Started

The following are helpful resources for getting started with nbdev:

104 | 110 |

If Someone Tells You Should Not Use Notebooks For Software Development

Watch this video.

111 | 112 |
113 |
114 |
115 |
116 |
117 |

Contributing

118 |
119 |
120 |
121 |
122 |
123 |

If you want to contribute to nbdev, be sure to review the contributions guidelines. This project adheres to fastai`s code of conduct. By participating, you are expected to uphold this code. In general, the fastai project strives to abide by generally accepted best practices in open-source software development.

124 |

Make sure you have the git hooks we use installed by running

125 | 126 |
nbdev_install_git_hooks
127 |

in the cloned repository folder.

128 | 129 |
130 |
131 |
132 |
133 |
134 | 135 |
136 |
137 |
138 |
139 |
140 |

Copyright 2019 onwards, fast.ai, Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this project's files except in compliance with the License. A copy of the License is provided in the LICENSE file in this repository.

141 | 142 |
143 |
144 |
145 |
146 |
147 |

Appendix

nbdev and fastai

148 |
149 |
150 |
151 |
152 |
153 |

nbdev has been used to build innovative software used by many developers, such as fastai, a deep learning library which implements a unique layered api and callback system, and fastcore, an extension to the Python programming language. Furthermore, nbdev allows a very small number of developers to maintain and grow a large ecosystem of software engineering, data science, machine learning and devops tools.

154 |

Here, for instance, is how combined_cos is defined and documented in the fastai library:

155 | 156 |
157 |
158 |
159 |
160 |
161 |

{% include image.html alt="Exporting from nbdev" width="700" caption="An example of a function defined in one cell (marked with the export flag) and explained, along with a visual example, in the following cells" max-width="700" file="/images/export_example.png" %}

162 | 163 |
164 |
165 |
166 |
167 | 168 | 169 | -------------------------------------------------------------------------------- /nbs/nbdev_comments.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": null, 6 | "metadata": { 7 | "hide_input": false 8 | }, 9 | "outputs": [], 10 | "source": [ 11 | "#default_exp nbdev_comments\n", 12 | "from nbdev.showdoc import show_doc " 13 | ] 14 | }, 15 | { 16 | "cell_type": "markdown", 17 | "metadata": {}, 18 | "source": [ 19 | "# nbdev comments \n", 20 | "\n", 21 | "> list of all special comments used in nbdev" 22 | ] 23 | }, 24 | { 25 | "cell_type": "markdown", 26 | "metadata": {}, 27 | "source": [ 28 | "nbdev uses special comments as a markup language that allows you to control various aspects of the documentation, how code is exported to modules, and how code is tested." 29 | ] 30 | }, 31 | { 32 | "cell_type": "markdown", 33 | "metadata": {}, 34 | "source": [ 35 | "## Export comments" 36 | ] 37 | }, 38 | { 39 | "cell_type": "markdown", 40 | "metadata": {}, 41 | "source": [ 42 | "nbdev comments for exporting cells to modules." 43 | ] 44 | }, 45 | { 46 | "cell_type": "markdown", 47 | "metadata": {}, 48 | "source": [ 49 | "### #default_exp" 50 | ] 51 | }, 52 | { 53 | "cell_type": "markdown", 54 | "metadata": {}, 55 | "source": [ 56 | "Using `#default_exp module_name` specifies that code exported from this notebook will be placed in the destination \"*module_name.py*\" module. \n", 57 | "Use dots `.` for submodules and do not include the `.py` file extension. For example, `#default_exp module.submodule` sets the destination module to \"*module/submodule.py*\"" 58 | ] 59 | }, 60 | { 61 | "cell_type": "markdown", 62 | "metadata": {}, 63 | "source": [ 64 | "If specific cells need to be exported to a different module, indicate it after #export: `#export special.module` \n", 65 | "\n", 66 | "* To add something to `__all__` if it's not picked automatically, write an exported cell with something like `#add2all \"my_name\"`. If you are not familiar with what `__all__` is used for, have a look at this [link](http://xion.io/post/code/python-all-wild-imports.html). " 67 | ] 68 | }, 69 | { 70 | "cell_type": "markdown", 71 | "metadata": {}, 72 | "source": [ 73 | "### #export" 74 | ] 75 | }, 76 | { 77 | "cell_type": "markdown", 78 | "metadata": {}, 79 | "source": [ 80 | "Add `#export` to each cell you want to be included in your module and the documentation. When no argument is provided to export, this defaults to the module specified by `#default_exp` as described above. " 81 | ] 82 | }, 83 | { 84 | "cell_type": "markdown", 85 | "metadata": {}, 86 | "source": [ 87 | "a cell marked with `#export` will have its signature added to the documentation." 88 | ] 89 | }, 90 | { 91 | "cell_type": "markdown", 92 | "metadata": {}, 93 | "source": [ 94 | "```python\n", 95 | "#export \n", 96 | "class S1():\n", 97 | " def __init__(self, *args, **kwargs):\n", 98 | " pass\n", 99 | "```" 100 | ] 101 | }, 102 | { 103 | "cell_type": "code", 104 | "execution_count": null, 105 | "metadata": {}, 106 | "outputs": [], 107 | "source": [ 108 | "#export \n", 109 | "class S1():\n", 110 | " def __init__(self, *args, **kwargs):\n", 111 | " pass" 112 | ] 113 | }, 114 | { 115 | "cell_type": "markdown", 116 | "metadata": {}, 117 | "source": [ 118 | "### #exports" 119 | ] 120 | }, 121 | { 122 | "cell_type": "markdown", 123 | "metadata": {}, 124 | "source": [ 125 | "`#exports` is just like `#export` but will additionally have the source code added to the documentation." 126 | ] 127 | }, 128 | { 129 | "cell_type": "markdown", 130 | "metadata": {}, 131 | "source": [ 132 | "```python\n", 133 | "#exports \n", 134 | "class S2():\n", 135 | " def __init__(self, *args, **kwargs):\n", 136 | " pass\n", 137 | "```" 138 | ] 139 | }, 140 | { 141 | "cell_type": "code", 142 | "execution_count": null, 143 | "metadata": {}, 144 | "outputs": [], 145 | "source": [ 146 | "#exports \n", 147 | "class S2():\n", 148 | " def __init__(self, *args, **kwargs):\n", 149 | " pass" 150 | ] 151 | }, 152 | { 153 | "cell_type": "markdown", 154 | "metadata": {}, 155 | "source": [ 156 | "### #exporti" 157 | ] 158 | }, 159 | { 160 | "cell_type": "markdown", 161 | "metadata": {}, 162 | "source": [ 163 | "Add `#exporti` for each cell you want exported without it being added to `__all__`, and without it showing up in the docs." 164 | ] 165 | }, 166 | { 167 | "cell_type": "markdown", 168 | "metadata": {}, 169 | "source": [ 170 | "```python\n", 171 | "#exporti\n", 172 | "class S3():\n", 173 | " def __init__(self, *args, **kwargs):\n", 174 | " pass\n", 175 | "```" 176 | ] 177 | }, 178 | { 179 | "cell_type": "code", 180 | "execution_count": null, 181 | "metadata": {}, 182 | "outputs": [], 183 | "source": [ 184 | "#exporti\n", 185 | "class S3():\n", 186 | " def __init__(self, *args, **kwargs):\n", 187 | " pass" 188 | ] 189 | }, 190 | { 191 | "cell_type": "markdown", 192 | "metadata": {}, 193 | "source": [ 194 | "## Hide comments" 195 | ] 196 | }, 197 | { 198 | "cell_type": "markdown", 199 | "metadata": {}, 200 | "source": [ 201 | "nbdev comments for hiding cells, inputs, or outputs." 202 | ] 203 | }, 204 | { 205 | "cell_type": "markdown", 206 | "metadata": {}, 207 | "source": [ 208 | "### #hide" 209 | ] 210 | }, 211 | { 212 | "cell_type": "markdown", 213 | "metadata": {}, 214 | "source": [ 215 | "This comment instructs nbdev to hide the cell when generating the docs." 216 | ] 217 | }, 218 | { 219 | "cell_type": "markdown", 220 | "metadata": {}, 221 | "source": [ 222 | "```python\n", 223 | "#|hide\n", 224 | "print(\"output\")\n", 225 | "```" 226 | ] 227 | }, 228 | { 229 | "cell_type": "code", 230 | "execution_count": null, 231 | "metadata": {}, 232 | "outputs": [ 233 | { 234 | "name": "stdout", 235 | "output_type": "stream", 236 | "text": [ 237 | "output\n" 238 | ] 239 | } 240 | ], 241 | "source": [ 242 | "#|hide\n", 243 | "print(\"output\")" 244 | ] 245 | }, 246 | { 247 | "cell_type": "markdown", 248 | "metadata": {}, 249 | "source": [ 250 | "### #hide_input" 251 | ] 252 | }, 253 | { 254 | "cell_type": "markdown", 255 | "metadata": {}, 256 | "source": [ 257 | "Use `#hide_input` at the top of a cell if you don't want code to be shown in the docs. \n", 258 | "cells containing `#export` or `show_doc` have their code hidden automatically." 259 | ] 260 | }, 261 | { 262 | "cell_type": "code", 263 | "execution_count": null, 264 | "metadata": {}, 265 | "outputs": [ 266 | { 267 | "name": "stdout", 268 | "output_type": "stream", 269 | "text": [ 270 | "This is output. Input is hidden using #hide_input\n" 271 | ] 272 | } 273 | ], 274 | "source": [ 275 | "#hide_input\n", 276 | "print(\"This is output. Input is hidden using #hide_input\")" 277 | ] 278 | }, 279 | { 280 | "cell_type": "markdown", 281 | "metadata": {}, 282 | "source": [ 283 | "### #hide_output" 284 | ] 285 | }, 286 | { 287 | "cell_type": "markdown", 288 | "metadata": {}, 289 | "source": [ 290 | "Use `#hide_output` at the top of a cell if you don't want output to be shown in the docs. " 291 | ] 292 | }, 293 | { 294 | "cell_type": "code", 295 | "execution_count": null, 296 | "metadata": {}, 297 | "outputs": [ 298 | { 299 | "name": "stdout", 300 | "output_type": "stream", 301 | "text": [ 302 | "This is input. Output is hidden using #hide_output\n" 303 | ] 304 | } 305 | ], 306 | "source": [ 307 | "#hide_output\n", 308 | "print(\"This is input. Output is hidden using #hide_output\")" 309 | ] 310 | }, 311 | { 312 | "cell_type": "markdown", 313 | "metadata": {}, 314 | "source": [ 315 | "## Collapse comments" 316 | ] 317 | }, 318 | { 319 | "cell_type": "markdown", 320 | "metadata": {}, 321 | "source": [ 322 | "nbdev comments for having inputs or outputs under a collapsable element. " 323 | ] 324 | }, 325 | { 326 | "cell_type": "markdown", 327 | "metadata": {}, 328 | "source": [ 329 | "### #collapse" 330 | ] 331 | }, 332 | { 333 | "cell_type": "markdown", 334 | "metadata": {}, 335 | "source": [ 336 | "use `#collapse` to include code in the docs under a collapsable element. The collapsable element is closed by default." 337 | ] 338 | }, 339 | { 340 | "cell_type": "code", 341 | "execution_count": null, 342 | "metadata": {}, 343 | "outputs": [ 344 | { 345 | "name": "stdout", 346 | "output_type": "stream", 347 | "text": [ 348 | "This is output. Input is collapsed using #collapse\n" 349 | ] 350 | } 351 | ], 352 | "source": [ 353 | "#collapse\n", 354 | "print(\"This is output. Input is collapsed using #collapse\")" 355 | ] 356 | }, 357 | { 358 | "cell_type": "markdown", 359 | "metadata": {}, 360 | "source": [ 361 | "### #collapse_show" 362 | ] 363 | }, 364 | { 365 | "cell_type": "markdown", 366 | "metadata": {}, 367 | "source": [ 368 | "Using `#collapse_show` in a code cell will include your code under a collapsable element that is open by default." 369 | ] 370 | }, 371 | { 372 | "cell_type": "code", 373 | "execution_count": null, 374 | "metadata": {}, 375 | "outputs": [ 376 | { 377 | "name": "stdout", 378 | "output_type": "stream", 379 | "text": [ 380 | "This is output. Input can be collapsed using #collapse_show\n" 381 | ] 382 | } 383 | ], 384 | "source": [ 385 | "#collapse_show\n", 386 | "print(\"This is output. Input can be collapsed using #collapse_show\")" 387 | ] 388 | }, 389 | { 390 | "cell_type": "markdown", 391 | "metadata": {}, 392 | "source": [ 393 | "### #collapse_output" 394 | ] 395 | }, 396 | { 397 | "cell_type": "markdown", 398 | "metadata": {}, 399 | "source": [ 400 | "use `#collapse_output` to include output in the docs under a collapsable element." 401 | ] 402 | }, 403 | { 404 | "cell_type": "code", 405 | "execution_count": null, 406 | "metadata": {}, 407 | "outputs": [ 408 | { 409 | "name": "stdout", 410 | "output_type": "stream", 411 | "text": [ 412 | "Output is collapsed using #collapse_output\n" 413 | ] 414 | } 415 | ], 416 | "source": [ 417 | "#collapse_output\n", 418 | "print(\"Output is collapsed using #collapse_output\")" 419 | ] 420 | }, 421 | { 422 | "cell_type": "markdown", 423 | "metadata": {}, 424 | "source": [ 425 | "## Docs comments" 426 | ] 427 | }, 428 | { 429 | "cell_type": "markdown", 430 | "metadata": {}, 431 | "source": [ 432 | "### #default_cls_lvl" 433 | ] 434 | }, 435 | { 436 | "cell_type": "markdown", 437 | "metadata": {}, 438 | "source": [ 439 | "This defines the default level of classes in the table of contents (TOC). Use `#default_cls_lvl` followed by a number to se the level (default is 2)." 440 | ] 441 | }, 442 | { 443 | "cell_type": "code", 444 | "execution_count": null, 445 | "metadata": {}, 446 | "outputs": [], 447 | "source": [ 448 | "#default_cls_lvl 4" 449 | ] 450 | }, 451 | { 452 | "cell_type": "markdown", 453 | "metadata": {}, 454 | "source": [ 455 | "above cell changes the level of classes in this notebook to 4. Check TOC at the top of this page." 456 | ] 457 | }, 458 | { 459 | "cell_type": "markdown", 460 | "metadata": {}, 461 | "source": [ 462 | "## Test flags" 463 | ] 464 | }, 465 | { 466 | "cell_type": "markdown", 467 | "metadata": {}, 468 | "source": [ 469 | "Everything that is not an exported cell is considered a test, so you should make sure your notebooks can all run smoothly (and fast) if you want to use this functionality as the CLI. You can mark some cells with special flags (like `#slow`) to make sure they are only executed when you authorize it. Those flags should be configured in your *settings.ini* (separated by a `|` if you have several of them). You can also apply flags to one entire notebook by using the `all` option, e.g. `#all_slow`, in code cells.\n", 470 | "\n", 471 | "If `tst_flags=slow|fastai` in *settings.ini*, you can:\n", 472 | "\n", 473 | "* mark slow tests with `#slow` flag\n", 474 | "* mark tests that depend on fastai with the `#fastai` flag." 475 | ] 476 | } 477 | ], 478 | "metadata": { 479 | "jekyll": { 480 | "keywords": "fastai", 481 | "toc": "false" 482 | }, 483 | "jupytext": { 484 | "split_at_heading": true 485 | }, 486 | "kernelspec": { 487 | "display_name": "Python 3", 488 | "language": "python", 489 | "name": "python3" 490 | } 491 | }, 492 | "nbformat": 4, 493 | "nbformat_minor": 2 494 | } 495 | -------------------------------------------------------------------------------- /nbs/07_clean.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": null, 6 | "metadata": { 7 | "hide_input": false 8 | }, 9 | "outputs": [], 10 | "source": [ 11 | "#|hide\n", 12 | "#default_exp clean\n", 13 | "from nbdev.showdoc import show_doc" 14 | ] 15 | }, 16 | { 17 | "cell_type": "code", 18 | "execution_count": null, 19 | "metadata": {}, 20 | "outputs": [], 21 | "source": [ 22 | "#|export\n", 23 | "import io,sys,json,glob,re\n", 24 | "from fastcore.script import call_parse,Param,bool_arg\n", 25 | "from fastcore.utils import ifnone\n", 26 | "from nbdev.imports import Config\n", 27 | "from nbdev.export import nbglob\n", 28 | "from pathlib import Path" 29 | ] 30 | }, 31 | { 32 | "cell_type": "code", 33 | "execution_count": null, 34 | "metadata": {}, 35 | "outputs": [], 36 | "source": [ 37 | "#|hide\n", 38 | "#For tests only\n", 39 | "from nbdev.imports import *" 40 | ] 41 | }, 42 | { 43 | "cell_type": "markdown", 44 | "metadata": {}, 45 | "source": [ 46 | "# Clean notebooks\n", 47 | "\n", 48 | "> Strip notebooks from superfluous metadata" 49 | ] 50 | }, 51 | { 52 | "cell_type": "markdown", 53 | "metadata": {}, 54 | "source": [ 55 | "To avoid pointless conflicts while working with jupyter notebooks (with different execution counts or cell metadata), it is recommended to clean the notebooks before committing anything (done automatically if you install the git hooks with `nbdev_install_git_hooks`). The following functions are used to do that." 56 | ] 57 | }, 58 | { 59 | "cell_type": "markdown", 60 | "metadata": {}, 61 | "source": [ 62 | "## Utils" 63 | ] 64 | }, 65 | { 66 | "cell_type": "code", 67 | "execution_count": null, 68 | "metadata": {}, 69 | "outputs": [], 70 | "source": [ 71 | "#|export\n", 72 | "def rm_execution_count(o):\n", 73 | " \"Remove execution count in `o`\"\n", 74 | " if 'execution_count' in o: o['execution_count'] = None" 75 | ] 76 | }, 77 | { 78 | "cell_type": "code", 79 | "execution_count": null, 80 | "metadata": {}, 81 | "outputs": [], 82 | "source": [ 83 | "#|export\n", 84 | "colab_json = \"application/vnd.google.colaboratory.intrinsic+json\"\n", 85 | "def clean_output_data_vnd(o):\n", 86 | " \"Remove `application/vnd.google.colaboratory.intrinsic+json` in data entries\"\n", 87 | " if 'data' in o:\n", 88 | " data = o['data']\n", 89 | " if colab_json in data:\n", 90 | " new_data = {k:v for k,v in data.items() if k != colab_json}\n", 91 | " o['data'] = new_data" 92 | ] 93 | }, 94 | { 95 | "cell_type": "code", 96 | "execution_count": null, 97 | "metadata": {}, 98 | "outputs": [], 99 | "source": [ 100 | "#|export\n", 101 | "def clean_cell_output(cell):\n", 102 | " \"Remove execution count in `cell`\"\n", 103 | " if 'outputs' in cell:\n", 104 | " for o in cell['outputs']:\n", 105 | " rm_execution_count(o)\n", 106 | " clean_output_data_vnd(o)\n", 107 | " o.get('metadata', o).pop('tags', None)" 108 | ] 109 | }, 110 | { 111 | "cell_type": "code", 112 | "execution_count": null, 113 | "metadata": {}, 114 | "outputs": [], 115 | "source": [ 116 | "#|export\n", 117 | "cell_metadata_keep = [\"hide_input\"]\n", 118 | "nb_metadata_keep = [\"kernelspec\", \"jekyll\", \"jupytext\", \"doc\"]" 119 | ] 120 | }, 121 | { 122 | "cell_type": "code", 123 | "execution_count": null, 124 | "metadata": {}, 125 | "outputs": [], 126 | "source": [ 127 | "#|export\n", 128 | "def clean_cell(cell, clear_all=False):\n", 129 | " \"Clean `cell` by removing superfluous metadata or everything except the input if `clear_all`\"\n", 130 | " rm_execution_count(cell)\n", 131 | " if 'outputs' in cell:\n", 132 | " if clear_all: cell['outputs'] = []\n", 133 | " else: clean_cell_output(cell)\n", 134 | " if cell['source'] == ['']: cell['source'] = []\n", 135 | " cell['metadata'] = {} if clear_all else {k:v for k,v in cell['metadata'].items() if k in cell_metadata_keep}" 136 | ] 137 | }, 138 | { 139 | "cell_type": "code", 140 | "execution_count": null, 141 | "metadata": {}, 142 | "outputs": [], 143 | "source": [ 144 | "tst = {'cell_type': 'code',\n", 145 | " 'execution_count': 26,\n", 146 | " 'metadata': {'hide_input': True, 'meta': 23},\n", 147 | " 'outputs': [{'execution_count': 2, \n", 148 | " 'data': {\n", 149 | " 'application/vnd.google.colaboratory.intrinsic+json': {\n", 150 | " 'type': 'string'},\n", 151 | " 'plain/text': ['sample output',]\n", 152 | " },\n", 153 | " 'output': 'super'}],\n", 154 | " \n", 155 | " 'source': 'awesome_code'}\n", 156 | "tst1 = tst.copy()\n", 157 | "\n", 158 | "clean_cell(tst)\n", 159 | "test_eq(tst, {'cell_type': 'code',\n", 160 | " 'execution_count': None,\n", 161 | " 'metadata': {'hide_input': True},\n", 162 | " 'outputs': [{'execution_count': None, \n", 163 | " 'data': {'plain/text': ['sample output',]},\n", 164 | " 'output': 'super'}],\n", 165 | " 'source': 'awesome_code'})\n", 166 | "\n", 167 | "clean_cell(tst1, clear_all=True)\n", 168 | "test_eq(tst1, {'cell_type': 'code',\n", 169 | " 'execution_count': None,\n", 170 | " 'metadata': {},\n", 171 | " 'outputs': [],\n", 172 | " 'source': 'awesome_code'})" 173 | ] 174 | }, 175 | { 176 | "cell_type": "code", 177 | "execution_count": null, 178 | "metadata": {}, 179 | "outputs": [], 180 | "source": [ 181 | "tst2 = {\n", 182 | " 'metadata': {'tags':[]},\n", 183 | " 'outputs': [{\n", 184 | " 'metadata': {\n", 185 | " 'tags':[]\n", 186 | " }}],\n", 187 | " \n", 188 | " \"source\": [\n", 189 | " \"\"\n", 190 | " ]}\n", 191 | "clean_cell(tst2, clear_all=False)\n", 192 | "test_eq(tst2, {\n", 193 | " 'metadata': {},\n", 194 | " 'outputs': [{\n", 195 | " 'metadata':{}}],\n", 196 | " 'source': []})" 197 | ] 198 | }, 199 | { 200 | "cell_type": "code", 201 | "execution_count": null, 202 | "metadata": {}, 203 | "outputs": [], 204 | "source": [ 205 | "#|export\n", 206 | "def clean_nb(nb, clear_all=False):\n", 207 | " \"Clean `nb` from superfluous metadata, passing `clear_all` to `clean_cell`\"\n", 208 | " for c in nb['cells']: clean_cell(c, clear_all=clear_all)\n", 209 | " nb['metadata'] = {k:v for k,v in nb['metadata'].items() if k in nb_metadata_keep }" 210 | ] 211 | }, 212 | { 213 | "cell_type": "code", 214 | "execution_count": null, 215 | "metadata": {}, 216 | "outputs": [], 217 | "source": [ 218 | "tst = {'cell_type': 'code',\n", 219 | " 'execution_count': 26,\n", 220 | " 'metadata': {'hide_input': True, 'meta': 23},\n", 221 | " 'outputs': [{'execution_count': 2,\n", 222 | " 'data': {\n", 223 | " 'application/vnd.google.colaboratory.intrinsic+json': {\n", 224 | " 'type': 'string'},\n", 225 | " 'plain/text': ['sample output',]\n", 226 | " },\n", 227 | " 'output': 'super'}],\n", 228 | " 'source': 'awesome_code'}\n", 229 | "nb = {'metadata': {'kernelspec': 'some_spec', 'jekyll': 'some_meta', 'meta': 37},\n", 230 | " 'cells': [tst]}\n", 231 | "\n", 232 | "clean_nb(nb)\n", 233 | "test_eq(nb['cells'][0], {'cell_type': 'code',\n", 234 | " 'execution_count': None,\n", 235 | " 'metadata': {'hide_input': True},\n", 236 | " 'outputs': [{'execution_count': None, \n", 237 | " 'data': { 'plain/text': ['sample output',]},\n", 238 | " 'output': 'super'}],\n", 239 | " 'source': 'awesome_code'})\n", 240 | "test_eq(nb['metadata'], {'kernelspec': 'some_spec', 'jekyll': 'some_meta'})" 241 | ] 242 | }, 243 | { 244 | "cell_type": "code", 245 | "execution_count": null, 246 | "metadata": {}, 247 | "outputs": [], 248 | "source": [ 249 | "#|export\n", 250 | "def _print_output(nb):\n", 251 | " \"Print `nb` in stdout for git things\"\n", 252 | " _output_stream = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')\n", 253 | " x = json.dumps(nb, sort_keys=True, indent=1, ensure_ascii=False)\n", 254 | " _output_stream.write(x)\n", 255 | " _output_stream.write(\"\\n\")\n", 256 | " _output_stream.flush()" 257 | ] 258 | }, 259 | { 260 | "cell_type": "markdown", 261 | "metadata": {}, 262 | "source": [ 263 | "## Main function" 264 | ] 265 | }, 266 | { 267 | "cell_type": "code", 268 | "execution_count": null, 269 | "metadata": {}, 270 | "outputs": [], 271 | "source": [ 272 | "#|export\n", 273 | "@call_parse\n", 274 | "def nbdev_clean_nbs(\n", 275 | " fname:str=None, # A notebook name or glob to convert\n", 276 | " clear_all:bool_arg=False, # Clean all metadata and outputs\n", 277 | " disp:bool_arg=False, # Print the cleaned outputs\n", 278 | " read_input_stream:bool_arg=False # Read input stram and not nb folder\n", 279 | "):\n", 280 | " \"Clean all notebooks in `fname` to avoid merge conflicts\"\n", 281 | " #Git hooks will pass the notebooks in the stdin\n", 282 | " if read_input_stream and sys.stdin:\n", 283 | " input_stream = io.TextIOWrapper(sys.stdin.buffer, encoding='utf-8')\n", 284 | " nb = json.load(input_stream)\n", 285 | " clean_nb(nb, clear_all=clear_all)\n", 286 | " _print_output(nb)\n", 287 | " return\n", 288 | " path = None\n", 289 | " if fname is None:\n", 290 | " try: path = get_config().path(\"nbs_path\")\n", 291 | " except Exception as e: path = Path.cwd()\n", 292 | "\n", 293 | " files = nbglob(fname=ifnone(fname,path))\n", 294 | " for f in files:\n", 295 | " if not str(f).endswith('.ipynb'): continue\n", 296 | " nb = json.loads(open(f, 'r', encoding='utf-8').read())\n", 297 | " clean_nb(nb, clear_all=clear_all)\n", 298 | " if disp: _print_output(nb)\n", 299 | " else:\n", 300 | " x = json.dumps(nb, sort_keys=True, indent=1, ensure_ascii=False)\n", 301 | " with io.open(f, 'w', encoding='utf-8') as f:\n", 302 | " f.write(x)\n", 303 | " f.write(\"\\n\")" 304 | ] 305 | }, 306 | { 307 | "cell_type": "markdown", 308 | "metadata": {}, 309 | "source": [ 310 | "By default (`fname` left to `None`), the all the notebooks in `lib_folder` 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`. `disp` is only used for internal use with git hooks and will print the clean notebook instead of saving it. Same for `read_input_stream` that will read the notebook from the input stream instead of the file names." 311 | ] 312 | }, 313 | { 314 | "cell_type": "markdown", 315 | "metadata": {}, 316 | "source": [ 317 | "## Export -" 318 | ] 319 | }, 320 | { 321 | "cell_type": "code", 322 | "execution_count": null, 323 | "metadata": {}, 324 | "outputs": [ 325 | { 326 | "name": "stdout", 327 | "output_type": "stream", 328 | "text": [ 329 | "Converted 00_export.ipynb.\n", 330 | "Converted 01_sync.ipynb.\n", 331 | "Converted 02_showdoc.ipynb.\n", 332 | "Converted 03_export2html.ipynb.\n", 333 | "Converted 04_test.ipynb.\n", 334 | "Converted 05_merge.ipynb.\n", 335 | "Converted 06_cli.ipynb.\n", 336 | "Converted 07_clean.ipynb.\n", 337 | "Converted 99_search.ipynb.\n", 338 | "Converted example.ipynb.\n", 339 | "Converted index.ipynb.\n", 340 | "Converted nbdev_comments.ipynb.\n", 341 | "Converted tutorial.ipynb.\n", 342 | "Converted tutorial_colab.ipynb.\n" 343 | ] 344 | } 345 | ], 346 | "source": [ 347 | "#|hide\n", 348 | "from nbdev.export import notebook2script\n", 349 | "notebook2script()" 350 | ] 351 | }, 352 | { 353 | "cell_type": "code", 354 | "execution_count": null, 355 | "metadata": {}, 356 | "outputs": [], 357 | "source": [] 358 | } 359 | ], 360 | "metadata": { 361 | "jupytext": { 362 | "split_at_heading": true 363 | }, 364 | "kernelspec": { 365 | "display_name": "Python 3", 366 | "language": "python", 367 | "name": "python3" 368 | } 369 | }, 370 | "nbformat": 4, 371 | "nbformat_minor": 1 372 | } 373 | -------------------------------------------------------------------------------- /docs/test.html: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | title: Extract tests 4 | 5 | 6 | keywords: fastai 7 | sidebar: home_sidebar 8 | 9 | summary: "The functions that grab the cells containing tests (filtering with potential flags) and execute them" 10 | description: "The functions that grab the cells containing tests (filtering with potential flags) and execute them" 11 | nb_path: "nbs/04_test.ipynb" 12 | --- 13 | 22 | 23 |
24 | 25 | {% raw %} 26 | 27 |
28 | 29 |
30 | {% endraw %} 31 | 32 | {% raw %} 33 | 34 |
35 | 36 |
37 | {% endraw %} 38 | 39 |
40 |
41 |

Everything that is not an exported cell is considered a test, so you should make sure your notebooks can all run smoothly (and fast) if you want to use this functionality as the CLI. You can mark some cells with special flags (like slow) to make sure they are only executed when you authorize it. Those flags should be configured in your settings.ini (separated by a | if you have several of them). You can also apply flags to one entire notebook by using the all option, e.g. #all_slow, in code cells.

42 |

If tst_flags=slow|fastai in settings.ini, you can:

43 |
    44 |
  • mark slow tests with #slow flag
  • 45 |
  • mark tests that depend on fastai with the #fastai flag.
  • 46 |
47 | 48 |
49 |
50 |
51 |
52 |
53 |

Detect flags

54 |
55 |
56 |
57 |
58 |
59 |

The following functions detect the cells that should be excluded from the tests (unless their special flag is passed).

60 | 61 |
62 |
63 |
64 | {% raw %} 65 | 66 |
67 | 68 |
69 | {% endraw %} 70 | 71 | {% raw %} 72 | 73 |
74 | 75 |
76 | {% endraw %} 77 | 78 | {% raw %} 79 | 80 |
81 | 82 |
83 |
84 | 85 |
86 | 87 | 88 |
89 |

get_all_flags[source]

get_all_flags(cells)

90 |
91 |

Check for all test flags in cells

92 | 93 |
94 | 95 |
96 | 97 |
98 |
99 | 100 |
101 | {% endraw %} 102 | 103 | {% raw %} 104 | 105 |
106 | 107 |
108 | {% endraw %} 109 | 110 | {% raw %} 111 | 112 |
113 |
114 | 115 |
116 |
117 |
nb = read_nb("04_test.ipynb")
118 | assert get_all_flags(nb['cells']) == set()
119 | 
120 | 121 |
122 |
123 |
124 | 125 |
126 | {% endraw %} 127 | 128 | {% raw %} 129 | 130 |
131 | 132 |
133 | {% endraw %} 134 | 135 | {% raw %} 136 | 137 |
138 | 139 |
140 |
141 | 142 |
143 | 144 | 145 |
146 |

get_cell_flags[source]

get_cell_flags(cell)

147 |
148 |

Check for any special test flag in cell

149 | 150 |
151 | 152 |
153 | 154 |
155 |
156 | 157 |
158 | {% endraw %} 159 | 160 | {% raw %} 161 | 162 |
163 | 164 |
165 | {% endraw %} 166 | 167 | {% raw %} 168 | 169 |
170 |
171 | 172 |
173 |
174 |
test_eq(get_cell_flags({'cell_type': 'code', 'source': "#hide\n"}), [])
175 | 
176 | 177 |
178 |
179 |
180 | 181 |
182 | {% endraw %} 183 | 184 |
185 |
186 |

Testing a notebook

187 |
188 |
189 |
190 | {% raw %} 191 | 192 |
193 | 194 |
195 |
196 | 197 |
198 | 199 | 200 |
201 |

class NoExportPreprocessor[source]

NoExportPreprocessor(flags, **kwargs) :: ExecutePreprocessor

202 |
203 |

An ExecutePreprocessor that executes cells that don't have a flag in flags

204 | 205 |
206 | 207 |
208 | 209 |
210 |
211 | 212 |
213 | {% endraw %} 214 | 215 | {% raw %} 216 | 217 |
218 | 219 |
220 | {% endraw %} 221 | 222 | {% raw %} 223 | 224 |
225 | 226 |
227 |
228 | 229 |
230 | 231 | 232 |
233 |

test_nb[source]

test_nb(fn, flags=None)

234 |
235 |

Execute tests in notebook in fn with flags

236 | 237 |
238 | 239 |
240 | 241 |
242 |
243 | 244 |
245 | {% endraw %} 246 | 247 | {% raw %} 248 | 249 |
250 | 251 |
252 | {% endraw %} 253 | 254 | {% raw %} 255 | 256 |
257 |
258 | 259 |
260 |
261 |
test_nb('index.ipynb')
262 | 
263 | 264 |
265 |
266 |
267 | 268 |
269 | {% endraw %} 270 | 271 | {% raw %} 272 | 273 |
274 | 275 |
276 | {% endraw %} 277 | 278 | {% raw %} 279 | 280 |
281 | 282 |
283 |
284 | 285 |
286 | 287 | 288 |
289 |

nbdev_test_nbs[source]

nbdev_test_nbs(fname:str=None, flags:str=None, n_workers:int=None, verbose:bool_arg=True, timing:bool=False, pause:float=0.5)

290 |
291 |

Test in parallel the notebooks matching fname, passing along flags

292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 |
TypeDefaultDetails
fnamestrNoneA notebook name or glob to convert
flagsstrNoneSpace separated list of flags
n_workersintNoneNumber of workers to use
verbosebool_argTruePrint errors along the way
timingboolFalseTiming each notebook to see the ones are slow
pausefloat0.5Pause time (in secs) between notebooks to avoid race conditions
339 | 340 |
341 | 342 |
343 | 344 |
345 |
346 | 347 |
348 | {% endraw %} 349 | 350 | {% raw %} 351 | 352 |
353 | 354 |
355 | {% endraw %} 356 | 357 | {% raw %} 358 | 359 |
360 | 361 |
362 |
363 | 364 |
365 | 366 | 367 |
368 |

nbdev_read_nbs[source]

nbdev_read_nbs(fname:str=None)

369 |
370 |

Check all notebooks matching fname can be opened

371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 |
TypeDefaultDetails
fnamestrNoneA notebook name or glob to convert
388 | 389 |
390 | 391 |
392 | 393 |
394 |
395 | 396 |
397 | {% endraw %} 398 | 399 | {% raw %} 400 | 401 |
402 | 403 |
404 | {% endraw %} 405 | 406 |
407 | 408 | 409 | --------------------------------------------------------------------------------