目录

样式和静态检查

Pre-commit

PY006 科学 Python 项目通常使用 pre-commit 来检查代码风格。它可以通过 brew(macOS)或 pip(任何地方)安装。有两种模式可以在本地使用它;您可以使用 pre-commit run(仅更改)或 pre-commit run --all-files(全部)手动检查。您还可以运行 pre-commit install 将检查添加为 git pre-commit 钩子(这就是它名称的由来)。即使您之前尝试过设置自定义 pre-commit 钩子但失败了,也值得一试;它非常优雅,不会添加或提交更改,它只是进行更改并允许您检查和添加它们。您可以始终使用 -n 覆盖钩子。

PC100 这是一个带有某些有用选项的最小 .pre-commit-config.yaml 文件

repos:
  - repo: https://github.com/pre-commit/pre-commit-hooks
    rev: "v5.0.0"
    hooks:
      - id: check-added-large-files
      - id: check-case-conflict
      - id: check-merge-conflict
      - id: check-symlinks
      - id: check-yaml
      - id: debug-statements
      - id: end-of-file-fixer
      - id: mixed-line-ending
      - id: name-tests-test
        args: ["--pytest-test-first"]
      - id: requirements-txt-fixer
      - id: trailing-whitespace

有用提示:Pre-commit 从上到下运行,因此将修改内容的检查(如上面的一些 pre-commit-hooks 或 Black)放在可能更有可能在修改后通过的检查(如 flake8)之上。

保持固定版本最新:您可以使用 pre-commit autoupdate 将您的标记版本向前移动到最新的标记!由于 pre-commit 的缓存系统的设计,这些必须指向固定的标记,永远不要在此处放置分支。

在 CI 中检查:您可以使用 pre-commit.ci 检查并经常自动为您更正。如果您的检查更新,它甚至会每隔一周左右更新您的 rev: 版本!

要使用,只需访问 pre-commit.ci,点击“使用 GitHub 登录”,如果首次为组织或用户添加,则点击“添加安装”,或者如果已存在安装,则点击“管理 GitHub 上的仓库”,然后从 GitHub 界面中的列表中添加您的仓库。

现在将会有一个新的检查,如果 pre-commit 检查进行了任何更改,pre-commit.ci 将提交更改。请注意,有一些功能缺失:基于 Docker 的检查将不起作用(pre-commit.ci 已经在 docker 中运行),您无法启用 --manual 标志,因此额外的检查将不会运行,并且作业不应下载包(使用 additional-dependencies: 添加您需要的包)。

PC901 您可以使用以下方法自定义 pre-commit 消息

ci:
  autoupdate_commit_msg: "chore: update pre-commit hooks"

格式化

PC110 Black 是 Python 软件基金会的一个流行的自动格式化工具。Black 的主要特点之一是它“固执己见”;也就是说,它几乎完全不可配置。它不会允许您提出自己的格式,而是强制您使用一种格式。虽然我非常确定您可以想出更好的格式,但拥有一个单一的标准可以让您非常快地学会阅读代码——您可以立即看到嵌套列表、匹配括号等。也有一部分开发人员不喜欢所有自动格式化工具,但在像 pre-commit 这样的系统中,自动格式化工具是理想的。它们还可以加快代码编写速度,因为您在编写代码时可以忽略代码格式。通过强加标准,所有科学 Python 开发人员都可以快速阅读任何包的代码。

此外,正确格式化的代码还有其他好处,例如,如果两个开发人员进行相同的更改,他们会获得相同的格式,并且合并请求更容易。Black 中的样式选择明确是为了优化 git diff!

有一些少量选项,主要用于启用/禁用某些文件、删除字符串规范化以及更改行长度,这些选项位于您的 pyproject.toml 文件中。

Ruff,这个强大的基于 Rust 的 linter,有一个格式化程序,它是在一些 Black 作者的帮助下设计的,看起来与 Black 99.9% 相同,但运行速度快 30 倍。以下是将格式化程序添加到您的 .pre-commit-config.yml 的代码片段(与下面的 Ruff linter 结合使用)

