如何为 NumPy 文档贡献力量#

本指南将帮助你决定贡献什么以及如何将其提交到官方 NumPy 文档。

文档团队会议#

NumPy 社区设定了一个明确的目标:改进其文档。我们在 Zoom 上定期举行文档会议(日期会在 numpy-discussion 邮件列表 上公布),欢迎所有人参加。如果你有任何问题或需要有人指导你完成你的第一步,请随时联系我们——我们很乐意提供帮助。会议记录在 hackmd.io 上记录,并存储在 NumPy Archive 仓库 中。

需要什么#

NumPy 文档 已涵盖了详细信息。API 参考文档是直接从代码中的 文档字符串 生成的,方法是在 构建 文档时进行。虽然我们已经为每个向用户公开的函数和类提供了几乎完整的参考文档,但其中一些函数和类的使用示例却不足。

我们缺少的是范围更广的文档——教程、操作指南和解释。报告缺陷是另一种贡献方式。我们讨论两者。

贡献修复#

我们渴望了解并修复文档缺陷。但为了解决最大的问题,我们最终不得不推迟或忽略一些错误报告。以下是最佳的缺陷修复目标。

最优先考虑的是**技术上的不准确性**——文档字符串缺少参数、函数/参数/方法的描述错误等等。其他“结构性”缺陷,例如损坏的链接,也优先考虑。所有这些修复都易于确认和实施。如果你知道如何操作,可以提交一个包含修复的 拉取请求 (PR);否则,请打开一个 issue

**错字和拼写错误**则处于较低的级别;我们欢迎你告知我们,但可能无法立即修复它们。这些也可以作为拉取请求或 issue 来处理。

明显的**措辞**错误(例如遗漏一个“not”)属于错字类别,但其他改写——即使是为了语法——也需要判断,这提高了门槛。请先将修复作为 issue 提出,以试探情况。

一些函数/对象,例如在 C 扩展模块中定义的 numpy.ndarray.transpose、numpy.array 等,其文档字符串在 _add_newdocs.py 中单独定义。

贡献新页面#

你在使用我们的文档时遇到的挫折,是我们改进文档的最佳指南。

如果你编写了一个缺失的文档,你将加入开源的前线,但仅仅让我们知道哪些内容缺失也是一种有意义的贡献。如果你想撰写文档,请在 邮件列表 上与大家讨论,以获得更多想法和反馈。如果你想提醒我们注意某个缺口,请打开一个 issue。查看 此 issue 作为示例。

如果你正在寻找主题,我们正式的文档路线图是一个NumPy 增强提案 (NEP)NEP 44 — 重构 NumPy 文档。它确定了我们的文档需要改进的领域,并列出了我们希望看到的几个新增内容,包括 Jupyter 笔记本

文档框架#

编写有用文档的方法有很多,四个方法几乎涵盖了一切。之所以有四个方法,是因为文档有四类——tutorial(教程)、how-to guide(操作指南)、explanation(解释)和reference(参考)。文档按这种方式划分的见解来自 Daniele Procida 及其 Diátaxis 框架。当你开始编写或提出一个文档时,请记住它属于哪一类型。

NumPy 教程#

除了作为 NumPy 源代码树一部分的文档外,你还可以将 Jupyter Notebook 格式的内容提交到 NumPy 教程 页面。这套教程和教育材料旨在由 NumPy 项目提供高质量的资源,既可用于自学,也可用于教学。这些资源在一个单独的 GitHub 仓库 numpy-tutorials 中开发,你可以在其中查看现有的笔记本,打开 issue 以建议新的主题或提交你自己的教程作为拉取请求。

更多关于贡献的信息#

如果英语不是你的母语,或者你只能写出粗略的草稿,请不要担心。开源是一项社区工作。尽你所能——我们会帮助你解决问题。

图像和现实生活中的数据使文本更具吸引力和说服力,但请确保你使用的内容具有适当的许可证并可用。同样,即使是粗略的艺术品构想也可以由其他人完善。

目前,NumPy 仅接受 pandas、SciPy 或 Matplotlib 等其他 Python 科学库也使用的那些数据格式。我们正在开发一个包以接受更多格式;请联系我们了解更多详情。

NumPy 文档保存在源代码树中。要将你的文档添加到文档库中,必须下载该树,构建它,然后提交拉取请求。如果你不熟悉 GitHub 和拉取请求,请查看我们的 贡献者指南

我们的标记语言是 reStructuredText (rST),它比 Markdown 更复杂。Sphinx 是许多 Python 项目用来构建和链接项目文档的工具,它将 rST 转换为 HTML 和其他格式。有关 rST 的更多信息,请参阅 快速 reStructuredText 指南reStructuredText Primer

间接贡献#

