贡献 Scrapy

重要提示

请务必仔细检查您正在阅读的是本文档的最新版本,地址为 https://docs.scrapy.net.cn/en/master/contributing.html

有许多方式可以为 Scrapy 贡献。以下是一些方式

  • 问题追踪器中报告 bug 和请求功能,请尽量遵循下文报告 Bug中详细介绍的指南。

  • 提交新功能和/或 bug 修复的补丁。请阅读下文编写补丁提交补丁,了解如何编写和提交补丁的详细信息。

  • 写博客介绍 Scrapy。告诉大家你是如何使用 Scrapy 的。这将为新手提供更多示例,并有助于提高 Scrapy 项目的知名度。

  • 加入 Scrapy subreddit 并分享你关于如何改进 Scrapy 的想法。我们始终乐于接受建议。

  • Stack Overflow 回答 Scrapy 相关问题。

报告 Bug

注意

将安全问题报告至 scrapy-security@googlegroups.com。这是一个私有列表,只对信任的 Scrapy 开发者开放,其归档不公开。

撰写良好的 bug 报告非常有帮助,因此在报告新 bug 时请牢记以下指南。

  • 首先查阅常见问题(FAQ),看看你的问题是否在已知问题中得到解答

  • 如果你有关于 Scrapy 使用的一般性问题,请在 Stack Overflow 上提问(使用 “scrapy” 标签)。

  • 查看开放的问题,看看该问题是否已被报告。如果已经报告,不要忽略该报告,而是查看工单历史和评论。如果你有其他有用的信息,请留言,或者考虑发送一个包含修复的 pull request

  • 搜索 scrapy-users 邮件列表和 Scrapy subreddit,看看是否有人在那里讨论过,或者你是否不确定你看到的现象是否是一个 bug。你也可以在 #scrapy IRC 频道提问。

  • 撰写完整、可重现、具体的 bug 报告。测试用例越小越好。记住,其他开发者没有你的项目来重现 bug,所以请包含重现 bug 所需的所有相关文件。例如,请参阅 Stack Overflow 关于创建最小、完整、可验证示例以展示问题的指南。

  • 提供完整可重现示例的最棒方式是发送一个 pull request,将一个失败的测试用例添加到 Scrapy 测试套件中(参见提交补丁)。即使你没有自己修复该问题的打算,这样做也很有帮助。

  • 包括 scrapy version -v 的输出,以便处理你的 bug 的开发者能确切知道它发生在哪个版本和平台,这通常对重现 bug 或判断是否已被修复非常有帮助。

寻找可贡献的工作

如果你决定为 Scrapy 做出贡献,但不知道该贡献什么,有几种方法可以找到待完成的工作

  • 查看 GitHub 贡献页面,其中列出了标记为 good first issue 的开放问题。

    也有标记为 help wanted 的问题,但请注意,有些可能需要熟悉 Scrapy 代码库。你也可以处理任何未标记为 discuss 的其他问题。

  • 如果你喜欢编写文档,也有 文档问题,但请注意,有些可能也需要熟悉 Scrapy 代码库。

  • 如果你喜欢编写自动化测试,你可以致力于提高我们的测试覆盖率

  • 如果你喜欢代码清理,我们欢迎修复我们的静态分析工具检测到的问题。请查看 pyproject.toml 中可能需要处理的已忽略问题。

    请注意,有些问题我们根本不打算解决,通常会在上面附带解释原因的评论;不要与说明问题内容的评论混淆,特别是对于非描述性的问题代码。

如果你发现了一个问题,在提问之前请务必阅读整个问题讨论串。这包括在其他地方提到该问题时,问题讨论串中显示的相关问题和 pull request。

我们不分配问题,你也不需要宣布你即将开始处理某个问题。如果你想处理某个问题,只需直接开始编写补丁即可。

不要仅仅因为某个问题已有开放的 pull request 就放弃它。首先检查开放的 pull request 是否活跃。即使有些是活跃的,如果你认为你可以构建一个更好的实现,请随时创建一个包含你的方法的 pull request。

