"Isaac") say_hello(
'Hello Isaac!'
下面的书面教程将向您展示如何使用 nbdev 从零开始创建一个 Python 包。
或者,您可以观看此视频教程,Jeremy Howard 和 Hamel Husain 将逐步指导您完成类似的过程
您需要以下软件来完成本教程,请继续阅读以获取具体的安装说明
如果您之前没有使用过 Python,我们建议您从 Anaconda Individual Edition 入手,并使用 conda 包管理器。
请注意,您只需为每个环境执行安装部分中的步骤一次。如果您创建一个新仓库,则无需重复这些步骤。
启动一个终端并输入以下命令安装 JupyterLab
…或者
…如果您使用的是 pip 包管理器。
您现在可以输入以下命令启动 Jupyter
这应该会在一个新的浏览器标签页中打开 JupyterLab
下一步是安装 nbdev 本身。JupyterLab 自带终端,所以我们将使用它进行后续操作。
在 Launcher 中,向下滚动到“Other”部分,然后点击“Terminal”。如果 Launcher 没有打开,您可以点击“File”→“New Launcher”来打开它。
应该会打开一个带有空白终端的新标签页——它可能看起来不完全一样,具体取决于您的 shell 配置
对于 Mac 和 Linux,输入
…或者对于 Mac、Linux 和 Windows
…如果您使用的是 pip。
nbdev 提供了一个命令来安装最新版本的 Quarto。在终端中,输入
此时可能会要求您输入密码。由于 nbdev 是开源的,您可以阅读此命令的源代码以验证它没有执行任何恶意操作。或者,如果您愿意,也可以选择遵循 Quarto 的官方安装说明。
Quarto 提供了自己的 JupyterLab 扩展,使其能够渲染 Quarto markdown 内容。
例如,这是他们演示其部分功能的 notebook
通过输入以下命令安装该扩展
请注意,jupyterlab-quarto
包目前无法通过 conda 获取。
您已全部设置完毕并准备就绪!安装这些工具可能需要一些时间,但您只需执行一次。接下来,我们将为您的特定项目设置一个 nbdev 仓库。
到本节结束时,您将拥有自己的 nbdev 仓库,包含测试、持续集成、简化的 PyPI 和 conda 打包,以及一个文档网站。
使用方便的链接 github.com/new 创建一个空的 GitHub 仓库。如果您遇到困难,GitHub 的 创建仓库 页面可能会有所帮助。
请记住添加描述,因为 nbdev 稍后会用到它。暂时不要添加 README 文件、.gitignore 或 license。
如果您使用的是网页界面,在您点击“Create Repository”之前,它应该看起来像这样(带有您自己的仓库名称和描述)
然后您应该会被重定向到您的新仓库
GitHub 的网页界面是入门的好方法。随着您经验的增长,您可能想探索 GitHub CLI(命令行界面)。对于我们容易出错的重复性任务,我们通常更喜欢使用命令行工具。将这些任务编写成终端中的小型脚本意味着您可以轻松地重复它们。
现在从您之前启动的 Jupyter 终端中克隆您的仓库(如果需要,请按照那些说明创建一个新的终端)。如果您在这里遇到困难,GitHub 的 克隆仓库 页面可能会有所帮助。
由于我们使用 fastai
用户创建了一个名为 nbev-hello-world
的仓库,我们可以按如下方式克隆它
然后 cd
(改变目录)到我们的仓库
克隆时您可能看到了这条消息
You appear to have cloned an empty repository.
…因为仓库完全是空的。让我们添加一些文件吧!
nbdev 提供了 nbdev_new
命令来初始化一个空的 git 仓库。它将从 git 和 GitHub 推断出有关您项目的信息,并要求您输入剩余的内容。它将在您的仓库中创建文件,这些文件将
通过输入以下命令初始化您的 nbdev 仓库
它可能会要求您输入无法从 git 或 GitHub 推断出的信息。
nbdev_new
假定您的包名称与您的仓库名称相同(将 -
替换为 _
)。如果不是这种情况,请使用 --lib_name
选项。
仔细检查您的 settings.ini
文件,确保所有信息都正确。然后提交并将您的添加推送到 GitHub
nbdev 将您的文档托管在 GitHub Pages 上——一个优秀(且免费!)的网站托管方式。
nbdev 默认使用 GitHub Pages,因为它易于访问。但是,您可以使用任何您喜欢的主机。有关更多信息,请参阅这些文档。
您需要通过点击仓库页面右上角的“Settings”选项卡,然后点击左侧的“Pages”,将“Branch”设置为“gh-pages”,最后点击“Save”来为您的仓库启用 GitHub Pages。
点击“Save”后,它应该看起来与此类似
如果您没有看到“gh-pages”分支,请等待几分钟并重新加载页面。它应该会自动为您设置好。
现在是时候看看 nbdev 为您提供了哪些好东西了!
通过点击仓库页面顶部的“Actions”选项卡打开 GitHub Actions。您应该看到两个工作流运行
如果您在推送首次提交后不久打开此页面,运行可能还没有绿色的勾(✅),因为它们仍在“进行中”或“排队中”。没关系,它们完成所需的时间不应超过一分钟。
如果您看到一个红色的叉(❌),这意味着某个地方失败了。点击叉,然后点击“Details”,您将能够看到失败的原因。如果您无法弄清楚哪里出了问题,请搜索论坛,看看其他人是否解决了相同的问题,否则请创建一个新帖子,尽可能详细地描述您的问题,我们将尽力帮助您。请记住,提供实际仓库和/或 GitHub Action 的链接是帮助我们快速识别问题所在的最佳方式。
这些工作流有什么作用?
我们提供了这些开箱即用的基础工作流,但是您可以根据自己的喜好编辑 .github/workflows/
文件夹中对应的 YAML 文件。
当您启用 GitHub Pages 时,您应该会看到一个新的工作流运行:“pages build and deployment”。顾名思义,此工作流会将您的网站内容部署到 GitHub Pages。
等待工作流运行完成,然后打开您的网站。默认情况下,它应该可以在:https://{user}.github.io/{repo}
访问。例如,您可以查看 fastai
的 nbdev-hello-world
文档,地址是 https://fastai.github.io/nbdev-hello-world。
您现在有了一个基础的 nbdev 仓库,包含持续集成和托管文档!以下是您采取的步骤总结
nbdev_new
初始化了您的仓库在本节中,您将对您在第一步中创建的仓库进行首次编辑。
在新的仓库中使用 Jupyter notebooks 的第一步是安装 nbdev 的 hooks(您可以将“hooks”视为应用程序的插件或扩展)。
通过在终端中输入此命令来安装它们
Clean hook 当前仅支持 Jupyter Notebook 和 JupyterLab。如果您使用的是 VSCode,可以尝试 实验性的 nbdev VSCode 扩展。此外,您可能还想尝试 nbdev 的 pre-commit hooks。
有关 nbdev hooks 工作原理以及如何自定义它们的更多信息,请参阅Git 友好的 Jupyter。以下是一个简短总结
nbdev 的 git hooks 适用于任何 git 仓库,即使它没有使用更广泛的 nbdev 系统。
您现在应该通过运行以下命令从您的 notebook 创建您的包
这将为您的 notebooks 创建 Python 模块。这些模块将构成您的 Python 包的内容。
您可能已经注意到,nbdev_new
在您的仓库中创建了一个 Python 包。在我们的例子中,它通过使用我们的仓库名称 nbdev-hello-world
并将 -
替换为 _
来自动命名为 nbdev_hello_world
,使其成为一个有效的 Python 包。
下一步是将此命令输入您的终端来安装您的包
这是使 Python 包在您当前环境中随处可导入的推荐方式
-e
– “editable” 的缩写,允许您立即使用对您的包所做的更改,而无需重新安装,这对于开发非常方便。.
– 指代当前目录。[dev]
– 包括“development”(开发)依赖:您的 notebooks 仅用于文档或测试的其他包。nbdev 是一个重视快速反馈循环的交互式编程环境。nbdev_preview
命令通过使用 Quarto 在您的计算机上渲染文档并随着您编辑 notebooks 进行更新来帮助实现这一点。
通过在终端中输入此命令来启动预览
它可能在启动时显示几秒钟 Preparing to preview
,并最终显示如下内容
Watching files for changes
Browse at http://localhost:3000/
点击链接在新浏览器标签页中打开预览。它应该看起来与您的在线文档完全一样。
我们经常发现在 Jupyter 中编辑 notebooks 时,在旁边保持一个预览窗口打开非常有用。
现在,在 Jupyter 中打开 nbs/00_core.ipynb
文件(由之前运行 nbdev_new
生成)。您不一定需要用数字开头命名 notebooks,但我们发现这样做有助于展示项目的阅读顺序——即使它们的创建顺序可能不同。
您会看到类似这样的内容
我们来解释一下这些特殊单元格的含义
default_exp
的代码单元格,它决定了此 notebook 将导出到哪个模块(有关更多信息,请参阅指令解释)。目前,它导出到 core
模块。接下来,重命名 notebook,替换标题和描述,并更改您自己项目的默认导出模块。
完成后,保存 notebook。上一节中启动的实时预览应该会随着您的最新更改而更新。
重新运行 notebook 中的所有单元格,以确保它们正常工作,并导出更新后的模块。
我们发现“restart kernel and run all cells”(重新启动内核并运行所有单元格)这个 Jupyter 命令(⏩ 按钮)非常宝贵,以至于我们将其绑定到了键盘快捷键。对 notebooks 的一个常见批评是,乱序执行会导致不可重现的 notebooks。根据我们的经验,养成“重启并重运行”的习惯可以解决这个问题。
运行 notebook 会导出 Python 模块,这是因为最后一个单元格包含了
这是什么意思?
#| hide
是一个指令(类似于 #| default_exp
),它将一个单元格从您导出的模块和文档中排除。nbdev_export
是用于将您的 notebooks 导出为 Python 模块的命令。我们建议在所有您想导出的 notebook 的底部包含这样一个单元格。
请记住删除任何未被 notebook 导出或您的包不需要的未使用模块。如果您更改了 notebook 的默认导出,很可能会发生这种情况——nbdev 不会删除旧模块。这是有意为之的,因为 nbdev 被设计用于处理混合包,这些包既使用 .py 模块(没有对应的 notebook),也使用从 notebooks 导出的模块。
在 #| default_exp
单元格下方添加一个新的代码单元格,其中包含一个函数。例如
请注意,它在顶部包含 #| export
——这是一个指令(类似于 #| default_exp
),告诉 nbdev 将此单元格包含在您导出的模块和文档中。
文档应该看起来像这样
say_hello (to)
向某人打招呼
notebook 驱动开发的一个超能力是,您可以非常轻松地在您的代码下方添加示例、测试和文档。
包含常规代码单元格,它们将(带输出)出现在您的文档中,例如
这也是一个测试!当您运行nbdev_test
时,它将执行此单元格(以及所有其他测试单元格),如果它们引发任何异常则失败。
对于测试,更推荐使用更明确的 assert
…或者来自 fastcore.test
的函数,它们行为类似 assert
,但在值不同时也会显示实际值和期望值
notebook 驱动开发的另一个超能力是,您的示例可以包含图表、图像,甚至 JavaScript widgets。例如,这是一个 SVG 圆
在将更改提交到 GitHub 之前,我们建议在终端中运行 nbdev_prepare
,它打包了以下命令
nbdev_export
: 从 Jupyter notebooks 构建 .py
模块nbdev_test
: 测试您的 notebooksnbdev_clean
: 清理您的 notebooks 以去除冗余输出,方便 git 管理nbdev_readme
: 从您的 index notebook 更新仓库的 README.md
文件。现在您准备好个性化您的文档主页和 README.md
文件了;它们都是从 index.ipynb 自动生成的。打开 Jupyter,然后点击 nbs/index.ipynb
打开它。
我们建议包含更长的描述,说明您的包的功能、安装方法以及使用方法(附带一些导入和使用您的包的示例)。请记住,示例可以是带有实际输出的代码单元格,而不是纯 markdown 文本——它们也可以兼作测试!
您现在可以提交并推送您的更改到 GitHub。如前所述,提交之前请务必运行 nbdev_prepare
,以确保您的模块已导出且测试通过。您可以使用 git status
查看生成或更改了哪些文件。然后
git add .
git commit -m 'Add `say_hello`; update index' # Update this text with your own message
git push
这将触发您的 GitHub Actions。等待一两分钟让它们完成,然后检查您更新后的仓库和文档。
恭喜您,您已经掌握了使用 nbdev 构建出色项目所需的所有基础知识!以下是您采取的步骤总结
nbdev_install_hooks
安装了对 git 友好的 notebooks 的 hookspip install -e '.[dev]'
安装了您的包nbdev_preview
预览了您的文档nbs/00_core.ipynb
添加了您自己的 frontmatter、函数、测试和文档nbdev_prepare
准备了您的更改nbs/index.ipynb
在 00_core.ipynb
中创建一个类,如下所示
#| export
class HelloSayer:
"Say hello to `to` using `say_hello`"
def __init__(self, to): self.to = to
def say(self):
"Do the saying"
return say_hello(self.to)
这将自动在文档中显示如下
HelloSayer (to)
使用 say_hello
向 to
打招呼
然而,方法不会自动生成文档。要添加方法文档,请使用show_doc
HelloSayer.say ()
执行打招呼的操作
并添加一些示例和/或测试
注意上面有一个从我们的新类文档到我们的函数的链接。那是因为我们在 docstring 中使用了反引号
这些在可能的情况下会自动转换为超链接。例如,这里是使用反引号创建的指向 HelloSayer
和 say_hello
的超链接。
由于您经常会在一个 notebook 中更新模块,并在另一个 notebook 中使用它们,如果您的 notebook 在 Python 文件更改后立即自动重新加载新模块,那将非常有帮助。要实现这一点,只需将以下行添加到您的 notebook 顶部
%load_ext autoreload
%autoreload 2
如果您的模块需要其他模块作为依赖项,您可以将这些先决条件添加到您的 settings.ini
文件中的 requirements
部分。依赖项应以空格分隔,并且如果模块需要至少或至多某个特定版本的依赖项,也可以在此处指定。
例如,如果您的模块需要至少版本 1.0.5 的 fastcore
模块,至多版本 0.7 的 torchvision
模块以及任意版本的 matplotlib
,那么先决条件将如下所示
除了 requirements
,您还可以使用其他具有不同范围的关键字指定依赖项。以下是所有可能的依赖项关键字列表
requirements
: 传递给 pip 和 conda 设置pip_requirements
: 仅传递给 pip 设置conda_requirements
: 仅传递给 conda 设置dev_requirements
: 作为开发依赖传递给 pip 设置有关依赖项格式的更多信息,请参阅 pypi 和 conda 关于在 setup.py 和 meta.yaml 中创建规范的文档。
在幕后,nbdev 使用标准的 setuptools
包来处理模块安装。setuptools
的一个非常实用的功能是它可以自动创建跨平台控制台脚本。nbdev 将此功能呈现出来;要使用它,请使用与 setuptools
相同的格式,并在每个脚本定义之间使用空格(如果您有多个脚本定义)。
console_scripts = nbdev_export=nbdev.cli:nbdev_export
如果您希望人们只需输入 pip install your-project
就能安装您的项目,那么您需要将其上传到 pypi。好消息是,我们已经为您的项目创建了一个完全符合 pypi 规范的安装程序!所以您所需要做的就是,如果您之前没有在 pypi 注册过,请先注册(在 pypi 上点击“Register”),生成一个 API token(前往Account settings 并点击“Add API token”),然后创建一个名为 ~/.pypirc
的文件,其中包含您的 token 详细信息。它应该包含以下内容
[pypi]
username = __token__
password = your_pypi_token
您还需要 twine
,所以应该运行一次
pip install twine
要将您的项目上传到 pypi,只需在您的项目根目录中输入 nbdev_pypi
。完成后,将显示您的项目在 pypi 上的链接。
类似于 pip install
支持,我们提供了一个符合 anaconda 规范的安装程序,用于将您的项目上传到 anaconda。上传后,您的包可以通过输入 conda install -c your_anaconda_username your-project
来安装。
您需要在 anaconda 注册(填写表格以 Sign Up
),这将创建一个用户名和密码。然后您需要安装以下包
pip install anaconda-client conda-build conda-verify
在运行 anaconda 上传器之前,您需要使用 CLI 命令登录到 conda(系统将提示您输入用户名和密码)
anaconda login
要上传到 anaconda,只需在您的项目根目录中输入 nbdev_conda
。
在 nbdev 仓库根目录运行命令 nbdev_release_both
将您的项目同时上传到 conda 和 pypi。
在使用此类项目时,我强烈推荐两个 jupyter notebook 扩展。它们是
Navigate
菜单项或它添加的 TOC 侧边栏进行导航。这些可以通过其设置进行修改和/或隐藏。nbdev 支持数学公式(使用 Quarto)。您可以使用以下方法在 notebook 的文档中包含数学公式。
使用 $$
,例如
\sum_{i=1}^{k+1}i
渲染后如下所示
_{i=1}^{k+1}i
使用 $
,例如
This version is displayed inline: \sum_{i=1}^{k+1}i . You can include text before and after.
渲染后如下所示
此版本以内联方式显示: _{i=1}^{k+1}i 。您可以在其前后包含文本。
有关更多信息,请参阅 Quarto 文档
别忘了 nbdev 本身就是用 nbdev 写的!这是一个很好的参考,可以看看 fast.ai 在实践中如何使用它,并获得一些技巧。您可以在 Github 的 nbs 文件夹中找到 nbdev 的 notebooks。
nbdev 支持大多数 Quarto 功能。我们鼓励您阅读 Quarto 文档,以发现所有可用的功能。例如,您可以整合 Graphviz。
值得一看的是关于图表、标注、markdown、小部件、布局、条件内容和quarto 扩展的文档,这些是我们遇到的一些有用的东西。