学习PyLint的各个方面

202 阅读3分钟

"PyLint可以拯救你的生命 "是一个夸张的说法,但并不像你想象的那么夸张!PyLint可以让你远离非常非常难找的复杂bug。PyLint可以让你远离非常非常难以发现的复杂bug。在最坏的情况下,它可以为你节省测试运行的时间。最好的情况是,它可以帮助你避免复杂的生产错误。

我很不好意思地说,这可能是很常见的。测试的命名永远都是那么奇怪:没有人关心这个名字,而且往往找不到一个自然的名字。例如,请看这段代码。

def test_add_small():
    # Math, am I right?
    assert 1 + 1 == 3
    
def test_add_large():
    assert 5 + 6 == 11
    
def test_add_small():
    assert 1 + 10 == 11

这个测试是有效的。

collected 2 items                                                                         
test.py .. 
2 passed 

但这里有一个关键问题:如果你覆盖了一个名字,测试基础设施就会愉快地跳过这个测试!

在现实中,这些文件可能有数百行之长,而添加新测试的人可能不知道所有的名字。除非有人仔细观察测试输出,否则一切看起来都很好。

最糟糕的是,添加覆盖测试破坏覆盖测试以及导致prod的问题可能相隔几天、几个月甚至几年。

PyLint发现了它

但就像一个好朋友,PyLint就在你身边。

test.py:8:0: E0102: function already defined line 1
     (function-redefined)

糟糕的是

就像90年代的情景喜剧一样,你越是接触PyLint,它就越是有问题。这对于一个库存建模程序来说是完全合理的代码。

"""Inventory abstractions"""

import attrs

@attrs.define
class Laptop:
    """A laptop"""
    ident: str
    cpu: str

似乎PyLint有意见(可能是在90年代形成的),而且不怕把它们当作事实来陈述。

$ pylint laptop.py | sed -n '/^laptop/s/[^ ]*: //p'
R0903: Too few public methods (0/2) (too-few-public-methods)

丑陋的

有没有想过在一个被数百万人使用的工具中加入你自己未经审核的意见?PyLint每月有1200万次下载。

"如果它太挑剔,人们会直接禁用整个检查。"-PyLint问题6987,2022年7月3日

它对增加一个可能有很多假阳性的测试所采取的态度是......"嗯。"

让它为你工作

PyLint很好,但你需要小心地与它互动。下面是我推荐的三件事,让PyLint为你工作。

1.钉住它

钉住你使用的PyLint版本,以避免任何意外的发生

在你的.toml 文件中。

[project.optional-dependencies]
pylint = ["pylint"]

在你的代码中。

from unittest import mock

这与这样的代码相对应。

# noxfile.py
...
@nox.session(python=VERSIONS[-1])
def refresh_deps(session):
    """Refresh the requirements-*.txt files"""
    session.install("pip-tools")
    for deps in [..., "pylint"]:
        session.run(
            "pip-compile",
            "--extra",
            deps,
            "pyproject.toml",
            "--output-file",
            f"requirements-{deps}.txt",
        )

2.默认拒绝

禁用所有检查。然后启用那些你认为有高价值--假阳性比率的检查。(不仅仅是假阴性与假阳性的比率!)。

# noxfile.py
...
@nox.session(python="3.10")
def lint(session):
    files = ["src/", "noxfile.py"]
    session.install("-r", "requirements-pylint.txt")
    session.install("-e", ".")
    session.run(
        "pylint",
        "--disable=all",
        *(f"--enable={checker}" for checker in checkers)
        "src",
    )

3.检查器

这些是我喜欢的一些。强制执行项目的一致性,避免一些明显的错误。

checkers = [
    "missing-class-docstring",
    "missing-function-docstring",
    "missing-module-docstring",
    "function-redefined",
]

使用PyLint

你可以只取PyLint的好部分。在CI中运行它以保持一致性,并使用最高价值的检查器。

丢掉不好的部分。默认的拒绝检查器。

避免丑陋的部分。钉住版本以避免出现意外。