FunctionNBProcessor

import os import joblib import warnings from execnb.nbio import read_nb, write_nb, new_nb, mk_cell from nbdev.process import NBProcessor, Processor

a = [4, 2, 5]
import pdb
class FunctionNBProcessor(Processor):
    def __init__ (self, cell_processor, debug=False):
        self.cell_processor = cell_processor
        self.function_idx = 0
        self.cell_list = []
        self.function_name_to_list_idx = {}
        self.debug=debug
        #for function in self.cell_processor.cell_nodes:
        #    function.cell_idx = None
    
    def cell(self, cell):
        separator = '\n**********************************************************************\n'
        cell_lines = cell.source.splitlines()
        if len(cell_lines) > 0 and '%%function' in cell_lines[0]:
            if self.debug:
                pdb.set_trace()
            if self.function_idx < len(self.cell_processor.cell_nodes):
                this_function = self.cell_processor.cell_nodes[self.function_idx]
                this_function.cell_idx = cell.idx_
                if this_function.name in self.function_name_to_list_idx:
                    list_idx = self.function_name_to_list_idx[this_function.name]
                    self.cell_list[list_idx] = '#| export\n' + this_function.code
                else:
                    list_idx = len(self.cell_list)-1
                    self.cell_list.append (separator + '#| export\n' + this_function.code)
                    self.function_name_to_list_idx[this_function.name] = list_idx
                self.function_idx += 1
        else:
            self.cell_list.append (cell.source)
    def end(self): 
        for cell in self.cell_list:
            print (cell)

## process_notebook

def process_notebook (cell_processor, debug=False):
    function_processor = FunctionNBProcessor (cell_processor, debug=debug)
    NBProcessor ('./nbdev_sync.ipynb', function_processor).process()

## simple case: each function is written in a single cell

# This is markdown

#%%function first_function
a = 3 
print ('a', a)

# normal code cell
print ('outside', a)

#%%function second_function
b = 4
c = a+b
print (a, b, c)

#cell_processor = %cell_processor

[function['name'] for function in cell_processor.cell_nodes]

print ('last cell:', a, b, c)

process_notebook (cell_processor)

## second case: functions are split into different cells

#%%function myf
print ('hello')
a = 3

#%print myf

myf_info.original_cell

#%%function myf --merge
b = 4

#%print myf

#%%function myf --merge
c = 5
d = a+b+c

#%print myf

myf_info.original_cell

process_notebook (cell_processor)

### (TODO) Use only the last cell associated with this function, e.g., by replacing previous cells.

## third case: have defined functions in cells

x=4

#%%function 
def my_defined_function (x, a=3):
    print (x)
    print (a)

process_notebook (cell_processor, debug=True)

### (TODO) Debug why the code of last function doesn't appear at all

## end
a
[4, 5, 5]
import pdb

class FunctionNBProcessor(Processor):
    def __init__ (
        self, 
        cell_processor, 
        path_to_notebook,
        debug=False
    ):
        self.cell_processor = cell_processor
        self.function_idx = 0
        self.cell_list = []
        self.function_name_to_list_idx = {}
        self.path_to_src_notebook = path_to_notebook
        self.path_to_dst_notebook = path_to_notebook.parent / f'{path_to_notebook.name[:-len(".ipynb")]}_nbdev.ipynb'
        self.debug=debug
    
    def cell(self, cell):
        separator = '\n**********************************************************************\n'
        cell_lines = cell.source.splitlines()
        if len(cell_lines) > 0 and '%%function' in cell_lines[0]:
            if self.debug:
                pdb.set_trace()
            if self.function_idx < len(self.cell_processor.cell_nodes):
                this_function = self.cell_processor.cell_nodes[self.function_idx]
                this_function.cell_idx = cell.idx_
                new_cell = mk_cell ('#| export\n' + this_function.code)
                if this_function.name in self.function_name_to_list_idx:
                    list_idx = self.function_name_to_list_idx[this_function.name]
                    self.cell_list[list_idx] = new_cell
                else:
                    list_idx = len(self.cell_list)
                    self.cell_list.append (new_cell)
                    self.function_name_to_list_idx[this_function.name] = list_idx
                self.function_idx += 1
        else:
            self.cell_list.append (mk_cell(cell.source, cell_type=cell.cell_type))
    def end(self): 
        original_nb = read_nb (self.path_to_src_notebook)
        write_nb (new_nb (self.cell_list, meta=original_nb.metadata), self.path_to_dst_notebook)

process_notebook

def process_notebook (
    cell_processor, 
    path_to_notebook='./nbdev_sync.ipynb', 
    debug=False
):
    path_to_notebook=Path(path_to_notebook)
    function_processor = FunctionNBProcessor (
        cell_processor, 
        path_to_notebook=path_to_notebook,
        debug=debug,
    )
    NBProcessor (path_to_notebook, function_processor).process()

simple case: each function is written in a single cell

This is markdown

a = 3 
print ('a', a)
a 3
Stored the following local variables in the first_function current_values dictionary: ['a']
# normal code cell
print ('outside', a)
outside 3
b = 4
c = a+b
print (a, b, c)
3 4 7
Stored the following local variables in the second_function current_values dictionary: ['b', 'c']
cell_processor = %cell_processor
[function['name'] for function in cell_processor.cell_nodes]
['first_function', 'second_function']
print ('last cell:', a, b, c)
last cell: 3 4 7
process_notebook (cell_processor)

second case: functions are split into different cells

print ('hello')
a = 3
hello
Stored the following local variables in the myf current_values dictionary: ['a']
def myf():
    print ('hello')
    a = 3
    return a
myf_info.original_cell
"print ('hello')\na = 3\n"
b = 4
Stored the following local variables in the myf current_values dictionary: ['b']
hello
Stored the following local variables in the myf current_values dictionary: ['a', 'b']
def myf():
    print ('hello')
    a = 3
    b = 4
    return b,a
c = 5
d = a+b+c
Stored the following local variables in the myf current_values dictionary: ['c', 'd']
hello
Stored the following local variables in the myf current_values dictionary: ['a', 'b', 'c', 'd']
def myf():
    print ('hello')
    a = 3
    b = 4
    c = 5
    d = a+b+c
    return b,d,a,c
myf_info.original_cell
"print ('hello')\na = 3\nb = 4\nc = 5\nd = a+b+c\n"
process_notebook (cell_processor)

(TODO) Use only the last cell associated with this function, e.g., by replacing previous cells.

third case: have defined functions in cells

x=4
def my_defined_function (x, a=3):
    print (x)
    print (a)
4
3
Stored the following local variables in the my_defined_function current_values dictionary: []
process_notebook (cell_processor)

(TODO) Debug why the code of last function doesn’t appear at all

end