
Le problème : trop d’outils pour un code propre
Section intitulée « Le problème : trop d’outils pour un code propre »Si vous travaillez sur un projet Python, vous connaissez probablement cette situation : avant chaque commit, vous devez lancer plusieurs outils pour garantir la qualité du code.
- Flake8 pour détecter les erreurs et violations de style
- Black pour formater le code automatiquement
- isort pour trier les imports
- Pylint pour une analyse plus approfondie
- pyupgrade pour moderniser la syntaxe
Résultat : votre hook pre-commit prend 15-20 secondes. Sur un gros projet, c’est encore pire. Certains développeurs finissent par désactiver ces vérifications localement et comptent sur la CI pour attraper les problèmes — ce qui ralentit tout le monde.
Ruff résout ce problème en combinant tous ces outils en un seul, écrit en Rust, qui est 100 à 200 fois plus rapide que Flake8.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »Ce guide vous accompagne pour :
- Comprendre pourquoi Ruff change la donne pour la qualité du code Python
- Installer Ruff et le configurer pour votre projet
- Choisir les règles adaptées à vos besoins
- Formater votre code comme Black, mais instantanément
- Corriger automatiquement les problèmes détectés
- Intégrer Ruff dans VS Code, pre-commit et GitHub Actions
Pourquoi Ruff plutôt que Flake8, Black et isort ?
Section intitulée « Pourquoi Ruff plutôt que Flake8, Black et isort ? »Avant d’installer Ruff, comprenons ce qui le rend différent.
La vitesse : un vrai changement au quotidien
Section intitulée « La vitesse : un vrai changement au quotidien »Quand vous lancez Flake8 sur un projet de 100 000 lignes, vous attendez 10 à 20 secondes. Black peut prendre plusieurs minutes sur un gros projet. Ces délais s’accumulent et cassent votre concentration.
Avec Ruff, la même analyse prend moins d’une seconde. Cette différence vient de plusieurs facteurs :
- Code Rust : pas d’interpréteur Python à démarrer, exécution native
- Analyse parallèle : Ruff utilise tous les cœurs de votre processeur
- Cache intelligent : les fichiers non modifiés ne sont pas réanalysés
Un seul outil au lieu de cinq
Section intitulée « Un seul outil au lieu de cinq »Avant Ruff, maintenir un code Python propre nécessitait plusieurs outils avec chacun sa configuration :
- Flake8 avec son
.flake8ousetup.cfg - Black avec sa section dans
pyproject.toml - isort avec une autre section dans
pyproject.toml - Pylint avec son
.pylintrc
Ruff remplace tout ça avec une seule configuration dans pyproject.toml. Plus
de conflits entre outils, plus de versions incompatibles, une seule
documentation à consulter.
Compatibilité avec l’existant
Section intitulée « Compatibilité avec l’existant »Ruff est conçu pour être un remplacement transparent. Il comprend les mêmes codes d’erreur que Flake8, il formate comme Black (avec la même longueur de ligne par défaut de 88 caractères), et il trie les imports comme isort.
Si vous avez des commentaires # noqa ou # type: ignore dans votre code, Ruff
les respecte. La migration est progressive : vous pouvez commencer par remplacer
un outil à la fois.
Installation de Ruff
Section intitulée « Installation de Ruff »Ruff s’installe de plusieurs façons selon votre environnement.
La méthode la plus courante. Si vous utilisez uv (recommandé), ajoutez Ruff comme dépendance de développement :
uv add --dev ruffAvec pip classique :
pip install ruffSi vous voulez juste tester Ruff sans l’ajouter à votre projet, utilisez uvx :
uvx ruff check .uvx ruff format .Pratique pour évaluer Ruff sur un projet existant avant de l’adopter.
Sur macOS ou Linux avec Homebrew :
brew install ruffCette méthode installe Ruff globalement sur votre système.
Pour une installation globale isolée :
pipx install ruffUtile si vous voulez utiliser Ruff sur plusieurs projets sans l’ajouter aux dépendances de chacun.
Vérifier l’installation
Section intitulée « Vérifier l’installation »ruff --versionVous devriez voir quelque chose comme ruff 0.8.x.
Utilisation rapide : vos premières commandes
Section intitulée « Utilisation rapide : vos premières commandes »Ruff a deux modes principaux : linter (vérification) et formatter (formatage). Voyons comment les utiliser.
Vérifier le code avec ruff check
Section intitulée « Vérifier le code avec ruff check »La commande ruff check analyse votre code et signale les problèmes :
ruff check .Le . signifie “analyser tous les fichiers Python du dossier courant et ses
sous-dossiers”. Vous pouvez aussi cibler un fichier spécifique :
ruff check mon_script.pyExemple de sortie :
src/utils.py:12:5: F841 Local variable `result` is assigned but never usedsrc/api.py:45:1: E302 Expected 2 blank lines, found 1src/api.py:78:80: E501 Line too long (92 > 88)Found 3 errors.Chaque ligne indique :
- Le fichier et la position (ligne:colonne)
- Le code de la règle (F841, E302, E501)
- Une description du problème
Corriger automatiquement avec —fix
Section intitulée « Corriger automatiquement avec —fix »Beaucoup de problèmes détectés par Ruff peuvent être corrigés automatiquement :
ruff check --fix .Ruff modifie vos fichiers pour corriger les problèmes qu’il sait résoudre. Par exemple, il supprime les imports inutilisés, ajoute les lignes vides manquantes, et modernise la syntaxe.
Formater le code avec ruff format
Section intitulée « Formater le code avec ruff format »La commande ruff format reformate votre code comme le ferait Black :
ruff format .C’est tout. Ruff ajuste les espaces, les sauts de ligne, les guillemets, et rend votre code conforme aux conventions Python. La différence avec Black ? Ruff format est quasi instantané, même sur un gros projet.
Pour voir ce qui serait modifié sans appliquer les changements :
ruff format --check .Combiner linting et formatage
Section intitulée « Combiner linting et formatage »En pratique, vous lancez souvent les deux :
ruff check --fix .ruff format .L’ordre est important : corrigez d’abord avec le linter (qui peut ajouter ou supprimer du code), puis formatez (qui ajuste la présentation).
Comprendre les règles de Ruff
Section intitulée « Comprendre les règles de Ruff »Ruff supporte plus de 800 règles provenant de différents outils. Chaque règle a un code qui indique son origine et son type.
Les familles de règles
Section intitulée « Les familles de règles »Les règles sont organisées par préfixe. Voici les plus courantes :
| Préfixe | Origine | Ce qu’elles vérifient |
|---|---|---|
| E | pycodestyle | Erreurs de style (espaces, indentation) |
| W | pycodestyle | Avertissements de style |
| F | Pyflakes | Erreurs logiques (variables non utilisées, imports manquants) |
| I | isort | Organisation des imports |
| B | flake8-bugbear | Bugs potentiels et mauvaises pratiques |
| UP | pyupgrade | Syntaxe obsolète à moderniser |
| SIM | flake8-simplify | Code qui peut être simplifié |
| D | pydocstyle | Docstrings manquantes ou mal formatées |
| N | pep8-naming | Conventions de nommage |
| S | flake8-bandit | Problèmes de sécurité |
Règles activées par défaut
Section intitulée « Règles activées par défaut »Par défaut, Ruff active les règles E et F — les erreurs de style et les erreurs logiques de base. C’est un bon point de départ, mais vous voudrez probablement en ajouter.
Pour voir quelles règles sont actives sur votre projet :
ruff check --show-settings | grep "select"Exemples de règles utiles
Section intitulée « Exemples de règles utiles »Voici quelques règles que je recommande d’activer :
F841 — Variable locale assignée mais jamais utilisée :
# ❌ Ruff signale cette erreurdef calculate(): result = 42 # F841: 'result' est assigné mais jamais utilisé return 0E501 — Ligne trop longue (plus de 88 caractères par défaut) :
# ❌ Ligne trop longuemessage = "Ceci est un message très très très très très très très très très long"I001 — Imports mal organisés :
# ❌ Imports dans le désordreimport osfrom collections import defaultdictimport sys # devrait être avec os
# ✅ Après correction automatiqueimport osimport sysfrom collections import defaultdictUP — Syntaxe à moderniser :
# ❌ Syntaxe Python 2/ancien Python 3"{} {}".format(first, last)
# ✅ Après correction (f-string)f"{first} {last}"Configurer Ruff pour votre projet
Section intitulée « Configurer Ruff pour votre projet »La configuration de Ruff se fait dans pyproject.toml. C’est là que vous
choisissez quelles règles activer et comment Ruff doit se comporter.
Configuration de base recommandée
Section intitulée « Configuration de base recommandée »Voici une configuration de départ équilibrée :
[tool.ruff]# Version Python cible (pour les règles de modernisation)target-version = "py311"
# Longueur de ligne (88 = défaut de Black)line-length = 88
# Dossiers à ignorerexclude = [ ".git", ".venv", "__pycache__", "build", "dist",]
[tool.ruff.lint]# Règles à activerselect = [ "E", # Erreurs de style pycodestyle "F", # Erreurs Pyflakes (variables non utilisées, etc.) "I", # Tri des imports (isort) "B", # Bugs potentiels (flake8-bugbear) "UP", # Modernisation syntaxe (pyupgrade) "SIM", # Simplifications possibles]
# Règles à ignorerignore = [ "E501", # Ligne trop longue (géré par le formatter)]
# Règles que --fix peut corriger automatiquementfixable = ["ALL"]
[tool.ruff.format]# Style des guillemets (comme Black)quote-style = "double"
# Indentation (comme Black)indent-style = "space"Comprendre select, ignore et extend-select
Section intitulée « Comprendre select, ignore et extend-select »select définit les règles de base. Si vous mettez select = ["E", "F"],
seules ces familles sont actives.
extend-select ajoute des règles en plus de celles par défaut ou déjà
sélectionnées. Utile pour ajouter progressivement des règles.
ignore désactive des règles spécifiques. Par exemple, ignore = ["E501"]
désactive la vérification de longueur de ligne.
Exemple avec extend-select :
[tool.ruff.lint]# Garde les règles par défaut (E, F) et ajoute I, B, UPextend-select = ["I", "B", "UP"]Ignorer des règles dans le code
Section intitulée « Ignorer des règles dans le code »Parfois, une règle ne s’applique pas à un cas précis. Utilisez # noqa :
# Ignorer une règle sur une lignelong_variable_name = "valeur" # noqa: E501
# Ignorer plusieurs règlesimport unused_module # noqa: F401, E501
# Ignorer toutes les règles sur une ligne (déconseillé)problematic_line # noqaPour ignorer une règle sur tout un fichier, ajoutez en haut :
# ruff: noqa: F401Configuration par dossier
Section intitulée « Configuration par dossier »Vous pouvez avoir des règles différentes selon les dossiers. Par exemple, être
plus strict sur le code source que sur les tests avec per-file-ignores :
[tool.ruff.lint]select = ["E", "F", "I", "B", "UP"]
[tool.ruff.lint.per-file-ignores]# Dans les tests, autoriser les assertions et les imports *"tests/*" = ["S101", "F403"]# Dans les migrations, moins strict"migrations/*" = ["E501"]Intégrer Ruff dans votre workflow
Section intitulée « Intégrer Ruff dans votre workflow »Ruff est plus utile quand il s’exécute automatiquement. Voici comment l’intégrer dans vos outils quotidiens.
VS Code : correction en temps réel
Section intitulée « VS Code : correction en temps réel »L’extension officielle Ruff pour VS Code analyse votre code pendant que vous tapez et peut corriger automatiquement à la sauvegarde.
-
Installer l’extension
Recherchez “Ruff” dans les extensions VS Code (éditeur : Astral Software) et installez-la.
-
Configurer le formatage automatique
Dans vos paramètres VS Code (
.vscode/settings.json) :{"[python]": {"editor.formatOnSave": true,"editor.defaultFormatter": "charliermarsh.ruff","editor.codeActionsOnSave": {"source.fixAll.ruff": "explicit","source.organizeImports.ruff": "explicit"}}} -
Désactiver les autres extensions
Si vous avez Pylint, Flake8 ou Black installés, désactivez-les pour éviter les conflits et la redondance.
Avec cette configuration, chaque sauvegarde formate votre code et corrige les imports automatiquement.
Pre-commit : vérification avant chaque commit
Section intitulée « Pre-commit : vérification avant chaque commit »Pre-commit lance des vérifications avant d’accepter un commit. C’est la dernière ligne de défense avant que du code ne soit versionné.
Créez ou modifiez .pre-commit-config.yaml :
repos: - repo: https://github.com/astral-sh/ruff-pre-commit rev: v0.8.0 # Utilisez la dernière version hooks: # Linter avec correction automatique - id: ruff args: ["--fix"] # Formateur - id: ruff-formatInstallez les hooks :
pip install pre-commitpre-commit installMaintenant, à chaque git commit, Ruff vérifie et formate votre code. Si des
fichiers sont modifiés, le commit est annulé — vous devez ajouter les
modifications et recommencer.
GitHub Actions : vérification dans la CI
Section intitulée « GitHub Actions : vérification dans la CI »Ajoutez une vérification Ruff à votre pipeline CI pour garantir que tout le code mergé respecte les règles.
Créez .github/workflows/lint.yml :
name: Lint
on: push: branches: [main] pull_request: branches: [main]
jobs: ruff: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4
- name: Install uv uses: astral-sh/setup-uv@v4
- name: Run Ruff linter run: uvx ruff check --output-format=github .
- name: Run Ruff formatter run: uvx ruff format --check .L’option --output-format=github formate les erreurs pour qu’elles apparaissent
directement dans l’interface de pull request, avec des annotations sur les
lignes problématiques.
Migrer depuis Flake8, Black et isort
Section intitulée « Migrer depuis Flake8, Black et isort »Si votre projet utilise déjà ces outils, voici comment migrer vers Ruff progressivement.
Étape 1 : Ajouter Ruff en parallèle
Section intitulée « Étape 1 : Ajouter Ruff en parallèle »Commencez par ajouter Ruff sans retirer les autres outils :
uv add --dev ruffLancez Ruff et comparez les résultats avec vos outils actuels :
ruff check .Étape 2 : Reproduire votre configuration
Section intitulée « Étape 2 : Reproduire votre configuration »Ruff comprend la plupart des options de Flake8, Black et isort. Voici comment traduire une configuration typique :
Avant (Flake8 + Black + isort) :
[flake8]max-line-length = 88extend-ignore = E203, E501[tool.black]line-length = 88
[tool.isort]profile = "black"Après (Ruff seul) :
[tool.ruff]line-length = 88
[tool.ruff.lint]select = ["E", "F", "I"]ignore = ["E203", "E501"]
[tool.ruff.lint.isort]# Compatibilité avec le profil "black"combine-as-imports = trueforce-single-line = falseÉtape 3 : Retirer les anciens outils
Section intitulée « Étape 3 : Retirer les anciens outils »Une fois que Ruff donne des résultats équivalents, retirez les dépendances :
uv remove flake8 black isortSupprimez les fichiers de configuration devenus inutiles (.flake8, etc.) et
mettez à jour votre pre-commit et votre CI.
Résoudre les problèmes courants
Section intitulée « Résoudre les problèmes courants »Ruff signale trop d’erreurs
Section intitulée « Ruff signale trop d’erreurs »Si vous activez beaucoup de règles d’un coup sur un projet existant, vous pouvez avoir des centaines d’erreurs. Deux approches :
Corriger progressivement : Activez les règles une par une, corrigez, puis passez à la suivante.
Ignorer l’existant : Utilisez --add-noqa pour ajouter des commentaires
# noqa partout où il y a une erreur, puis corrigez au fil du temps :
ruff check --add-noqa .Conflits avec d’autres outils
Section intitulée « Conflits avec d’autres outils »Si vous gardez d’autres outils (mypy, pylint en CI), assurez-vous qu’ils ne vérifient pas les mêmes règles. Désactivez dans Ruff ce que vous préférez laisser à un autre outil.
Le formatter et le linter ne sont pas d’accord
Section intitulée « Le formatter et le linter ne sont pas d’accord »Parfois, ruff check --fix produit du code que ruff format veut modifier, ce
qui crée une boucle. Lancez toujours le linter avant le formatter :
ruff check --fix .ruff format .Si le problème persiste, c’est probablement une règle de linting incompatible avec le style du formatter. Désactivez-la.
Voir les règles disponibles
Section intitulée « Voir les règles disponibles »Pour explorer toutes les règles disponibles :
ruff rule --all | lessPour avoir des détails sur une règle spécifique :
ruff rule E501À retenir
Section intitulée « À retenir »- Ruff remplace Flake8, Black, isort, Pylint et pyupgrade en un seul outil
- 100-200x plus rapide que les outils traditionnels grâce à Rust
ruff checkanalyse le code,ruff formatle formate--fixcorrige automatiquement beaucoup de problèmes- Configuration dans
pyproject.tomlavecselectetignore - Intégration VS Code avec correction à la sauvegarde
- Pre-commit et GitHub Actions pour automatiser les vérifications