= read_nb('../../tests/minimal.ipynb') minimal
处理
一个 Notebook 处理器
Notebook 单元格开头的特殊注释可以用于向 nbdev
提供有关如何处理单元格的信息,因此我们需要能够找到这些注释的位置。
nb_lang
nb_lang (nb)
first_code_ln
first_code_ln (code_list, re_pattern=None, lang='python')
获取代码出现的第一行行号,其中 code_list
是代码列表
= """
_tst #|default_exp
#|export
#|hide_input
foo
"""
True)), 4) test_eq(first_code_ln(_tst.splitlines(
extract_directives
extract_directives (cell, remove=True, lang='python')
从 ss
中的代码行提取开头的注释指令,移除 #|
,并进行分割
注释指令以 #|
开头,后跟空格分隔的 token。 extract_directives
会从单元格开头提取这些指令,直到遇到空行或包含非注释内容的行。提取的行会从源代码中移除。
= AttrDict(source = """#|export module
exp #|eval:false
#| hide
# | foo bar
# |woo: baz
1+2
#bar""")
# this one has #|hide: with a colon at the end, wich is quarto compliant
= AttrDict(source = """#|export module
exp2 #|eval:false
#| hide:
# | foo bar
# |woo: baz
1+2
#bar""")
= {'export':['module'], 'hide':[], 'eval:': ['false'], 'foo': ['bar'], 'woo:': ['baz']}
_answer
test_eq(extract_directives(exp), _answer)
test_eq(extract_directives(exp2), _answer)'#|eval: false\n# |woo: baz\n1+2\n#bar') test_eq(exp.source,
opt_set
opt_set (var, newval)
如果 newval 存在则使用 newval,否则使用 var
实例化
instantiate (x, **kwargs)
如果 x
是一个类型,则将其实例化
NBProcessor
NBProcessor (path=None, procs=None, nb=None, debug=False, rm_directives=True, process=False)
处理 Notebook 中的单元格和 nbdev 注释
单元格处理器可以是可调用对象(例如普通函数),在这种情况下,它们会对每个单元格进行调用(将单元格的 source 设置为 None
以移除该单元格)
= '../../tests/01_everything.ipynb'
everything_fn
def print_execs(cell):
if 'exec' in cell.source: print(cell.source)
NBProcessor(everything_fn, print_execs).process()
---
title: Foo
execute:
echo: false
---
exec("o_y=1")
exec("p_y=1")
_all_ = [o_y, 'p_y']
注释指令会作为字典存储在单元格属性 directive_
中,字典的键是指令名称
def printme_func(cell):
if cell.directives_ and 'printme' in cell.directives_: print(cell.directives_['printme'])
NBProcessor(everything_fn, printme_func).process()
['testing']
然而,一种更方便处理注释指令的方法是使用一个 类 作为处理器,并在你的类中包含一个与你的指令同名(前后加下划线)的方法
class _PrintExample:
def _printme_(self, cell, to_print): print(to_print)
NBProcessor(everything_fn, _PrintExample()).process()
testing
如果你的处理器只支持一个注释指令,你可以只使用一个普通函数,函数名与你的指令同名,但末尾附加一个下划线 – 例如这里的 printme_
与上面的 _PrintExample
相同
def printme_(cell, to_print): print(to_print)
NBProcessor(everything_fn, printme_).process()
testing
NBProcessor(everything_fn, _PrintExample()).process()
testing
Processor
Processor (nb)
处理器的基类
对于更复杂的行为,可以继承 Processor
,并重写 begin()
(在处理任何单元格之前调用)、cell()
(为每个单元格调用)和 end()
(在处理完所有单元格之后调用)中的一个或多个方法。你还可以在这些子类中包含注释指令(例如上面的 _printme
示例)。子类会自动访问包含已处理 Notebook 的 self.nb
.
class CountCellProcessor(Processor):
def begin(self):
print(f"First cell:\n{self.nb.cells[0].source}")
self.count=0
def cell(self, cell):
if cell.cell_type=='code': self.count += 1
def end(self): print(f"* There were {self.count} code cells")
NBProcessor(everything_fn, CountCellProcessor).process()
First cell:
---
title: Foo
execute:
echo: false
---
* There were 26 code cells