如果你遇到外部资料,这些资料可以作为 NumPy 文档的有益补充,请通过打开一个 issue 让我们知道。

你无需在这里贡献就能为 NumPy 作出贡献。如果你在你的博客上写教程,创建 YouTube 视频,或者在 Stack Overflow 和其他网站上回答问题,你都做出了贡献。

文档风格#

用户文档#

  • 一般来说,我们遵循 Google 开发者文档风格指南 来编写用户指南。

  • 在以下情况下,NumPy 风格适用:

    • Google 没有提供指导,或者

    • 我们更倾向于不使用 Google 风格

    我们目前的规则

    • 我们把 *index* 的复数形式写成 *indices* 而不是 indexes,遵循 numpy.indices 的先例。

    • 为保持一致性,我们也把 *matrix* 的复数形式写成 *matrices*。

  • NumPy 或 Google 规则未能充分解决的语法问题,将根据最新版本的 芝加哥格式手册 中“语法和用法”部分的规定来决定。

  • 我们欢迎你 告知 我们应该添加到 NumPy 风格规则中的案例。

文档字符串#

当结合使用 Sphinx 和 NumPy 约定时,你应该使用 numpydoc 扩展,以便你的文档字符串能够被正确处理。例如,Sphinx 将从你的文档字符串中提取 Parameters 部分并将其转换为字段列表。使用 numpydoc 还可以避免普通 Sphinx 在遇到 NumPy 文档字符串约定(例如 Sphinx 不期望在文档字符串中找到的部分标题(例如 -------------))时产生的 reStructuredText 错误。

可在以下位置获取

请注意,对于 NumPy 内部的文档,无需在示例开头执行import numpy as np

请使用numpydoc 格式标准,如其示例所示。

C/C++ 代码文档化#

NumPy 使用Doxygen 解析特殊格式的 C/C++ 注释块。这将生成 XML 文件,然后由Breathe 转换为 RST,Sphinx 使用 RST。

完成文档化过程需要三个步骤:

1. 编写注释块#

虽然还没有设定要遵循的注释风格,但由于Javadoc与当前存在的未索引注释块比较相似,因此Javadoc更受欢迎。

注意

请参阅“代码文档化”

Javadoc 风格如下所示:

/**
 * This a simple brief.
 *
 * And the details goes here.
 * Multi lines are welcome.
 *
 * @param  num  leave a comment for parameter num.
 * @param  str  leave a comment for the second parameter.
 * @return      leave a comment for the returned value.
 */
int doxy_javadoc_example(int num, const char *str);

以下是其渲染效果:

警告

doxygenfunction: 找不到文件: /home/matti/oss/numpy/doc/build/doxygen/xml/index.xml

对于行注释,可以使用三个正斜杠。例如:

/**
 *  Template to represent limbo numbers.
 *
 *  Specializations for integer types that are part of nowhere.
 *  It doesn't support with any real types.
 *
 *  @param Tp Type of the integer. Required to be an integer type.
 *  @param N  Number of elements.
*/
template<typename Tp, std::size_t N>
class DoxyLimbo {
 public:
    /// Default constructor. Initialize nothing.
    DoxyLimbo();
    /// Set Default behavior for copy the limbo.
    DoxyLimbo(const DoxyLimbo<Tp, N> &l);
    /// Returns the raw data for the limbo.
    const Tp *data();
 protected:
    Tp p_data[N]; ///< Example for inline comment.
};

以下是其渲染效果:

警告

doxygenclass: 找不到文件: /home/matti/oss/numpy/doc/build/doxygen/xml/index.xml

常用的 Doxygen 标记#

注意

更多标记/命令,请查看https://doxygen.cpp.org.cn/manual/commands.html

@brief

开始一个段落,作为简短描述。默认情况下,文档块的第一句会自动作为简短描述处理,因为在 doxygen 配置中启用了选项JAVADOC_AUTOBRIEF

@details

就像@brief 开始简短描述一样,@details 开始详细描述。您也可以另起一段(空行),则不需要@details 命令。

@param

开始函数参数的描述,参数名为 <parameter-name>,后跟参数的描述。系统会检查参数是否存在,如果此参数(或任何其他参数)的文档缺失或未出现在函数声明或定义中,则会发出警告。

@return

开始函数的返回值描述。多个相邻的@return 命令将合并到一个段落中。@return 描述在遇到空行或其他分段命令时结束。

@code/@endcode

开始/结束代码块。代码块与普通文本的处理方式不同。它被解释为源代码。

@rst/@endrst

开始/结束一个 reST 标记块。

示例#

请查看以下示例:

/**
 * A comment block contains reST markup.
 * @rst
 * .. note::
 *
 *   Thanks to Breathe_, we were able to bring it to Doxygen_
 *
 * Some code example::
 *
 *   int example(int x) {
 *       return x * 2;
 *   }
 * @endrst
 */
