#296: Lint & Format Code With Ruff
When we work on larger Python projects, inconsistent formatting and lingering lint errors can break our flow. We may use tools like Black, isort, and Flake8 to keep code clean, but running each in sequence feels slow and an extra burden that we soon will skip. Luckily for us, there is a tool named Ruff by the same team that wrote uv. Let us see how Ruff can help us to get more consistent Python code.
Installation
We can install Ruff with this command to have it as a system wide tool:
If you prefer a standalone installer, you can run one of these platform-specific commands:
# On macOS and Linux.
curl -LsSf https://astral.sh/ruff/install.sh | sh
# On Windows.
powershell -c "irm https://astral.sh/ruff/install.ps1 | iex"
Check for common problems
We can use Ruff as a linter that checks for common problems in Python code with this command:
Without specifying a specific file, Ruff will check the current directory and all its sub-directories. If we run this command the first time in a larger project, we may get a lengthy list of errors. Therefore, it may be helpful to check specific files when we want to start cleaning up our code:
ruff check .\data\__all_models.py
F401 [*] `.entities.Task` imported but unused
--> data\__all_models.py:1:23
|
1 | from .entities import Task
| ^^^^
|
help: Remove unused import: `.entities.Task`
Found 1 error.
[*] 1 fixable with the `--fix` option.
Ruff can fix the error in this file automatically, when we run Ruff with the --fix option:
If we now run Ruff once more, it shows us that all checks now pass:
Format code
We can use Ruff to get a consistent formatting in all of our applications. For that we can call Ruff with the format command:
This time Ruff will go through all files in the current folder and all sub-folders and formats everything to the (pre-) defined rules.
If you prefer a preview for a specific file, you can use the --diff option:
ruff format .\data\database.py --diff
--- data\database.py
+++ data\database.py
@@ -6,7 +6,7 @@
def create_session_factory(db_file: str) -> sessionmaker:
engine = create_engine(
- 'sqlite:///' + db_file, connect_args={"check_same_thread": False}, echo=False
+ "sqlite:///" + db_file, connect_args={"check_same_thread": False}, echo=False
)
This shows us what Ruff would change, in this case the string definition uses now double-quotes instead of single-quotes.
Customisations
There are many opinions about formatting and linting code that may contradict each other. Ruff takes a large default set with sensible settings that we can modify at many levels. We can put our modifications in a dedicated ruff.toml file or add a Ruff-specific [tool.ruff] section in a pre-existing pyproject.toml file:
As with all formatter and linters, try to keep the customisations at a minimum. The rules are there for a reason and it may be a lot simpler just to go with the common rules than to customise every last part.
Conclusion
Ruff is a super-fast tool that can help us to find silly mistakes and formats our code in a consistent manner. I suggest you start with the default configuration and only make customisations when you have a valid use-case that beats the Python conventions.