Science and technology

PyLint: The good, the dangerous, and the ugly

Hot take: PyLint is definitely good!

“PyLint can save your life” is an exaggeration, however not as a lot as you may suppose! PyLint can preserve you from actually actually arduous to search out and complex bugs. At worst, it could prevent the time of a take a look at run. At greatest, it could assist you keep away from difficult manufacturing errors.

The good

I’m embarrassed to say how frequent this may be. Naming exams is perpetually bizarre: Nothing cares concerning the identify, and there is usually not a pure identify to be discovered. For occasion, have a look at this code:

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

The take a look at works:

collected 2 objects                                                                        
take a look at.py ..
2 handed

But this is the kicker: If you override a reputation, the testing infrastructure fortunately skips over the take a look at!

In actuality, these information may be tons of of traces lengthy, and the individual including the brand new take a look at may not concentrate on all of the names. Unless somebody is take a look at output fastidiously, the whole lot seems to be superb.

Worst of all, the addition of the overriding take a look at, the breakage of the overridden take a look at, and the downside that ends in prod is perhaps separated by days, months, and even years.

PyLint finds it

But like a superb buddy, PyLint is there for you.

take a look at.py:8:0: E0102: operate already outlined line 1
     (function-redefined)

The dangerous

Like a 90s sitcom, the extra you get into PyLint, the extra it turns into problematic. This is totally affordable code for a listing modeling program:

"""Inventory abstractions"""

import attrs

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

It appears that PyLint has opinions (in all probability fashioned within the 90s) and isn’t afraid to state them as info:

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

The ugly

Ever needed so as to add your individual unvetted opinion to a software utilized by hundreds of thousands? PyLint has 12 million month-to-month downloads.

“People will just disable the whole check if it’s too picky.” —PyLint problem 6987, July third, 2022

The angle it takes in direction of including a take a look at with doubtlessly many false positives is…“eh.”

Making it give you the results you want

PyLint is ok, however it’s essential work together with it fastidiously. Here are the three issues I like to recommend to make PyLint give you the results you want.

1. Pin it

Pin the PyLint model you utilize to keep away from any surprises!

In your .toml file:

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

In your code:

from unittest import mock

This corresponds with code like this:

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

2. Default deny

Disable all checks. Then allow ones that you just suppose have a excessive value-to-false-positive ratio. (Not simply false-negative-to-false-positive ratio!)

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

3. Checkers

These are a number of the ones I like. Enforce consistency within the venture, keep away from some apparent errors.

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

Using PyLint

You can take simply the nice components of PyLint. Run it in CI to maintain consistency, and use the best worth checkers.

Lose the dangerous components: Default deny checkers.

Avoid the ugly components: Pin the model to keep away from surprises.

Most Popular

To Top