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


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.

You can customize nbdev for all your projects by creating a ~/.config/nbdev/config.toml file (or following the XDG specification). For example, you could globally disable nbdev’s Jupyter hooks with jupyter_hooks = false.

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'))

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:int=2, unbump:bool=False
):

Bump semver string v at index part (0=major, 1=minor, 2=patch)


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')

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.

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__