config

Configuring nbdev and bootstrapping notebook export

Configuring nbdev

nbdev is heavily customizeable, thanks to the configuration system defined in this module. There are 2 ways to interact with nbdev’s config:

  • In the terminal: nbdev-create-config creates a pyproject.toml (if you’re starting a new project use nbdev-new instead)
  • In your library: get_config returns a ConfigToml object.

Read on for more about how these work.


source

nbdev_create_config

def nbdev_create_config(
    repo:str=None, # Repo name
    branch:str='main', # Repo default branch
    user:str=None, # Repo username
    author:str=None, # Package author's name
    author_email:str=None, # Package author's email address
    description:str='', # Short summary of the package
    path:str='.', # Path to create config file
    min_python:str='3.10', # Minimum Python version
    license:str='Apache-2.0', # License (SPDX identifier)
):

Create a pyproject.toml config file.

You can create a pyproject.toml by passing settings via the command line:

nbdev-create-config --repo nbdev --user fastai --author fastai \
                    --author-email [email protected] --description 'A test project'

If you don’t provide settings, we’ll try to infer them from git and GitHub.


source

ConfigToml

def ConfigToml(
    d, proj, cfg_file
):

dict subclass that also provides access to keys as attrs, and has a pretty markdown repr


source

get_config

def get_config(
    path:NoneType=None, also_settings:bool=False
):

Return nbdev config.

Searches up from path until a pyproject.toml with [tool.nbdev] is found. Unspecified optional settings return defaults.

See nbdev-create-config for creating a new config.

cfg = get_config()

cfg is a ConfigToml object (inherits from AttrDict), so you can access keys as attributes:

p = Path.cwd().parent.parent
test_eq(cfg.lib_name, 'nbdev')
test_eq(cfg.git_url, 'https://github.com/AnswerDotAI/nbdev')

Its own path and parent are attributes too:

test_eq(cfg.config_path, p)
test_eq(cfg.config_file, p/'pyproject.toml')

Paths are relative to the project:

test_eq(cfg.doc_path, p/'_docs')
test_eq(cfg.lib_path, p/'nbdev')
test_eq(cfg.nbs_path, p/'nbs')

Note: If no pyproject.toml with [tool.nbdev] is found, get_config() returns a minimal config with defaults based on the current directory. Use is_nbdev() to check if you’re in an nbdev project.

Set defaults for all projects in ~/.config/nbdev/config.toml, or its XDG location. It accepts any [tool.nbdev] key. Project settings override these defaults.

For example, jupyter_hooks = false disables the Jupyter hooks by default. cell_timeout = 60 sets a 60-second default for nbdev-test.

nbdev-create-config also reads user, author and author_email from this file when arguments and Git don’t supply them.

Helpers


source

is_nbdev

def is_nbdev(
    path:NoneType=None
):

source

create_output

def create_output(
    txt, mime
):

Add a cell output containing txt of the mime text MIME sub-type


source

show_src

def show_src(
    src, lang:str='python'
):
show_src("print(create_output('text', 'text/plain'))")
print(create_output('text', 'text/plain'))

source

nbpath2html

def nbpath2html(
    p
):

Convert notebook path p to its html doc path (strips numeric prefix)


source

nbpath2docurl

def nbpath2docurl(
    nb_path
):

Hosted docs URL (with .md suffix) for notebook nb_path, or ’’ if no doc_host

Exporting a basic module


source

read_version

def read_version(
    path
):

Read version from path/__init__.py, or None if not found


source

set_version

def set_version(
    path, version
):

Set version in path/__init__.py

with tempfile.TemporaryDirectory() as d:
    test_is(read_version(d), None)  # No file yet
    set_version(d, '1.0.0')
    test_eq(read_version(d), '1.0.0')
    set_version(d, '1.0.1')
    test_eq(read_version(d), '1.0.1')

source

bump_version

def bump_version(
    v, part:NoneType=None, unbump:bool=False
):

Bump .postN by default when present, otherwise a semver part counted from the right


source

update_version

def update_version(
    path:NoneType=None
):

Add version to path/__init__.py if it doesn’t exist

