以静默开始,而不是以噪音开始。但请开始吧!
项目描述
Pylint-Ignore
以静默开始,而不是以噪音开始。但请开始吧!
项目/仓库
代码质量/CI
名称 | 角色 | 自 | 至 |
---|---|---|---|
Manuel Barkhau (mbarkhau@gmail.com) | 作者/维护者 | 2020-06 | - |
开发者人机工程学
Pylint的主要问题是开发者人机工程学。Pylint生成的消息可以很有价值,但您在使用它之前需要做一些工作。如果您有一个稳定的代码库,您可能需要
- 研究配置选项
- 禁用许多无用的消息
- 盲目地在代码中添加
pylint:disable
注释。
使用Pylint-Ignore,您可以立即从Pylint中受益。您无需先浏览无穷无尽的噪声消息,无需花时间配置,也不需要更改您的代码。即使您开始时忽略现有代码的所有消息,您也可以立即为新编写的代码受益。
那么,现有代码的墙式消息怎么办?嗯,至少您可以在有时间的情况下逐渐改善您的状况。换句话说,您可能现在已经陷入困境,但至少您可以停止继续挖坑,并逐渐开始爬出来。
工作原理
pylint-ignore
命令是pylint
包的一个薄包装。您可以立即通过运行以下命令开始
$ pip install pylint-ignore
Installing collected packages: astroid,isort,pylint,pylint-ignore
...
Successfully installed pylint-ignore-2020.1006
$ pylint-ignore src/
************* Module src/mymodule.py
src/mymodule.py:290:0: W0102: Dangerous default value sys.argv[1:] (builtins.list) as argument (dangerous-default-value)
...
-------------------------------------------------------------------
Your code has been rated at 9.92/10
$ echo $? # exit status != 0
28
pylint-ignore
命令读取一个名为pylint-ignore.md
的文件,您应该将其作为您仓库的一部分保留。该文件包含应忽略的消息,并且如果您指定了--update-ignorefile
参数,则会自动更新新条目。
$ pylint-ignore src/ --update-ignorefile
-------------------------------------------------------------------
Your code has been rated at 10.00/10 (previous run: 9.92/10, +0.08)
$ echo $? # exit status == 0
0
原始消息不再出现在输出中,而是记录在pylint-ignore.md
中,现在可能看起来像这样
...
## File src/mymodule.py - Line 290 - W0102 (dangerous-default-value)
- message: Dangerous default value sys.argv[1:] (builtins.list) as argument
- author : Manuel Barkhau <mbarkhau@gmail.com>
- date : 2020-07-17T21:15:25
```
289:
> 290: def main(args: Sequence[str] = sys.argv[1:]) -> ExitCode:
291: try:
```
理想情况下,您应该在开始使用Pylint时只做一次,然后文件将只会越来越小。在您的时间允许的情况下,使用pylint-ignore
的推荐方法如下
- 如果一条消息指的是一个有效的问题(特别是错误和警告),请更新您的代码以解决该问题。
- 如果一条消息是误报,请向您的代码添加如下形式的注释:
# pylint:disable=<symbol> ; explain why this is a false positive
- 如果这是一条无用的消息(例如,与您的代码格式化程序行为冲突的空白规则),应该始终忽略,则通过您的
pylintrc
或setup.cfg
文件忽略。
原则上,这些是在使用Pylint本身时拥有的相同选项。对于上述示例,dangerous-default-value
(在[https://docs.python-guide.org/writing/gotchas/#mutable-default-arguments](https://docs.python-guide.org/writing/gotchas/#mutable-default-arguments)中是一个有用的消息)只是在这个特定情况下不是。您可能采取第2种方法,并添加一个pylint:disable
注释。
def main(args: Sequence[str] = sys.argv[1:]) -> ExitCode:
# pylint:disable=dangerous-default-value; args is not mutated
# mypy prevents this because Sequence[str] does not support mutation
try:
通过这种更改,下次您运行pylint-ignore --update-ignorefile
时,相应的条目将消失,积压将缩小。
CLI用法
pylint-ignore
命令只有两个选项,任何其他命令行选项都将传递给pylint
。例如,pylint-ignore --help
将表现得与pylint --help
完全相同。pylint-ignore
提供的选项是
Usage: pylint-ignore [options]
Options:
--ignorefile=<FILE> Path to ignore file [default: pylint-ignore.md]
--update-ignorefile Update the ignorefile, adds new messages,
removes any messages that are no longer
emmitted by pylint (were fixed or disabled)
通常,pylint-ignore
命令不会更新pylint-ignore.md
文件。这对于
- 正常开发,如果您不引入任何新问题的政策。
- CI/CD构建系统,您希望报告任何新引入的问题。
如果您修复了一个问题或显式禁用了一条消息,您可以通过添加--update-ignorefile
参数来清理过时的条目。例如
$ pylint-ignore --update-ignorefile src/ test/
注意:如果您更改了在pylint-ignore.md
文件中有条目的某些代码,条目可能不再与Pylint生成的消息匹配。通常,只要代码本身没有更改并且构建不会失败,行号的变化就会被检测到。希望您不需要习惯性地使用--update-ignorefile
,但您可能偶尔需要使用它,仅为了刷新已变得无效的现有条目。当然,您也可以利用这样的机会来处理潜在的问题。
与pre-commit
集成
pylint-ignore
可以用作预提交钩子,但继承了预提交集成中描述的pylint
的限制。
要使用提供的插件将pylint-ignore
作为预提交钩子,请将以下条目添加到正在检查的仓库中的.pre-commit-config.yaml
文件中
- repo: https://github.com/mbarkhau/pylint-ignore
rev: "2021.1024"
hooks:
- id: pylint-ignore
如果您发现只有在本地Python环境中运行时pylint
才能正常工作(如预提交集成中所述),则可以使用以下本地钩子条目代替pylint-ignore
repos:
- repo: local
hooks:
- id: pylint-ignore
name: pylint-ignore
entry: pylint-ignore
language: system
types: [python]
require_serial: true
# args: [
# "--rcfile",
# "setup.cfg",
# "src/",
# "test/",
# "--ignore-paths",
# "scripts/,fixtures/,setup.py",
# ]
根据需要,可以将args: [...]
属性添加到条目中。
要测试,可以使用pre-commit run
$ pre-commit run pylint-ignore --all-files
配置
Pylint的行为可以像往常一样配置,有关详细信息,请参阅命令行参数和配置文件。
pylint-ignore.md
文件
您可以在以下位置查看示例文件:fixtures/pylint-ignore.md。您可以将此文件视为可能的潜在问题的存档。条目首先按类别排序,即错误和警告首先,然后按频率排序。您可以使用--ignorefile
参数更改路径/文件名:pylint-ignore --ignorefile=etc/pylint-backlog.md
pylint-ignore.md
文件使用自定义格式,但它是有效的Markdown。这种选择主要是为了让您更容易在github/gitlab/bitbucket等平台上阅读和审查它。您不需要编辑该文件,并且它不是任何其他程序需要解析的格式,因此我认为这是一个合理的选择。
这种方法解决了什么问题,为什么不用Pylint本身?
为什么使用Pylint-Ignore
问题1:噪音
flake8比Pylint使用得更多,原因之一是“噪音”问题得到了Pylint文档早期的认可。实际上,使用Pylint的挫败感如此明显,以至于它甚至成为了项目标语的主题:“它不仅仅是一个让你烦恼的代码检查工具!”
Pylint-Ignore当然不会消除这种噪音,但它将它们放置在一个专门的位置,而不是终端中的垃圾邮件。您的代码中的每个问题都是文件中的一个条目,而不是需要反复扫描的行。
一旦您已经建立了安静作为您的基准,您就可以放心,您只需要处理两种状态:OK和FAIL。这大大降低了开发者的认知负担,使得您能够在CI系统中集成代码检查工具,即使您还没有处理完所有的Pylint消息。
问题2:设置成本
我不会过多地强调这一点,但最好尽可能地少花时间开始使用有用的工具,而不是将其推迟到未来,可能永远无法使用,或者只是偶尔使用,而不是将其作为您常规工作流程的一部分。
话虽如此,您越早花时间来减少这些设置成本,并在您的配置中禁用实际噪音的消息,Pylint对您就越有用。每个无用的消息都会增加您错过更重要消息的可能性。
即使您已经完美设置Pylint并完成了代码库的初始清理,也可能会在您的开发工作流程中继续使用Pylint-Ignore。
问题3:勤奋是稀缺的
没有Pylint-Ignore,你(或你的队友)很可能会对你的配置中的禁用
部分过于热情。迟早你会有时间紧迫,实际上关闭了代码检查器。谁会在后来知道或关心消息是否被禁用,是因为它真正无用,还是因为你当时有其他优先事项?你可以尝试提醒自己回顾事物,你可以添加一个待办
注释,你希望记住定期使用grep
搜索,但这样的良好意图有很大可能迟早会被遗忘。
有了Pylint-Ignore,在你的代码库中有一个专门的文件,这比其他选项更明确、更直观。条目按重要性排序,而不是随机出现在你的终端上。你可以专注于其他事情,并在你有时间时处理轻微的代码检查问题,或者也许可以将它们留作新成员的第一项贡献,这样他们就可以适应你的工作流程。
问题4:恶意合规
你可能会发现一些消息有用,但现有的代码库,一次性的工作量会太大。你不想禁用它,但又不想一开始就启用它。例如,可能是missing-function-docstring
消息。如果你启用了它,你可能会发现以下模式出现
def get_author_name() -> str:
"""Gets the author name and returns it as a string."""
如果不是很明显,上面的文档字符串是多余的,它没有提供比函数名称和类型已经包含的新信息。换句话说,诱惑是通过改变代码来安抚代码检查器,这样做至多是无用的时间浪费,在最坏的情况下是恶意和适得其反的。
你处于控制地位,如果你觉得忽略代码检查器是合理的,你只需忽略并提交更改即可。有了Pylint-Ignore,你不必因为第二辆车的花朵在看到行李上到处喷油而晕倒而停止前进。这个pylint-ignore.md
会跟踪问题,你可以在到达车站后处理它,而不是在你全速前进时处理。
问题5:误报
虽然你可以也应该通过使用禁用
注释来处理大多数误报,但在某些情况下,你可能宁愿不这样做,甚至在某些情况下甚至不可能这样做。对于这些边缘情况,你可以在pylint-ignore.md
中永久性地留下一个条目,并在出现新情况时仍然受益于其他情况下有用的消息。
动机/为什么使用Pylint
如果你不相信Pylint、代码检查器或静态分析(总的来说)的有用性(也许你认为它们主要是对过于挑剔的人的额外工作),让我向你展示是什么说服我使用Pylint。
动态代码和作用域相关错误
一些代码在语法上有效,甚至可以执行而不抛出错误,但几乎可以肯定不是作者的本意。当然,如果你有适当的测试,你会捕获这样的错误,但即使如此,如果静态分析可以帮助你更快地捕获这样的错误,它可能也会有所贡献。
def frobnicate(seq: Sequence[int]):
total = 0
for value in seq:
total += value
return value / len(seq)
上面的代码会“工作”,具体取决于你如何调用它,它甚至不会抛出错误,但它几乎肯定是不正确的。如果函数长度超过5行,错误可能就不那么明显了。最近我至少花了一个小时追踪这样的错误,它已经进入了生产环境。无论如何,Pylint会为这样的代码报告以下消息
W0631: Using possibly undefined loop variable 'value'
(undefined-loop-variable)
还有其他消息,与名称遮蔽和未使用的参数相关,我发现它们特别有用,因为它们指出了实际的错误,而不仅仅是作者根据Pylint的说法所认为的“纯粹”的偏好或“最佳实践”。
支持代码审查
在与其他人合作时,代码检查器最重要的可能就是,有关代码风格等琐事的问题反馈将来自计算机而不是来自另一个人。这对审查者和作者来说都是一种优势。
- 花费宝贵的时间在重复的琐事反馈上并不有趣。
- 在审查期间被指出自己的愚蠢错误可能并不有趣,甚至可能令人尴尬。
代码检查器还允许你制定一个规则,这将结束关于主观风格偏好的讨论。可能每个人都会同意任何特定的风格都是愚蠢的,但关于代码风格的无限讨论则更加愚蠢。因此,制定这个规则:如果它通过了代码检查器,讨论就结束了(当然,除非代码检查器仅仅是因为被恶意禁用而通过)。
捕捉Python的陷阱
初级程序员甚至(新接触Python的资深程序员)可能没有意识到与Python一起工作的常见陷阱。他们需要尽可能多的帮助,你可以将静态分析视为一种编码知识形式,以及来自资深程序员的自动化交流。你写的代码可能很完美,但问题是其他人,Pylint可以帮助你在项目中保持一些基本标准,即使在引入新开发人员时也是如此。
一个改进的提示
当你专注于解决实际问题,专注于完成实际工作™时,你可能会编写出一些可能很好用,可能通过所有你的测试,可能很有效,甚至可能(为了辩论的目的,我们假设)最优和正确的代码。
R0902 Too many instance attributes (10/7) (too-many-instance-attributes)
简单的代码指标,如too-many-locals
、too-many-branches
等,可能很主观,繁琐,家长式作风的电子游戏胡言乱语,当然,这些指标当然不应该被转变为目标。
class ToCoolForSchool():
# pylint:disable=too-many-branches
# behold this glorious perfection 🤘 — rockstar@unicorn.io
...
除了这些情况之外,复杂的代码的一个常见原因是作者太懒惰没有时间重构他们的代码,以便其他人也能理解它。
替代方案
在Pylint的过多噪音让你不敢使用它的情况下,我希望你会觉得pylint-ignore
很有用,至少可以开始使用。这里还有一个你可能喜欢的方案。
选择性加入
Itamar Turner-Trauring在“为什么Pylint既有用又难以使用,以及你如何真正使用它”中提出的一个替代方案是以下做法:
- 首先,将Pylint设置成什么都不做:禁用所有消息
- 选择性地启用一些检查,如果它们有价值则保留
- 重复
显然,这是一个缩写,所以我鼓励你阅读他的文章,如果选择性地白名单对你来说是一个更好的方法。对我来说,这种方法存在勤奋问题,因为它要求你至少重新访问配置几次,跟踪你发现有价值的内容,这样你就更容易忽视它。
自动禁用注释
另一种自动方法是使用 pylint-silent。如果你考虑这种方法,请务必使用版本控制。
pylint-ignore 的变更日志
2021.1024
-
添加/文档支持 pre-commit。感谢James Quilty为此做出的贡献 github/issue/9 github/pull/10 :heart:。
-
修复 github #11:MessagesHandlerMixIn 已在pylint 2.12中删除
-
破坏性变更:放弃对
Python<3.7
的支持 -
破坏性变更:放弃对
pylint<2.4
的支持由于pylint内部API的变化,较旧版本的pylint不再受支持。如果你需要使用较旧的pylint版本,你必须将
pylint-ignore==2021.1021
锁定。
2021.1020
- 修复 github #6:Windows上路径问题。
感谢davidsheldon
2021.1019
感谢 @agraul (Alexander Graul) 发现这些问题。
2021.1018
- 修复 github #2:Typerror
2020.1014
- 修复 gitlab #2:与无效参数调用相关的错误(这导致底层的pylint错误被隐藏)。
2020.1013
- 修复:与MacOSX和Windows上的多进程相关的错误
2020.1012
- 修复:启用使用
--jobs=<n>
的功能,其中n > 1
2020.1008 - 2020.1011
- 修复:与python 2.7和pylint 1.9.5的兼容性
2020.1007
- 将概述部分添加到
pylint-ignore.md
文件中。 - 修复:处理与特定文件或行无关的问题(例如,多个文件中的
duplicate-code
) - 修复:
--ignorefile
参数的解析。 - 修复:
--jobs
参数的解析。 - 再次允许忽略
(E) error
消息,优先级高于忽略文件中的条目。
2020.1006
- 不要忽略类型为
(E) error,可能存在代码中的错误
的消息
2020.1003
- 初始版本