= '''a_=(1,
t 2,
3)
b_=3'''
'a_'), (0,3))
test_eq(find_var(t.splitlines(), 'b_'), (4,5)) test_eq(find_var(t.splitlines(),
maker
辅助函数
变量辅助函数
这些函数允许我们在 Python 模块中查找和修改变量的定义。
find_var
find_var (lines, varname)
在 lines
中查找定义 varname
的行号
read_var
read_var (code, varname)
评估并返回在 code
中定义的 varname
的值
'a_'), (1,2,3))
test_eq(read_var(t, 'b_'), 3) test_eq(read_var(t,
update_var
update_var (varname, func, fn=None, code=None)
通过调用 func
并传入当前定义,更新文件 fn
中 varname
的定义
= exec_new(t)
g 'a_'],g['b_']), ((1,2,3),3))
test_eq((g[= update_var('a_', lambda o:0, code=t)
t2 exec(t2, g)
'a_'],g['b_']), (0,3))
test_eq((g[= update_var('b_', lambda o:0, code=t)
t3 exec(t3, g)
'a_'],g['b_']), ((1,2,3),0)) test_eq((g[
ModuleMaker
ModuleMaker (dest, name, nb_path, is_new=True, parse=True, solo_nb=False)
用于从 notebook 源代码单元格创建导出库的辅助类
为了导出 notebook,我们需要一种创建 Python 文件的方法。 ModuleMaker
承担了这个角色。传入您希望创建模块的目录、模块名称、notebook 源代码路径,如果是正在创建的新文件(而不是添加到现有文件),则将 is_new
设置为 True
。保存的模块的位置将在 fname
中。最后,如果 notebook 中的源代码不应被 Python 解析(例如单元格中的部分类声明),则应将 parse
设置为 False
。
注意:如果这样做,那么
__all__
的生成也将被关闭。
= ModuleMaker(dest='tmp', name='test.testing', nb_path=Path.cwd()/'04_export.ipynb', is_new=True)
mm mm.fname
Path('tmp/test/testing.py')
decor_id
decor_id (d)
装饰器的 id
属性,无论是以函数形式调用还是直接使用
ModuleMaker.make_all
ModuleMaker.make_all (cells)
使用 cells
中的所有导出内容创建 __all__
make_code_cells
make_code_cells (*ss)
我们想在导出的模块顶部添加一个 __all__
。此方法会从 cells
中的所有代码自动生成它。
= make_code_cells("from __future__ import print_function", "def a():...", "def b():...",
nb "c=d=1", "_f=1", "_g=1", "_h=1", "_all_=['_g', _h]", "@patch\ndef h(self:ca):...")
set(mm.make_all(nb)), set(['a','b','c','d', '_g', '_h'])) test_eq(
relative_import
relative_import (name, fname, level=0)
将模块 name
转换为相对于 fname
的名称
'nbdev.core', "xyz"), 'nbdev.core')
test_eq(relative_import('nbdev.core', 'nbdev'), '.core')
test_eq(relative_import(= Path('fastai')
_p 'fastai.core', _p/'vision'), '..core')
test_eq(relative_import('fastai.core', _p/'vision/transform'), '...core')
test_eq(relative_import('fastai.vision.transform', _p/'vision'), '.transform')
test_eq(relative_import('fastai.notebook.core', _p/'data'), '..notebook.core')
test_eq(relative_import('fastai.vision', _p/'vision'), '.')
test_eq(relative_import('fastai', _p), '.')
test_eq(relative_import('fastai', _p/'vision'), '..')
test_eq(relative_import('fastai', _p/'vision/transform'), '...') test_eq(relative_import(
NbCell.import2relative
NbCell.import2relative (cell:execnb.nbio.NbCell, libname)
update_import
update_import (source, tree, libname, f=<function relative_import>)
= "from nbdev.export import *\nfrom nbdev.a.b import *"
ss = make_code_cells([ss])[0]
cell 'nbdev')
cell.import2relative('from .export import *\nfrom .a.b import *')
test_eq(cell.source,
= make_code_cells([ss])[0]
cell 'nbdev/a')
cell.import2relative('from ..export import *\nfrom .b import *') test_eq(cell.source,
ModuleMaker.make
ModuleMaker.make (cells, all_cells=None, lib_path=None)
写入包含 cells
的模块,其中 __all__
由 all_cells
生成
= make_code_cells("from __future__ import print_function",
cells "#|export\ndef a(): ...", "def b(): ...")
2]]))
mm.make(cells, L([cells['tmp/test/testing.py').read_text(encoding='utf-8')) show_src(Path(
# AUTOGENERATED! DO NOT EDIT! File to edit: ../../04_export.ipynb.
# %% ../../04_export.ipynb 0
from __future__ import print_function
# %% auto 0
= ['b']
__all__
# %% ../../04_export.ipynb
#|export
def a(): ...
# %% ../../04_export.ipynb
def b(): ...
如果您不想添加任何 __all__
,请传递 all_cells=[]
或 parse=False
。
传递 parse=False
在编写 ast.parse
可能不喜欢但仍希望导出的分散函数或类时也很方便,例如包含以下内容的单元格:
#|export
class A:
请注意,这样做无法正确生成 __all__
,因此我们假定这是不需要的。
= ModuleMaker(dest='tmp', name='test.testing_noall', nb_path=Path.cwd()/'01_export.ipynb', is_new=True, parse=False)
am am.fname
Path('tmp/test/testing_noall.py')
= make_code_cells("from __future__ import print_function", "#|export\ndef a(): ...", "#|export\nclass A:")
cells
am.make(cells)'tmp/test/testing_noall.py').read_text(encoding='utf-8')) show_src(Path(
# AUTOGENERATED! DO NOT EDIT! File to edit: ../../01_export.ipynb.
# %% ../../01_export.ipynb
from __future__ import print_function
# %% ../../01_export.ipynb
#|export
def a(): ...
# %% ../../01_export.ipynb
#|export
class A:
如果 is_new=False
,则附加定义将添加到底部,并且任何现有的 __all__
将通过新添加的符号进行更新。
= make_code_cells("def c(): ...", "def d(): ...")
c2 = ModuleMaker(dest='tmp', name='test.testing', nb_path=Path.cwd()/'04_export.ipynb', is_new=False)
mm mm.make(c2, c2)
'tmp/test/testing.py').read_text(encoding='utf-8')) show_src(Path(
# AUTOGENERATED! DO NOT EDIT! File to edit: ../../04_export.ipynb.
# %% ../../04_export.ipynb 0
from __future__ import print_function
# %% auto 0
= ['b', 'c', 'd']
__all__
# %% ../../04_export.ipynb
#|export
def a(): ...
# %% ../../04_export.ipynb
def b(): ...
# %% ../../04_export.ipynb 0
def c(): ...
# %% ../../04_export.ipynb 1
def d(): ...
try:
= exec_import('tmp.test.testing', '*')
g for s in "b c d".split(): assert s in g, s
assert 'a' not in g
assert g['b']() is None
finally: shutil.rmtree('tmp')