Papyri – 进行中
项目描述
Papyri
Papyri 是一套构建、发布(未来功能 - 待完成)、安装和渲染 IPython 和 Jupyter 中的文档的工具。
信息 | 链接 |
---|---|
项目 | |
CI |
Papyri 允许
- 跨库的双向交叉链接,
- 导航,
- 用户文档字符串文本的正确重新流,
- 内联图像的正确重新流(在渲染为 HTML 时),
- 正确渲染数学(在终端和 HTML 中),
- 等等。
动机
在 这篇博客文章 中查看一些项目背后的原因。
主要动机是构建一套更好的 Python 项目的文档工具。
- 使用有偏见的实现来更好地理解您项目的结构。
- 允许在 Python 包之间的文档中自动进行交叉链接(双向)。
- 使用文档 IR(中间表示)来将构建文档与在许多上下文中渲染文档分开。
这种方法的目的是希望允许类似于 conda-forge 的模型,其中项目将他们的 IR 上传到指定的仓库,一个包含多个项目文档的 单个网站(没有子域名)。然后可以使用更好的项目之间的交叉链接和 高效 的页面重建来构建文档页面。
这也应允许在 非 HTML 后端(例如终端)上显示面向用户的文档,或者在 IDE(Spyder/Jupyterlab)中提供文档,而无需使用 iframe。
概述演示
这是在 2021 年 11 月初的 CZI EOSS4 会议上的一个小型演示。
屏幕截图
终端中的类型推断和键盘导航:指令在终端中正确渲染,示例类型被推断,点击(或按回车)突出显示的标记将打开相应页面(退格键导航回退)。
由于 Jupyter Notebook 和 Lab 页面可以渲染 HTML,因此在使用 Jupyter 内联帮助时应该可以内嵌图表和图像(待实现)。在终端中,我们用按钮/链接替换内嵌图像以在外部查看器(quicklook、evince、paint...)中打开图像。
Papyri 包含有关哪些页面链接到其他页面的完整信息;这使我们能够创建一个本地图,显示哪些页面相互提及,以找到相关主题。
以下是可以看到 numpy.zeros
的本地连接图(d3js,可拖动,可点击)。numpy.zeroes
链接到(或从)图中所有点。绿色显示其他 numpy 函数;蓝色显示 skimage 函数;橙色显示 scipy 函数;红色显示 xarray 函数。点之间的箭头表示相互链接的页面(例如 ndarray 从 xarray.cos
链接),点的大小表示页面的 流行度。
即使在终端中,数学表达式也能正确渲染:这里,polyfit
在启用 Papyri 的 IPython(左侧)和禁用 Papyri(右侧)时显示。
目录
安装(不完全功能)
当从 PyPI 安装时,某些功能尚不可用。目前,您需要通过 开发安装 来访问所有功能。
您需要 Python 3.8 或更高版本,否则 pip 会告诉您找不到任何匹配的分发。
从 PyPI 安装
$ pip install papyri
安装给定包的文档
$ papyri install package_name [package_name [package_name [...]]]
目前只有 numpy 1.20.0、scipy 1.5.0 和 xarray 0.17.0 可安装和发布。对于其他包,您需要本地构建,这是一个更复杂的过程。
以扩展的形式运行带有 Papyri 的 IPython 终端
$ ipython --ext papyri.ipython
这将增强 ?
操作符以显示更好的文档(使用 papyri install ...
安装时)
Papyri 尚未完全构建自己的文档,但您可能可以在 此处 查看其静态渲染。它尚未自动构建,因此可能已过时。
开发安装
根据开发阶段,您可能需要获取 numpydoc 的修改版本。如果您想进行可编辑安装,则需要 pip > 21.3。
# clone this repo
# cd this repo
pip install -e .
某些功能需要 tree_sitter_rst
。要构建 TreeSitter rst 解析器
$ git submodule update --init
$ papyri build-parser
注意,Papyri 仍然使用自定义解析器,将来将移除以主要依赖 TreeSitter。
测试
运行以下命令安装额外的开发依赖项
$ pip install -r requirements-dev.txt
使用以下命令运行测试
$ pytest
用法
Papyri 依赖于三个步骤
- IR 生成(由包维护者执行);
- IR 安装(由最终用户或通过 pip/conda 执行);
- IR 渲染(通常由 IDE、CLI/web 服务器执行)。
IR 生成(papyri gen
)
如果您正在使用 Papyri 为您维护的库构建文档,则希望触发的步骤是此步骤。最有可能的情况是,作为最终用户,您不需要执行此步骤,可以安装预先发布的文档包。此步骤可能只在项目的每个新版本中发生一次。
examples
中的 Toml 文件将为您提供一些现有库的示例配置。
$ ls -1 examples/*.toml
examples/IPython.toml
examples/astropy.toml
examples/dask.toml
examples/matplotlib.toml
examples/numpy.toml
examples/papyri.toml
examples/scipy.toml
examples/skimage.toml
目前这些文件位于 papyri 中,但将来可能位于相关存储库的 docs/papyri.toml
下。
[!注意] 在完整的 numpy/scipy 上 非常慢;使用
--no-infer
(见下文)可以获得较差但较快的体验。
使用 papyri gen <示例文件路径>
例如
$ papyri gen examples/numpy.toml
$ papyri gen examples/scipy.toml
这将在~/.papyri/data/<library name>_<library_version>
中创建中间文档文件。有关详细信息,请参阅生成。
您还可以使用--only
标志为对象子集生成中间文档文件。例如
$ papyri gen examples/numpy.toml --only numpy:einsum
[!IMPORTANT] 为了避免歧义,Papyri使用完全限定名称来引用对象。这意味着您需要使用
numpy:einsum
而不是einsum
或numpy.einsum
来引用numpy
模块中的einsum
函数,例如。
安装/摄取
文档包的安装/摄取是使所有包“相互了解”并允许交叉链接/索引工作的步骤。
我们将保留“安装”和“安装”这两个术语,当您从外部源下载预构建的文档包并只提供包名时——这尚未完全实现。
您可以使用以下命令摄取本地文件夹
$ papyri ingest ~/.papyri/data/<path to folder generated at previous step>
这将将与新创建的文件夹交叉链接到现有文件夹。摄取的数据可以在~/.papyri/ingest/
中找到,但您不应该使用Papyri之外的工具与此文件夹交互。
目前有几个预构建的文档包可以预先安装,但它们可能与Papyri的每个新版本都出现冲突。我们建议您现在使用开发人员安装和摄取程序。
渲染
Papyri流水线的最后一步是渲染文档,或您感兴趣的部分。这很可能是通过您的IDE完成的,很可能是在您探索文档时即时完成。尽管如此,我们已实现了一些外部渲染器,以帮助调试问题。
[!WARNING] 目前许多渲染方法都需要首先构建和摄取Papyri的文档。
$ papyri gen examples/papyri.toml
$ papyri ingest ~/.papyri/data/papyri_0.0.7 # or any current version
或者您可以尝试预先安装旧的Papyri文档包
$ papyri install papyri
独立HTML渲染
要查看之前摄取的所有包的渲染文档,运行
$ papyri serve
这将启动一个实时服务器,它会即时渲染页面。
如果您需要渲染页面的静态版本,请使用以下任一命令
$ papyri render # render all the html pages statically in ~/.papyri/html
$ papyri serve-static # start a http.server with the proper root to serve above files.
丰富的终端渲染
要在终端上渲染单个对象的文档,请使用
$ papyri rich <fully qualified name>
例如
$ papyri rich numpy:einsum # note the colon for the fully qualified name.
要在终端中使用实验性的交互式文本界面,请使用
$ papyri textual <fully qualified name>
IPython扩展
要作为IPython扩展运行papyri
,请运行
$ ipython --ext papyri.ipython
这将启动一个带有增强的?
运算符的IPython会话。
Jupyter扩展
正在进行中。
更多命令
您可以通过不输入命令来运行papyri
,以查看当前所有可用的命令。
Papyri - 名称的含义
参见传说中的纸草别墅,其名称来源于其收集的大量纸草卷轴。
架构
生成(papyri gen
)
将项目的文档收集到DocBundle中——一系列具有定义良好的语义结构和一些元数据的DocBlobs(目前是json文件),并引用该项目文档的版本(以及可能的一些其他blob)。
在生成过程中,可以并应该发生许多规范化和推理步骤。例如
- 使用类型推理将docstrings的
Examples
部分转换为对(标记,参考)对的存储,这样您可以稍后决定在示例中单击np.array
会将您带到numpy数组文档;无论我们是否目前处于numpy文档中; - 将“另请参阅”解析为良好的结构;
- 运行示例为具有图像的文档生成图像(部分实现);
- 解析本地引用。例如,在构建NumPy文档时,
zeroes_like
是明确的,应规范为numpy.zeroes_like
。类似地,~.pyplot.histogram
应规范为matplotlib.pyplot.histogram
作为目标和histogram
作为文本。
生成步骤很可能与项目相关,因为可能存在每个项目定义的导入约定,不需要重复使用(例如:import pandas as pd
)。
生成步骤可能是最耗时的,并且对于每个项目,会产生以下输出:
- 一个
papyri.json
文件,其中包含与已记录对象对应的唯一合格名称和一些元数据; - 一个
toc.json
文件,? - 一个包含生成过程中所有图像的
assets
文件夹; - 一个
docs
文件夹,? - 一个
examples
文件夹,? - 一个包含每个已记录对象的 json 文件的
module
文件夹。
生成步骤之后,应该处理什么?
摄取(papyri ingest
)
摄取步骤将 DocBundle 和/或 DocBlobs 添加到已知项的图中;摄取对于高效构建集合图元数据和了解哪些项目引用哪些项目至关重要。这允许以下操作:
- 更新指向 DocBundle 的反向引用列表;
- 更新前向引用元数据,以了解链接是否有效。
目前,摄取将所有内容加载到内存中并就地更新所有捆绑包,但这样做可能更有效。
在更大规模上可以执行更多操作,例如检测文档在先前版本中是否已更改,以推断哪些库版本的文档是有效的。
可能还需要在该点进行一些整理,因为像 numpy.array
这样的对象具有极其大量的反向引用。
合格名称
为了避免在引用对象时出现歧义,papyri 使用对象的 完全合格名称 进行操作。这意味着我们不是使用点(.
),而是使用冒号(:
)来分隔模块部分和对象的名称及子属性。
为了理解为什么需要这样做,假设以下情况:一个顶级 __init__
从具有相同名称的子模块导入一个函数
# project/__init__.py
from .sub import sub
此子模块定义了一个类(在此示例中我们使用小写字母)
# project/sub.py
class sub:
attribute:str
attribute = 'hello'
并定义了第二个子模块
# project/attribute.py
None
仅使用点(.
)作为合格名称可能导致难以确定我们引用的是哪个对象,或者实现查找对象的逻辑。例如,要获取对象 project.sub.attribute
,人们会做
import project
x = getattr(project, 'sub')
getattr(x, 'attribute')
但在这里,因为使用了 from .sub import sub
,我们最终得到的是类属性而不是模块。使用冒号(:
)可以消除这种歧义,因为我们现在明确知道模块部分,并且 package.sub.attribute
与 package.sub:attribute
是不同的。请注意,package:sub.attribute
也是非歧义的,即使它不是一个对象的正确完全合格名称。
此外,使用冒号(:
)作为分隔符使得实现更加容易,因为在 package.sub:attribute
的情况下,可以直接执行 importlib.import_module('package.sub')
以获取对子模块 sub
的引用,而不需要 try/except 或递归 getattr
检查对象的类型。
树形结构信息
见 https://tree-sitter.github.io/tree-sitter/creating-parsers
当事情不按预期进行时!
SqlOperationalError
:
- 数据库模式可能已更改,尝试:
rm -rf ~/.papyri/ingest/
。
项目详情
下载文件
下载适用于您平台上的文件。如果您不确定选择哪个,请了解有关 安装包 的更多信息。