What is Ruff?
In a nutshell, Ruff is a super, mega-ultra fast linter for Python that can be used to replace tools such as Black and Flake8. It’s good practice to check your homework and a good standard to use as a base for writing code is PEP8.
OK, so what is PEP8?
Line 7 of The Zen of Python (Python’s guiding principles) states unambiguously: “Readability counts” and whist Python is deliberately ultra-flexible, just because you can write Python is an infinite number of ways doesn’t mean that you should. For the most part, the code we write will, at some point, be read, maintained or otherwise amended by others. Developers worked here before us and will after we leave, working to a baseline standard that is accepted across the Python world means that anyone else can easily read, and therefore maintain, our projects.
One more apt line from the Zen of Python: “Special cases aren’t special enough to break the rules.”
We already use Flake8, so why would we bother with a new toy?
One of the big selling points of Ruff is it’s speed. Ruff claims to be up to 100 times faster than Flake8, which in itself can be a reason. That in itself is not a reason to change anything, unless old and slow is a real problem. In many cases, Flake8 will be found in CI pipelines, where we may have to pay per-second. Those seconds add up, quickly. This means that there is the potential for a real cost saving for what is little more than changing a single word in a pipeline, from “flake8” to “ruff”.
Furthermore, Ruff can be used as a replacement for other commonly used tools and linters, such as black
, isort
, pydocstyle
and pyupgrade
.
On type checking, whilst Ruff can catch some typing issues, it is not a formal type checker. I would continue to use something like mypy
.
Ruff respects pyproject.toml
, which is great if you’re using something like Poetry. Flake8 on the other hand doesn’t because until Python 3.11, Python didn’t have a native TOML parser in the core, something that even now requires an external library, flake8-pyproject
. If you want to keep your Ruff and package TOML files separate, you can use a ruff.toml
file instead.
Setup
pip install ruff
and it’ll work OOTB. You don’t need to create a distinct configuration unless you want to, the defaults are well thought out.
Demo
Let’s write some poorly constructed Python. Unused imports, super-long lines, bad indentation and more.
import datetime
def get_a_silly_long_string():
return "foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar"
def multiple_spaces():
return "bar" + "baz"
def poor_indent():
return "Foo"
if __name__ == "__main__":
pass
Whilst Ruff does work out-of-the-box, we can specify the rules we’d like to focus on.
E111
= Indentation not multiple of 4E117
= Over indentationE222
= Spaces are squiffy (over/under used)E
= PEP8F
= PyFlakes, a basic error reporter
Now with can either create a ruff.toml
with the following:
select = [
"E111",
"E117",
"E222",
"E",
"F",
]
Or, we can add this to our pyproject.toml
:
[tool.ruff]
select = [
"E111",
"E117",
"E222",
"E",
"F",
]
Now we run the linter with ruff check .
main.py:1:8: F401 [*] `datetime` imported but unused
main.py:4:89: E501 Line too long (140 > 88 characters)
main.py:8:1: E117 Over-indented
main.py:8:25: E222 Multiple spaces after operator
main.py:12:1: E111 Indentation is not a multiple of 4
Found 5 errors.
[*] 1 potentially fixable with the --fix option.
Let’s see what the auto-fix does:
$ ruff check . --fix
main.py:3:89: E501 Line too long (140 > 88 characters)
main.py:7:1: E117 Over-indented
main.py:7:25: E222 Multiple spaces after operator
main.py:11:1: E111 Indentation is not a multiple of 4
Found 5 errors (1 fixed, 4 remaining).
Whilst Ruff can be used instead of black
, it’s not really intended as such and they do differ.
IDEs
You can add Ruff to any IDE that supports LSP (a protocol that strandardises the language used for defining IDE plugins, enabling cross-application plugin support, like intellisense). I’m not going to go through all IDEs, but…
Pycharm
Settings > Plugins > Marketplace and search for Ruff, install. Given a minute or two to index your project, it will then highlight far in excess of what Pycharm uses as a baseline minimum.
VS Code
Bring up the extensions panel with CRTL + shift + x
, then search for “ruff”.
Finally
Ruff is an outstanding addition to any Python developer’s toolbox. It’s blisteringly fast, accurate and can be used as a single drop in replacement for many libraries, which often come with maintaining multiple different config files. It’s designed to be trivial to use and can be run adequately with no config whatsoever. Give it a go.