Linting with pyflakes
A linter reads your code without running it and reports mistakes that are almost always bugs or clutter: names that were never defined, imports nobody uses, variables assigned and then ignored. It finds them before a test or a user does.
import ast
from pyflakes.checker import Checker
source = (
"import os\n"
"def area(r):\n"
" unused = 1\n"
" return pi * r * r\n"
)
tree = ast.parse(source)
for m in Checker(tree, "demo.py").messages:
print(m)Reading the messages
- Each message has a
linenoand acol. Its class names the problem:UndefinedName,UnusedImport,UnusedVariable. m.message % m.message_argsis the text without the file name.- A linter cannot tell whether your logic is right. It complements tests rather than replacing them.
On a desktop you would run pyflakes . over a project, or flake8 or ruff, which add style rules on top. Editors run one as you type.
Your task
Write lint(source) returning a sorted list of (line, kind) pairs, where kind is the pyflakes message class name such as "UnusedImport". If the source does not parse, return [(line, "SyntaxError")] with the line number from the error.
The explanation opens here once every check passes.