如何为 NumPy 文档做贡献#

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

文档团队会议#

NumPy 社区已设定了改进文档的坚定目标。我们定期在 Zoom 上举行文档会议(日期将在 numpy-discussion 邮件列表 上公布),欢迎大家参加。如果您有任何疑问或需要有人指导您完成初次步骤,请联系我们——我们很乐意提供帮助。会议纪要记录在 hackmd.io 上,并存储在 NumPy Archive 仓库 中。

需要什么#

NumPy 文档》已涵盖了详细信息。API 参考文档是在文档构建时直接从代码中的 docstrings 生成的。尽管我们几乎为每个暴露给用户的函数和类都提供了完整的参考文档,但其中一些缺乏使用示例。

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

贡献修复#

我们渴望听到并修复文档缺陷。但要解决最严重的问题,我们最终不得不推迟或忽略一些错误报告。以下是最佳的缺陷处理方式。

最高优先级是**技术准确性**——文档字符串缺少参数,函数/参数/方法的描述错误,等等。其他“结构性”缺陷,如链接断开,也获得优先处理。所有这些修复都易于确认和实施。如果您知道如何操作,可以通过包含修复的拉取请求 (PR) 进行提交;否则,请打开一个问题

**拼写和语法错误**的优先级较低;我们欢迎您提出这些问题,但可能无法及时修复。这些也可以通过拉取请求或问题来处理。

明显的**措辞**错误(例如遗漏了“不”)属于拼写错误范畴,但其他措辞修改——即使是语法——也需要权衡,这会提高门槛。首先通过提交问题来试探。

像 numpy.ndarray.transpose、numpy.array 等在 C 扩展模块中定义的函数/对象,它们的文档字符串分别定义在 _add_newdocs.py 中。

贡献新页面#

您在使用我们文档时遇到的挫败感是我们改进文档的最佳指南。

如果您撰写了缺失的文档,您就加入了开源的前线,但仅仅告知我们缺失了什么也是一项有意义的贡献。如果您想撰写文档,请在邮件列表上讨论您的想法,以获得进一步的建议和反馈。如果您想提醒我们存在某个空白,请打开一个问题。请参阅此问题作为示例。

如果您在寻找主题,我们文档的正式路线图是 *NumPy 增强提案 (NEP)*,即 NEP 44 — 重构 NumPy 文档。它指出了我们的文档需要改进的领域,并列出了我们希望看到的几项补充,包括 Jupyter Notebooks

文档框架#

撰写有用文档有其方法论,四种方法几乎涵盖了一切。之所以有四种方法,是因为文档有四个类别——tutorial(教程)、how-to guide(操作指南)、explanation(解释)和reference(参考)。文档分为这几类的洞察来自于 Daniele Procida 及其 Diátaxis 框架。当您开始撰写文档或提出建议时,请考虑它将属于哪种类型。

NumPy 教程#

除了 NumPy 源代码树中的文档外,您还可以将 Jupyter Notebook 格式的内容提交到 NumPy 教程页面。这套教程和教育材料旨在为 NumPy 项目提供高质量资源,供个人学习和用于教学。这些资源是在一个单独的 GitHub 仓库 numpy-tutorials 中开发的,您可以在那里查看现有 Notebook,提出建议新主题的问题,或通过拉取请求提交您自己的教程。

更多关于贡献#

如果英语不是您的母语,或者您只能写出粗略的草稿,请不要担心。开源是一项社区努力。尽力而为——我们会帮助修复问题。

图片和真实数据能使文字更具吸引力和说服力,但请确保您使用的内容拥有适当的许可并可用。同样,即使是艺术方面的粗略想法也可以由他人完善。

目前,NumPy 接受的唯一数据格式是其他 Python 科学库(如 pandas、SciPy 或 Matplotlib)所使用的格式。我们正在开发一个软件包以接受更多格式;请联系我们了解详情。

NumPy 文档保存在源代码树中。要将您的文档纳入文档库,您必须下载源代码树,构建它,然后提交一个拉取请求。如果您对 GitHub 和拉取请求不熟悉,请参阅我们的贡献者指南

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

间接贡献#

如果您遇到外部材料,而这些材料会成为 NumPy 文档的有用补充,请通过打开一个问题来告知我们。

您不必直接为 NumPy 文档做贡献,也可以为 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 使用。

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

1. 编写注释块#

尽管还没有设置要遵循的注释风格,但由于与当前现有的非索引注释块的相似性,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);

渲染效果如下::

int doxy_javadoc_example(int num, const char *str)#

这是一个简单的摘要。

详细信息在此处。欢迎使用多行。

参数:
  • num – 为参数 num 留下注释。

  • str – 为第二个参数留下注释。

返回:

为返回值留下注释。

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

/**
 *  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.
};

渲染效果如下::

template<typename Tp, std::size_t N>
class DoxyLimbo#

用于表示 limbo 数字的模板。

整数类型的特化,这些整数类型不属于任何地方。它不支持任何实际类型。

Param Tp:

整数的类型。要求为整数类型。

Param N:

元素的数量。

公有函数

DoxyLimbo()#

默认构造函数。不初始化任何内容。

DoxyLimbo(const DoxyLimbo<Tp, N> &l)#

设置复制 limbo 的默认行为。

const Tp *data()#

返回 limbo 的原始数据。

保护属性

Tp p_data[N]#

行内注释示例。

通用 Doxygen 标签:#

注意

有关更多标签/命令,请参阅 https://doxygen.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);

渲染效果如下::

void doxy_reST_example(void)#

注释块包含 reST 标记。

一些代码示例:

int example(int x) {
    return x * 2;
}

注意

感谢 Breathe,我们能够将其引入 Doxygen

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. Inclusion directives#

Breathe 提供了一系列自定义指令,允许将 Doxygen 生成的文档转换为 reST 文件。

注意

有关更多信息,请参阅“指令和配置变量”。

通用指令:#

doxygenfunction

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

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

查看示例以了解其工作原理。

doxygenclass

此指令为单个类生成相应的输出。它接受标准的 project、path、outline 和 no-link 选项,以及 members、protected-members、private-members、undoc-members、membergroups 和 members-only 选项。

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

查看doxygenclass 文档以获取更多详细信息并了解其工作原理。

doxygennamespace

此指令为命名空间的内容生成相应的输出。它接受标准的 project、path、outline 和 no-link 选项,以及 content-only、members、protected-members、private-members 和 undoc-members 选项。要引用嵌套命名空间,必须提供完整的命名空间路径,例如 foo::bar 表示 foo 命名空间内的 bar 命名空间。

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

查看doxygennamespace 文档以获取更多详细信息并了解其工作原理。

doxygengroup

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

它接受标准的 project、path、outline 和 no-link 选项,以及 content-only、members、protected-members、private-members 和 undoc-members 选项。

.. 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 的使命是教授研究人员软件。除了托管课程外,该网站还解释了如何有效地呈现想法。