Linting your Python code
In this section, we will learn how to use linters, formatters, and pre-commit hooks to improve the quality of your code and automate the process of checking for errors and enforcing coding standards.
The Style Guide for Python Code is called PEP8 (or see this stylized presentation). Rules are proposed by the community of users, and subject to change. There are hundreds of rules as of 2024, and it would not be feasible (even desirable) to check them manually each time we write a code.
Linters: the flake8 example
A linter is a tool that analyzes your code for potential errors, bugs, and stylistic issues.
It can help you catch mistakes early in the development process and
ensure that your code is consistent and maintainable.
There are many linters available for Python, but one of the most popular is flake8.
flake8
is a command-line tool that runs several other linters, including pyflakes
and pycodestyle
, and
reports any errors or warnings that it finds.
You can run flake8
from the command line to analyze your code.
For example, to check all Python files in the current directory and its subdirectories, you can use the command flake8 .
(see the documentation for more options/configuration).
flake8
will report any errors or warnings that it finds,
along with the line number and a brief description of the issue.
Fix the issues reported by flake8
and run it again to ensure that
your code is free of errors and warnings.
Exercise: run flake8
on the module ~/robust-programming/tests/bad_quality_flake8.py
and fix the errors:
flake8 ~/robust-programming/tests/bad_quality_flake8.py
Note that we installed flake8
but also some of its extensions to ensure a wider rule coverage:
flake8==7.0.0
flake8-docstrings==1.7.0
pep8-naming==0.13.3
Formatters: the black example
Complying to a coding style can be a tedious task, which a linter won’t help you with. A formatter can help you automate this process by automatically formatting your code to comply with a specific coding style.
One of the most popular formatters for Python is black.
black
reformats your entire file in place to comply with the black coding style (a strict subset of PEP 8).
It is a great tool to enforce consistent formatting across your code base.
Exercise: first run black
on the module ~/robust-programming/tests/bad_quality_black.py
with the options --test
and diff
black --check --diff ~/robust-programming/tests/bad_quality_black.py
--test
runs black without overwriting the file, and --diff
shows you what
would have been changed: +
are additions, and -
are deletions. Once you
understand better the changes, you can directly apply black
to reformat the file:
black ~/robust-programming/tests/bad_quality_black.py
Linters vs formatters
Should you use a linter or a formatter? In practice both!
They usually are very complementary, and your code will be only
better by using both. Note however they can contredict each other
sometimes, see e.g. the black
FAQ
to remedy to this problem.
When to run linters and formatters?
You can run your favourite linter and formatter on your local
machine each time you make changes, but let’s face it: it will
become annoying very quickly, and there is a high chance to forget to
do it. Instead, you can automate the rule checks using pre-commit
hooks
and continuous integration
jobs.
Pre-commit hooks
Pre-commit hooks are scripts installed in your .git/hooks
directory that are run before each commit.
They can be used to automate the process of checking for errors and enforcing coding standards,
and can help you catch mistakes early in the development process.
In Python, the pre-commit package can be used to manage pre-commit hooks. It allows you to define a set of hooks in a configuration file, and then run them automatically before each commit.
Continuous integration
Pre-commit hooks are great, but they assume that you have your development environment installed in your local machine, which is not always the case. So instead of enforcing checks before committing the code, you can perform the check after each push in the repository. This is called continuous integration, and you will learn more at the end of this lecture (see continuous integration).