void doxy_reST_example(void);

以下是其渲染效果:

警告

doxygenfunction: 找不到文件: /home/matti/oss/numpy/doc/build/doxygen/xml/index.xml

2. 为 Doxygen 提供输入#

并非所有头文件都会自动收集。您必须在 Doxygen 的子配置文件中添加所需的 C/C++ 头文件路径。

子配置文件具有唯一名称.doxyfile,通常可以在包含已记录头文件的目录附近找到。如果在您要添加的头文件附近(2 级深度)的路径中没有找到配置文件,则需要创建一个新的配置文件。

子配置文件可以接受任何Doxygen配置选项,但不覆盖或重新初始化任何配置选项,而只使用连接运算符“+=”。例如

# to specify certain headers
INPUT += @CUR_DIR/header1.h \
         @CUR_DIR/header2.h
# to add all headers in certain path
INPUT += @CUR_DIR/to/headers
# to define certain macros
PREDEFINED += C_MACRO(X)=X
# to enable certain branches
PREDEFINED += NPY_HAVE_FEATURE \
              NPY_HAVE_FEATURE2

注意

@CUR_DIR 是一个模板常量,返回子配置文件的当前目录路径。

3. 包含指令#

Breathe 提供了广泛的自定义指令,允许将Doxygen生成的文档转换为 RST 文件。

注意

更多信息,请查看“指令和配置变量

常用的指令#

doxygenfunction

此指令生成单个函数的相应输出。函数名称必须在项目中唯一。

.. doxygenfunction:: <function name>
    :outline:
    :no-link:

查看示例以查看其实际效果。

doxygenclass

此指令生成单个类的相应输出。它采用标准项目、路径、大纲和无链接选项,此外还有成员、受保护成员、私有成员、未记录成员、成员组和仅成员选项。

.. doxygenclass:: <class name>
   :members: [...]
   :protected-members:
   :private-members:
   :undoc-members:
   :membergroups: ...
   :members-only:
   :outline:
   :no-link:

查看doxygenclass 文档以了解更多详情并查看其实际效果。

doxygennamespace

此指令生成命名空间内容的相应输出。它采用标准项目、路径、大纲和无链接选项,此外还有仅内容、成员、受保护成员、私有成员和未记录成员选项。要引用嵌套命名空间,必须提供完整的命名空间路径,例如 foo::bar 用于 foo 命名空间内的 bar 命名空间。

.. doxygennamespace:: <namespace>
   :content-only:
   :outline:
   :members:
   :protected-members:
   :private-members:
   :undoc-members:
   :no-link:

查看doxygennamespace 文档以了解更多详情并查看其实际效果。

doxygengroup

此指令生成 doxygen 组内容的相应输出。doxygen 组可以使用源注释中特定的 doxygen 标记声明,如 doxygen 的分组文档中所述。

它采用标准项目、路径、大纲和无链接选项,此外还有仅内容、成员、受保护成员、私有成员和未记录成员选项。

.. doxygengroup:: <group name>
   :content-only:
   :outline:
   :members:
   :protected-members:
   :private-members:
   :undoc-members:
   :no-link:
   :inner:

查看doxygengroup 文档以了解更多详情并查看其实际效果。

旧版指令#

如果函数、模块或 API 处于*旧版*模式,这意味着出于向后兼容性的原因而保留,但不建议在新代码中使用,则可以使用.. legacy:: 指令。

默认情况下,如果未使用任何参数,则旧版指令将生成以下输出

旧版

此子模块被认为是旧版,将不再接收更新。这也可能意味着它将在未来的 NumPy 版本中被删除。

我们强烈建议您也添加自定义消息,例如替换旧 API 的新 API

.. legacy::

   For more details, see :ref:`distutils-status-migration`.

此消息将附加到默认消息,并将创建以下输出

旧版

此子模块被认为是旧版,将不再接收更新。这也可能意味着它将在未来的 NumPy 版本中被删除。更多详情,请参见numpy.distutils 的状态和迁移建议

最后,如果您想提及函数、方法(或任何自定义对象)而不是*子模块*,可以使用可选参数

.. legacy:: function

这将创建以下输出

旧版

此函数被认为是旧版,将不再接收更新。这也可能意味着它将在未来的 NumPy 版本中被删除。

文档阅读#

  • 领先的技术作家组织Write the Docs 举办会议,提供学习资源,并运营一个 Slack 频道。

  • Google 的技术写作资源集合(包括面向开发人员的免费在线课程,涵盖文档规划和编写)指出:“每个工程师也是一名作家”。

  • Software Carpentry 的使命是向研究人员教授软件。除了托管课程外,该网站还解释了如何有效地呈现想法。