A notebook processor

Special comments at the start of a cell can be used to provide information to nbdev about how to process a cell, so we need to be able to find the location of these comments.

minimal = read_nb('../tests/minimal.ipynb')


 nb_lang (nb)


 first_code_ln (code_list, re_pattern=None, lang='python')
_tst = """ 
test_eq(first_code_ln(_tst.splitlines(True)), 4)


 extract_directives (cell, remove=True, lang='python')

Take leading comment directives from lines of code in ss, remove #|, and split

Comment directives start with #|, followed by whitespace delimited tokens, which extract_directives extracts from the start of a cell, up until a blank line or a line containing something other than comments. The extracted lines are removed from the source.

exp  = AttrDict(source = """#|export module
#| hide
# | foo bar
# |woo: baz
test_eq(extract_directives(exp), {'export':['module'], 'hide':[], 'eval:': ['false'], 'foo': ['bar'], 'woo:': ['baz']})
test_eq(exp.source, '#|eval: false\n# |woo: baz\n1+2\n#bar')


 opt_set (var, newval)

newval if newval else var


 instantiate (x, **kwargs)

Instantiate x if it’s a type


 NBProcessor (path=None, procs=None, preprocs=None, postprocs=None,
              nb=None, debug=False, rm_directives=True, process=False)

Process cells and nbdev comments in a notebook

Cell processors can be callables (e.g regular functions), in which case they are called for every cell:

everything_fn = '../tests/01_everything.ipynb'

def print_execs(cell):
    if 'exec' in cell.source: print(cell.source)

NBProcessor(everything_fn, print_execs).process()
_all_ = [o_y, 'p_y']

Comment directives are put in a cell attribute directive_ as a dictionary keyed by directive name:

def printme_func(cell):
    if cell.directives_ and 'printme' in cell.directives_: print(cell.directives_['printme'])

NBProcessor(everything_fn, printme_func).process()

However, a more convenient way to handle comment directives is to use a class as a processor, and include a method in your class with the same name as your directive, surrounded by underscores:

class _PrintExample:
    def _printme_(self, nbp, cell, to_print): print(to_print)

NBProcessor(everything_fn, _PrintExample()).process()

In the case that your processor supports just one comment directive, you can just use a regular function, with the same name as your directive, but with an underscore appended – here printme_ is identical to _PrintExample above:

def printme_(nbp, cell, to_print): print(to_print)

NBProcessor(everything_fn, printme_).process()
basic_export_nb2('01_read.ipynb', 'read')
basic_export_nb2('02_maker.ipynb', 'maker')
basic_export_nb2('03_process.ipynb', 'process')

g = exec_new('import nbdev.process')
assert hasattr(g['nbdev'].process, 'NBProcessor')