如果你决定处理一个没有开放问题的工作,请注意

  • 不要为了处理代码覆盖率或代码清理而创建问题,请直接创建 pull request。

  • 不要立即同时创建问题和 pull request。要么先开放一个问题以获取关于该问题是否值得解决的反馈,并在团队反馈积极后才创建 pull request;要么只创建 pull request,如果你认为通过代码进行讨论会更容易。

  • 不要为了添加 docstrings 而添加 docstrings,或者仅仅为了解决被抑制的 Ruff 问题。我们期望 docstrings 只在它们对读者有重要价值时才存在,例如解释一些难以从相应代码中理解的内容,总结冗长、难以阅读的实现,提供关于调用代码的上下文,或者指出被调用代码中故意未捕获的异常。

  • 不要为了仅仅触及某行代码并因此提高行覆盖率而添加尽可能多地使用 mocking 的测试。虽然我们确实旨在最大化测试覆盖率,但测试应该针对实际场景编写,并尽量减少 mocking。我们通常更倾向于端到端测试。

编写补丁

补丁写得越好,被接受的可能性就越高,合并的速度也会越快。

编写良好的补丁应该

  • 包含特定更改所需的最小代码量。小的补丁更容易审查和合并。因此,如果你正在进行多项更改(或 bug 修复),请考虑为每项更改提交一个补丁。不要将多个更改合并到一个补丁中。对于较大的更改,请考虑使用补丁队列。

  • 通过所有单元测试。参见下文的运行测试

  • 包含一个(或多个)测试用例,检查已修复的 bug 或添加的新功能。参见下文的编写测试

  • 如果你正在添加或更改一个公共(有文档)的 API,请在同一个补丁中包含文档更改。参见下文的文档政策

  • 如果你正在添加一个私有 API,请在 docs/conf.py 文件的 coverage_ignore_pyobjects 变量中添加一个正则表达式,以便将新的私有 API 排除在文档覆盖率检查之外。

    要查看你的私有 API 是否被正确跳过,请按如下方式生成文档覆盖率报告

    tox -e docs-coverage
    
  • 如果你正在移除已弃用的代码,请首先确保自引入弃用功能的版本发布以来已至少过去 1 年(12 个月)。参见弃用政策

提交补丁

提交补丁的最佳方式是在 GitHub 上发起一个pull request,也可以选择先创建一个新的 issue。

记住解释修复了什么或新增了什么功能(是什么,为什么需要等等)。包含的信息越多,核心开发者就越容易理解和接受你的补丁。

如果你的 pull request 旨在解决一个开放的问题,请相应地链接它,例如

Resolves #123

你也可以在创建补丁之前讨论新功能(或 bug 修复),但准备好一个补丁来阐明你的论点并表明你已经对该主题进行了一些额外思考总是好的。一个好的起点是在 GitHub 上发送一个 pull request。它可以足够简单地说明你的想法,并在想法被验证并证明有用后,再添加文档/测试。或者,你可以在 Scrapy subreddit 中发起讨论,先讨论你的想法。

有时,对于你想解决的问题,可能存在一个现有但由于某种原因停滞不前的 pull request。通常,这个 pull request 的方向是正确的,但 Scrapy 的维护者要求进行一些更改,而原始的 pull request 作者没有时间处理。在这种情况下,请考虑接手这个 pull request:创建一个新的 pull request,包含原始 pull request 的所有提交,以及为解决提出的问题而进行的额外更改。这样做非常有帮助;只要通过保留原始作者的提交来承认其贡献,这就不被视为无礼。

你可以通过运行 git fetch upstream pull/$PR_NUMBER/head:$BRANCH_NAME_TO_CREATE 将现有 pull request 拉取到本地分支(将 'upstream' 替换为 Scrapy 仓库的远程名称,$PR_NUMBER 替换为 pull request 的 ID,$BRANCH_NAME_TO_CREATE 替换为你想要在本地创建的分支名称)。另请参见:https://githubdocs.cn/en/pull-requests/collaborating-with-pull-requests/reviewing-changes-in-pull-requests/checking-out-pull-requests-locally#modifying-an-inactive-pull-request-locally