- repo: https://github.com/astral-sh/ruff-pre-commit
  rev: "v0.7.1"
  hooks:
    #  id: ruff would go here if using both
    - id: ruff-format

由于您在遵循本指南时可能会使用 Ruff,因此也建议使用格式化程序。

您还可以将 Ruff 徽章添加到您的仓库中

Code style: Ruff

[![Code style: Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/format.json)](https://github.com/astral-sh/ruff)
.. image:: https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/format.json
    :target: https://github.com/astral-sh/ruff

非常特殊的情况下,例如在创建二维数组时,您可能希望保留特殊格式。在仔细确定这是一个特殊用例后,您可以在代码块周围使用 # fmt: on# fmt: off 来使其保留自定义格式。始终在尝试此选项之前考虑重构!大多数情况下,您可以通过重写代码找到一种方法使 Blacked 代码看起来更好;将难以阅读的长部分分解成变量,避免将矩阵写成一维列表等。

文档/自述文件片段支持

PC111 如果您希望在文档中使用 Black,您可以使用 blacken-docs。这甚至可以捕获代码片段中的语法错误!它支持 markdown 和重组文本。请注意,因为 black 位于 additional_dependencies 中,您必须手动将其更新。

- repo: https://github.com/adamchainz/blacken-docs
  rev: "1.19.1"
  hooks:
    - id: blacken-docs
      additional_dependencies: [black==24.*]

Ruff

PC190 Ruff (文档) 是一个 Python 代码 linter 和自动修复工具,它用一个超快的(用 Rust 编写的)、单个零依赖项的包替换了生态系统中的许多其他工具。所有插件都已编译,因此您无法在不更新 pre-commit 钩子的情况下从插件更新中获得新的错误。

- repo: https://github.com/astral-sh/ruff-pre-commit
  rev: "v0.7.1"
  hooks:
    - id: ruff
      args: ["--fix", "--show-fixes"]

PC191 --fix 参数是可选的,但建议使用,因为您可以在 git 中检查和撤消更改。

RF001 Ruff 在您的 pyproject.toml 中配置。以下是一个示例

[tool.ruff.lint]
extend-select = [
  "ARG",      # flake8-unused-arguments
  "B",        # flake8-bugbear
  "C4",       # flake8-comprehensions
  "EM",       # flake8-errmsg
  "EXE",      # flake8-executable
  "FURB",     # refurb
  "G",        # flake8-logging-format
  "I",        # isort
  "ICN",      # flake8-import-conventions
  "NPY",      # NumPy specific rules
  "PD",       # pandas-vet
  "PGH",      # pygrep-hooks
  "PIE",      # flake8-pie
  "PL",       # pylint
  "PT",       # flake8-pytest-style
  "PTH",      # flake8-use-pathlib
  "PYI",      # flake8-pyi
  "RET",      # flake8-return
  "RUF",      # Ruff-specific
  "SIM",      # flake8-simplify
  "T20",      # flake8-print
  "UP",       # pyupgrade
  "YTT",      # flake8-2020
]
ignore = [
  "ISC001",   # Conflicts with formatter
  "PLR09",    # Too many <...>
  "PLR2004",  # Magic value used in comparison
]
typing-modules = ["mypackage._compat.typing"]
isort.required-imports = ["from __future__ import annotations"]

[tool.ruff.lint.per-file-ignores]
"tests/**" = ["T20"]

Ruff 提供了数十种规则集;您可以从中选择您想要的。与 Flake8 一样,插件按整个字母序列匹配(除了 pylint 的“PL”快捷方式),然后您还可以包含前导或整个错误代码。以 9 开头的代码必须显式选择,至少包含字母后跟 9。您还可以通过 ignore 忽略某些错误代码。您还可以为要忽略的路径设置代码,方法是在 per-file-ignores 中设置。如果您不喜欢某些自动修复,您可以通过 unfixable 为特定错误代码禁用自动修复。

还有其他配置选项,例如 typing-modules,它有助于将特定于类型的规则应用于重新导出的类型模块(这是一种基于 Python 版本统一类型和 typing_extensions 的常见做法)。还有一个文件 exclude 集,如果您完全从 pre-commit 运行它,则可以覆盖它(默认排除包括“build”,因此如果您有一个名为 build 的模块或名为 build.py 的文件,它将默认跳过,如果没有此设置)。

如果仅在 Ruff 0.6+ 中设置为 ["src"],则不再需要告诉它在哪里查找顶级包的 src 列表。 RF003

如果您不使用 [project] 表(旧版 setuptools 或 Poetry),那么您还应该设置

target-version = "py39"

这将选择您要定位的最低版本(主要用于 "UP""I"RF002

以下是一些在大多数(但不是全部!)项目中启用的良好错误代码

  • EFW:这些是标准的 flake8 检查,经受时间考验的经典检查。如果您使用 extend-select 则不需要(如果您使用格式化程序,则不需要 W)。
  • B:它查找非常容易出错的模式。 RF101
  • I:它对您的导入进行排序。这样做有很多好处,例如更小的差异、更少的冲突、一种自动注入 __future__ 导入的方法,以及让读者更容易分辨哪些是内置的、第三方和本地的。它有很多配置选项,但默认使用与 Black 兼容的样式。 RF102
  • ARG:它查找未使用的参数。您可能需要偶尔使用 # noqa: ARG001,但总的来说它非常有用。
  • C4:它查找可以使用列表推导式的地方,并且可以自动修复它们。
  • EM:错误消息方面非常有主见的技巧:它阻止您将错误字符串直接放在您抛出的异常中,从而生成更清晰的回溯,而无需重复错误字符串。
  • ISC:检查隐式字符串连接,这有助于捕获缺少逗号的错误。(可能与格式化程序冲突)
  • PGH:检查模式,例如没有特定错误代码的类型忽略或 noqa。
  • PL:一组四个代码组,涵盖了 PyLint 的一部分(600 条规则中的 200 条左右)。
  • PT:帮助测试遵循最佳 pytest 实践。一些代码并不理想,但很多代码都很有帮助。
  • PTH:想要迁移到使用现代 pathlib 吗?这将有所帮助。在某些情况下,性能很重要,但在其他情况下,pathlib 更易于阅读和使用。
  • RUF:Ruff 特定的代码,包括删除不再使用的 noqa。
  • T20:禁止在代码中使用 print(基于它是一种常见的调试工具的假设)。
  • UP:将旧的 Python 语法升级到您的 target-versionRF103
  • FURB:来自 refurb 工具,一系列有用的清理操作。
  • PYI:类型相关的检查

上面还包含了一些其他的小检查,Ruff 中还有更多可用的检查。您可以使用 ALL 获取所有检查,然后忽略您想要忽略的检查。新的检查在次要版本中激活之前会进入 --preview

您还可以将 Ruff 徽章添加到您的仓库中

Code style: Ruff)

[![Code style: Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json))](https://github.com/astral-sh/ruff)
.. image:: https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json
    :target: https://github.com/astral-sh/ruff
Ruff 替换的独立工具

PyCln

PyCln 将清理您的导入,如果您有任何不需要的导入。为此有一个 Flake8 检查,但通常自动执行清理比强制用户手动删除不需要的导入更好。如果您使用手动阶段,则它是可选的而不是自动的。

- repo: https://github.com/hadialqattan/pycln
  rev: "v2.4.0"
  hooks:
    - id: pycln
      args: [--all]
      stages: [manual]

Flake8

Flake8 可以为您检查一系列良好的实践,从简单的样式到可能混淆或分散用户注意力的内容,例如未使用的导入、从未使用过的命名值、可变默认参数等等。与 black 和其他一些工具不同,flake8 不会纠正问题,它只会报告问题。一些检查本可以有自动修复,可惜(这就是 Black 很棒的原因)。这是一个建议的 .flake8setup.cfg,以启用与 Black 的兼容性(遗憾的是,flake8 不支持 pyproject.toml 配置)

[flake8]
extend-ignore = E203, E501

Flake8 的一个推荐插件是 flake8-bugbear,它可以捕获许多常见的错误。它非常有主见,并且可以通过 B9 设置变得更加有主见。您还可以设置最大复杂度,当您拥有应该分解的复杂函数时,它会提示您。这是一个有主见的配置

[flake8]
max-complexity = 12
extend-select = B9
extend-ignore = E203, E501, E722, B950

(错误 E722 非常重要,但它与已激活的 B001 相同。)以下是用于 pre-commit 的 flake8 添加,以及 bugbear 插件

- repo: https://github.com/pycqa/flake8
  rev: "7.1.1"
  hooks:
    - id: flake8
      additional_dependencies: [flake8-bugbear]

一开始会太多,因此您可以通过其标签禁用或启用任何测试。您还可以使用 # noqa: X###(其中列出检查标签)在内联禁用一个检查或一组检查。随着时间的推移,您可以修复并启用更多检查。一些有趣的插件

  • flake8-bugbear:一个很棒的检查器,可以捕获容易导致错误的常见情况。代码:BB9
  • flake8-docstrings:文档字符串检查器。--docstring-convention=pep257 为默认值,numpygoogle 也允许。
  • flake8-spellcheck:拼写检查器。代码:SC
  • flake8-import-order:强制执行 PEP8 分组导入(您可能更喜欢 isort)。代码:I
  • pep8-naming:强制执行 PEP8 命名规则。代码:N
  • flake8-print:确保您没有偷偷摸摸的 print 语句。代码:T
Flake8-print 细节

有一些东西可以验证您是否不小心添加了 print 语句,这非常有用。print 检查器的一个常见需求是将其添加到单个目录(如果您遵循推荐的约定,则为 src)。您可以通过删除仅用于此检查的目录和文件(T)来实现次优选择,方法是在您的 flake8 配置中。

[flake8]
per-file-ignores =
    tests/*: T
    examples/*: T

YesQA

随着时间的推移,您最终可能会得到不再需要的额外“noqa”注释。这是一个 flake8 辅助程序,当这些注释不再需要时,它会删除它们。

- repo: https://github.com/asottile/yesqa
  rev: "v1.5.0"
  hooks:
    - id: yesqa

您需要与 flake8 具有相同的额外依赖项。在 YAML 中,您可以保存传递给 yesqa 的列表,并在 flake8 中使用 &flake8-dependencies*flake8-dependencies 在冒号之后重复它。

isort

您可以通过 isort 自动对您的导入进行排序。这将对您的导入进行排序,并且与 black 兼容。拥有排序导入的一个原因是减少合并冲突。另一个原因是阐明导入来自哪里 - 标准库导入位于第三方导入之上,第三方导入位于本地导入之上。所有这些都是可配置的。要使用 isort,以下 pre-commit 配置将有效

- repo: https://github.com/PyCQA/isort
  rev: "5.13.2"
  hooks:
    - id: isort

为了使用它,您需要添加一些配置。您可以将其添加到 pyproject.toml 或经典配置文件中

[tool.isort]
profile = "black"

PyUpgrade

另一个有用的工具是 PyUpgrade,它监视您的代码库中“旧”样式的语法。最有用的是排除 Python 2 过时的构造,它甚至可以对不同版本的 Python 3 进行一些代码更新,例如,如果您设置 --py36-plus(例如),则可以在明确更好时添加 f-字符串(请始终使用它们,它们更快)。这是任何项目的推荐补充。

- repo: https://github.com/asottile/pyupgrade
  rev: "v3.19.0"
  hooks:
    - id: pyupgrade
      args: ["--py39-plus"]

如果您将其设置为至少 --py37-plus,则可以通过将以下行添加到您的 isort pre-commit hook 配置中来添加注释导入

args: ["-a", "from __future__ import annotations"]

还要确保 isort 在 pyupgrade 之前。现在,当您运行 pre-commit 时,它也会将您的注释清理到 3.7+ 样式!

类型检查

PC140 过去 10 年中 Python 最令人兴奋的进步之一是静态类型提示。科学 Python 项目在类型提示就绪的程度上有所不同。提供静态类型提示的挑战之一是它是在 Python 3 时代开发的,它在 Python 3.7+ 代码库中真正闪耀(由于 from __future__ import annotations,它将注释转换为字符串,并允许您在 Python 3.7+ 注释中使用未来的 Python 功能,只要您的类型检查器支持它们)。目前,建议您尽最大努力通过您的公共 API 支持类型检查(基于您支持的 Python 版本)。存根文件可以代替内联类型使用。MyPy 建议用于类型检查,尽管还有其他几个不错的选项可以尝试。如果您内置支持类型检查,则需要将空的 py.typed 文件添加到所有包/子包中,以指示您支持它。

专用页面 上阅读有关类型检查的更多信息。

用于 pre-commit 的 MyPy 添加

- repo: https://github.com/pre-commit/mirrors-mypy
  rev: "v1.13.0"
  hooks:
    - id: mypy
      files: src
      args: []

您应该始终指定参数,因为钩子的默认设置隐藏了问题 - 它的设计是为了避免配置,但您应该添加配置。您还可以将项目添加到 MyPy 的虚拟环境设置中,例如,通过 pre-commit

additional_dependencies: [attrs==23.1.0]

MY100 MyPy 在 pyproject.toml 中有一个如下所示的配置部分

[tool.mypy]
files = "src"
python_version = "3.9"
strict = true
enable_error_code = ["ignore-without-code", "redundant-expr", "truthy-bool"]
warn_unreachable = true


# You can disable imports or control per-module/file settings here
[[tool.mypy.overrides]]
module = [ "numpy.*", ]
ignore_missing_imports = true

有很多选项,你可以从只键入包含至少一个类型注释的全局代码和函数开始(默认),然后逐渐启用更多检查(可能通过慢慢取消上面列表中项目的注释)。你可以忽略上面所示库中缺少的导入,每个部分一个。你也可以使用 # type: ignore 在一行中禁用 MyPy。一种策略是首先启用 check_untyped_defs,然后是 disallow_untyped_defs,最后是 disallow_incomplete_defs。你可以通过在文件顶部添加 # mypy: <option>每个文件添加这些选项。你也可以在命令行中传递 --strict。现在,配置文件中也允许使用 strict = true MY101

上面显示的额外严格选项,如 warn_unreachable MY103ignore-without-code MY104redundant-expr MY105truthy-bool MY106 可能会触发过于频繁(例如在 sys.platform 检查中),并且偶尔需要忽略,但可以发现类型检查中的一些重大逻辑错误。

setuptools 特定检查

如果你使用 setuptools,这些检查很有用

仅限 setuptools 的检查

Check-Manifest(仅限 setuptools)

Check-manifest 是一款很棒且强烈推荐的工具,用于验证你是否有可用的 SDists。你可以从 PyPI 安装它。在你的仓库上运行它并查看结果。如果你想忽略某些文件(例如测试文件夹、示例文件夹、文档等),你可以将这些文件添加到你的 pyproject.toml 文件中

[tool.check-manifest]
ignore = [
    ".travis.yml",
]

将以下内容添加到你的 pre-commit 配置中

- repo: https://github.com/mgedmin/check-manifest
  rev: "0.50"
  hooks:
    - id: check-manifest

如果你使用 setuptools_scm,你可能需要添加

additional_dependencies: ["setuptools_scm[toml]"]
如果这太慢了

警告:对于复杂的包,这可能会很慢。你可以选择在 id 下方设置 stages: [manual],然后只显式运行它(可能只在 CI 中运行)。在 GHA 中,你应该启用手动阶段,这将运行所有检查

- uses: pre-commit/action@v3.0.1
  with:
    extra_args: --show-diff-on-failure --all-files --hook-stage manual

Setup.cfg 格式(仅限 setuptools)

有一个工具可以保持你的 setup.cfg 文件井井有条,并确保重要部分(如 Python 分类器)保持同步。这个工具 setup-cfg-fmt 对 pre-commit 提供了原生支持

- repo: https://github.com/asottile/setup-cfg-fmt
  rev: "v2.7.0"
  hooks:
    - id: setup-cfg-fmt
      args: [--include-version-classifiers, --max-py-version=3.12]

确保你在这里列出你正在测试的最高版本的 Python。

拼写检查

PC160 你可以也应该检查代码中的拼写错误。如果你想添加此功能,可以使用 codespell 检查常见的拼写错误。与大多数拼写检查器不同,它有一份要查找的错误列表,而不是“有效”单词列表。要使用

- repo: https://github.com/codespell-project/codespell
  rev: "v2.3.0"
  hooks:
    - id: codespell
      args: ["-L", "sur,nd"]

你可以在传递给 -L(或 --ignore-words-list - 通常在非实时输入时最好使用长选项)的逗号分隔字符串中列出允许的拼写。上面的示例将允许“Big Sur”和“ND”。你也可以在 setup.cfg.codespellrc 中使用逗号分隔列表。

[codespell]
ignore-words-list = sur,nd

如果你添加了 toml 额外依赖项(或使用 Python 3.11+),则可以改为在你的 pyproject.toml 中放置一个 tool.codespell 部分。

你还可以使用本地 pygrep 检查来消除常见的首字母大小写错误,例如以下错误

- repo: local
  hooks:
    - id: disallow-caps
      name: Disallow improper capitalization
      language: pygrep
      entry: PyBind|Numpy|Cmake|CCache|Github|PyTest
      exclude: .pre-commit-config.yaml

你还可以添加 -w 标志让它自动更正错误 - 如果你在第一次添加检查时有很多错误,这对于快速更正非常有用。

PyGrep 钩子

PC170 这是一个包含 预提交额外钩子集合 的仓库,用于防止一些常见的、易于检测的错误。你可以从仓库中选择所需的钩子;以下是 Restructured Text 的一些常用钩子

- repo: https://github.com/pre-commit/pygrep-hooks
  rev: "v1.10.0"
  hooks:
    - id: rst-backticks
    - id: rst-directive-colons
    - id: rst-inline-touching-normal

如果你想添加特定的类型忽略,请参阅 mypy_clean_slate,这是一个可以为你添加特定忽略的工具。你需要删除现有的类型忽略 (git ls-files '*.py' | xargs sed -i '' 's/ # type: ignore//g'),将预提交输出(在 mypy 的参数中使用 --show-error-codes)复制到名为 mypy_error_report.txt 的文件中,然后运行 pipx run mypy_clean_slate -a

请注意,如果你没有使用 Ruff 的“PGH”代码,还有 python-* 钩子

- id: python-check-blanket-noqa
- id: python-check-blanket-type-ignore
- id: python-no-log-warn
- id: python-no-eval
- id: python-use-type-annotations

Clang-format(仅限 C++)

如果你有 C++ 代码,你应该有一个 .clang-format 文件并使用以下预提交配置

- repo: https://github.com/pre-commit/mirrors-clang-format
  rev: "v19.1.2"
  hooks:
    - id: clang-format
      types_or: [c++, c, cuda]

这将在所有常用平台上使用来自 PyPI 的 1-2 MB 二进制轮子。你可以使用 pipx run clang-format -style=llvm -dump-config > .clang-format 生成这样的文件。

Shellcheck(仅限 shell 脚本)

如果你有 shell 脚本,可以使用 shellcheck 防止常见的错误。

- repo: https://github.com/shellcheck-py/shellcheck-py
  rev: "v0.10.0.1"
  hooks:
    - id: shellcheck

Prettier

PC180 Prettier 工具可以格式化大量不同的文件类型。以下是使用方法示例

- repo: https://github.com/rbubley/mirrors-prettier
  rev: "v3.3.3"
  hooks:
    - id: prettier
      types_or: [yaml, markdown, html, css, scss, javascript, json]

由于它格式化各种非常常见的文件类型(如 .html.md.yaml.js.json),你通常需要提供一个 types_or 设置(如上所示)来指定你感兴趣的自动格式化文件。你可以先尝试不使用 types_or 来查看它可以做什么。html/markdown 文件中的特殊标记可能会与自动格式化冲突 - 请检查以验证你的文件是否受支持。此检查使用 node 运行,但 pre-commit 会为你处理。

如果你有一个 .editor-config 文件,prettier 将尊重其中的规则。你还可以为 prettier 指定 配置文件,或将选项传递给 pre-commit 中的 args:。其中一个选项是 --prose-wrap,它可以设置为 "never""always" 以让 prettier 重新调整文本格式。你可以使用 根据语言的不同使用注释关闭 prettier

模式验证

有两个工具都基于 JSON Schema,你可以使用它们来验证各种配置文件。第一个是 validate-pyproject,它验证你的 pyproject.toml 文件。默认情况下,它会检查标准定义的部分(build-systemproject),以及 tool.setuptools。还有一些其他工具的插件,例如 scikit-build-corecibuildwheel。你甚至可以使用 [validate-pyproject-schema-store][] 插件获取所有 SchemaStore 的插件。使用方法如下

- repo: https://github.com/abravalheri/validate-pyproject
  rev: "v0.22"
  hooks:
    - id: validate-pyproject
      additional_dependencies: ["validate-pyproject-schema-store[all]"]

你还可以使用 check-jsonschema 验证各种其他类型的文件。它内置支持多种常见文件(请参阅文档),例如各种 CI 配置文件。你也可以编写/提供自己的模式并使用它们进行验证 - SchemaStore 提供了几百种不同的常用模式,你可以通过 URL 加载它们。它适用于 JSON、YAML 和 TOML。

- repo: https://github.com/python-jsonschema/check-jsonschema
  rev: "0.29.4"
  hooks:
    - id: check-dependabot
    - id: check-github-workflows
    - id: check-readthedocs

PyLint(嘈杂)

PyLint 非常有主见,信噪比很高。但是,通过限制默认检查或使用它们开始一个新项目,你可以获得非常好的代码风格检查,包括捕获一些其他难以捕获的有问题的代码。PyLint 通常不是预提交的良好选择,因为它需要安装你的包 - 它比 Ruff 或 Flake8 的检查更不静态。以下是一个建议的 pyproject.toml 条目,以帮助你入门

[tool.pylint]
py-version = "3.9"
jobs = "0"
reports.output-format = "colorized"
similarities.ignore-imports = "yes"
messages_control.enable = ["useless-suppression"]
messages_control.disable = [
  "design",
  "fixme",
  "line-too-long",
  "wrong-import-position",
]

以及一个 noxfile 条目

@nox.session
def pylint(session: nox.Session) -> None:
    session.install("-e.")
    session.install("pylint>=3.2")
    session.run("pylint", "<your package>", *session.posargs)

你可以使用 run: pipx run nox -s pylint -- --output-format=github 将其添加到你的 GitHub Actions 中。你可以将 <your package> 替换为模块名称。

Jupyter Notebook 支持

Ruff

Ruff 原生支持 Notebook。您不再需要启用它,在 Ruff 0.6+ 版本中默认开启。如果您想根据 Notebook 控制规则,您可以像其他文件一样使用 **.ipynb 进行匹配。

Black

对于 Black,只需确保您使用 id: black-jupyter 钩子而不是 id: black;这也会包含 Notebook。

NBQA

您可以使用 nbQA 将其他工具适配到 Notebook。但是,请先检查该工具是否原生支持 Notebook,现在很多工具都支持了。

清除输出

您可能还会喜欢以下钩子,它可以清除 Jupyter 输出

- repo: https://github.com/kynan/nbstripout
  rev: "0.7.1"
  hooks:
    - id: nbstripout