test_eq(bump_version('1.2.3'), '1.2.4')
test_eq(bump_version('1.2.3', part=1), '1.3.0')
test_eq(bump_version('1.2.3', part=0), '2.0.0')
test_eq(bump_version('1.2.3', part=2, unbump=True), '1.2.2')
test_eq(bump_version('2026.05.27.2'), '2026.05.27.3')
test_eq(bump_version('2026.05.27.2', part=1), '2026.05.28.0')
test_eq(bump_version('2026.05.27.2', part=0), '2026.6.0.0')
test_eq(bump_version('0.0.2026082005.post1'), '0.0.2026082005.post2')
test_eq(bump_version('0.0.2026082005.post2', unbump=True), '0.0.2026082005.post1')
test_eq(bump_version('0.0.2026082005.post1', part=2), '0.0.2026082006')

source

update_proj

def update_proj(
    path
):

Create or update pyproject.toml in the project root.


source

add_init

def add_init(
    path:NoneType=None
):

Add __init__.py in all subdirs of path containing python files if it’s not there already.

The package docstring helps readers of doc(pkg) choose which modules to read next. pkg_mdoc lists modules whose docstrings extend beyond the default summary and Docs: link. Each entry uses the module docstring’s first paragraph.

update_init_mdoc writes this documentation into __init__.py without changing its code. nbdev-export runs it through add_init.

pyskills’ doc() uses this package documentation instead of adding its usual submodule listing. For example, see doc('pyskills').


source

pkg_mdoc

def pkg_mdoc(
    path:NoneType=None, desc:NoneType=None, index_nb:NoneType=None
):

Package docstring for path: desc, intro from index_nb, and a line per module with a substantive docstring


source

update_init_mdoc

def update_init_mdoc(
    path:NoneType=None, desc:NoneType=None
):

Write pkg_mdoc as the docstring of path/__init__.py, replacing any existing docstring

pkg_llms builds an llms.txt from the same documentation. It includes the title, summary, index-notebook introduction and module list. Module links use the .html.md URLs from their docstrings’ Docs: lines.

update_llms_txt writes the file to the notebooks folder for Quarto to copy to the site root. It marks generated files with an HTML comment. It never overwrites an existing file without that marker.


source

update_llms_txt

def update_llms_txt(
    path:NoneType=None, fn:NoneType=None, desc:NoneType=None, index_nb:NoneType=None
):

Write pkg_llms to fn when it’s absent or generated (has the nbdev marker)


source

pkg_llms

def pkg_llms(
    path:NoneType=None, desc:NoneType=None, index_nb:NoneType=None
):

llms.txt for the package at path, from the same sources as pkg_mdoc (’’ if no intro or modules)

with tempfile.TemporaryDirectory() as d:
    d = Path(d)
    cfg_text = (pyproj_tmpl.replace('name = "FILL_IN"', 'name = "testpkg"').replace('requires-python="FILL_IN"', 'requires-python=">=3.10"'))
    cfg_text += '\n[tool.nbdev]\n'
    (d/_pyproj).write_text(cfg_text)
    (d/'testpkg').mkdir()

    with working_directory(d): update_proj(d)

    result = (d/_pyproj).read_text()
    assert 'name = "testpkg"' in result

Python modules require a __init.py__ file in all directories that are modules. We assume that all directories containing a python file (including in subdirectories of any depth) is a module, and therefore add a __init__.py to each.

with tempfile.TemporaryDirectory() as d:
    d = Path(d)
    (d/'a/b').mkdir(parents=True)
    (d/'a/b/f.py').touch()
    (d/'a/c').mkdir()
    add_init(d)
    assert not (d/'a/c'/_init).exists(), "Should not add init to dir without py file"
    for e in [d, d/'a', d/'a/b']: assert (e/_init).exists(),f"Missing init in {e}"

source

import_obj

def import_obj(
    s
):

Import and return module:obj string


source

write_cells

def write_cells(
    cells, hdr, file, solo_nb:bool=False
):

Write cells to file along with header hdr (mainly for nbdev internal use).

This is a simple exporter with just enough functionality to correctly export this notebook, in order to bootstrap the creation of nbdev itself.

# #| hide
# #| eval: false
# path = Path('../nbdev')
# (path/'config.py').unlink(missing_ok=True)
# 
# _basic_export_nb("01_config.ipynb", 'config.py')
# 
# g = exec_new('from nbdev import config')
# assert g['config'].add_init
# assert 'add_init' in g['config'].__all__