在编写 GitHub pull request 时,尽量保持标题简短但具有描述性。例如,对于 bug #411:“Scrapy hangs if an exception raises in start_requests”,最好使用“Fix hanging when exception occurs in start_requests (#411)”,而不是“Fix for #411”。完整的标题使得浏览问题追踪器更容易。

最后,尽量将美观性更改(PEP 8 规范,删除未使用的导入等)与功能性更改分开提交。这将使 pull request 更容易审查,也更有可能被合并。

编码风格

在为 Scrapy 编写代码时,请遵循以下编码约定

Pre-commit

我们使用 pre-commit 在每次提交前自动处理简单的代码问题。

在创建 Scrapy 仓库 fork 的本地克隆后

  1. 安装 pre-commit.

  2. 在你本地克隆的 Scrapy 仓库根目录下,运行以下命令

    pre-commit install
    

现在,pre-commit 将在你每次创建 Git 提交时检查你的更改。发现问题时,pre-commit 会中止你的提交,并自动修复这些问题,或者只报告给你。如果它自动修复了这些问题,再次创建提交应该会成功。否则,你可能需要先手动解决相应的问题。

文档政策

对于 API 成员(类、方法等)的参考文档,使用 docstrings,并确保 Sphinx 文档使用 autodoc 扩展来提取 docstrings。API 参考文档应遵循 docstring 约定(PEP 257),并对 IDE 友好:简短、重点突出,并可以提供简短示例。

其他类型的文档,如教程或主题,应涵盖在 docs/ 目录中的文件中。这包括特定于 API 成员但超出 API 参考文档范围的文档。

无论如何,如果某些内容已在 docstring 中涵盖,请使用 autodoc 扩展将 docstring 提取到文档中,而不是在 docs/ 目录中的文件中重复 docstring。

涵盖新功能或修改功能的文档更新必须使用 Sphinx 的 versionaddedversionchanged 指令。使用 VERSION 作为版本号,我们将在相应版本发布前将其替换为实际版本号。当我们发布 Scrapy 的新主要或次要版本时,如果这些指令已超过 3 年,我们将移除它们。

关于已弃用功能的文档必须随着这些功能的弃用而被移除,以便新读者不会遇到它们。新的弃用和弃用移除记录在版本说明中。

测试

测试是使用 Twisted 单元测试框架实现的。运行测试需要 tox

运行测试

运行所有测试

tox

要运行特定的测试(例如 tests/test_loader.py),请使用

tox -- tests/test_loader.py

要在特定的 tox 环境中运行测试,请使用 -e <name>,其中 tox.ini 中的环境名称。例如,要在 Python 3.10 中运行测试,请使用

tox -e py310

你也可以指定一个逗号分隔的环境列表,并使用 tox 的并行模式在多个环境中并行运行测试

tox -e py39,py310 -p auto

要将命令行选项传递给 pytest,请在调用 tox-- 之后添加它们。使用 -- 会覆盖 tox.ini 中定义的默认位置参数,因此你也必须在 -- 之后包含这些默认位置参数(scrapy tests

tox -- scrapy tests -x  # stop after first failure

你还可以使用 pytest-xdist 插件。例如,要在 Python 3.10 tox 环境中使用所有 CPU 核心运行所有测试

tox -e py310 -- scrapy tests -n auto

要查看覆盖率报告,请安装 coveragepip install coverage)并运行

coverage report

查看 coverage --help 的输出以了解更多选项,例如 html 或 xml 报告。

编写测试

所有功能(包括新功能和 bug 修复)必须包含一个测试用例来检查其是否按预期工作,因此如果你希望你的补丁更快被接受,请为其包含测试。

Scrapy 使用单元测试,位于 tests/ 目录中。它们的模块名通常与其正在测试的模块的完整路径相似。例如,item loaders 的代码在

scrapy.loader

它们的单元测试在

tests/test_loader.py