
Analyser son code Python, c'est vérifier automatiquement sa lisibilité, sa complexité et sa sécurité avec des outils dédiés, plutôt qu'à l'œil nu. Ce guide présente la boîte à outils moderne : Ruff pour analyser et formater le code, Radon pour mesurer la complexité, Bandit pour repérer les failles dans le code, et pip-audit pour les dépendances vulnérables. Il montre aussi comment les automatiser avec pre-commit et en CI/CD, pour qu'ils tournent à chaque commit sans y penser.
Il s'adresse aux développeurs qui veulent un code propre, maintenable et sûr, du script personnel au projet d'équipe. La lisibilité, la performance et la sécurité sont les trois piliers d'un code de qualité, et chacun a ses outils. Toutes les commandes ont été exécutées avec Python 3.12.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »- Analyser et formater votre code avec Ruff, l'outil moderne tout-en-un.
- Mesurer la complexité d'une fonction avec Radon.
- Détecter les failles de sécurité dans le code avec Bandit.
- Scanner les dépendances vulnérables avec pip-audit.
- Automatiser ces contrôles en pre-commit et dans un pipeline CI/CD.
Respecter lisibilité, performance et sécurité : un défi
Section intitulée « Respecter lisibilité, performance et sécurité : un défi »Équilibrer la lisibilité, la performance et la sécurité d’un projet Python peut vite devenir un vrai casse-tête. Pourquoi ? Parce que ces trois besoins sont souvent en tension. Prenez un exemple simple : vous voulez optimiser un bout de code pour qu’il s’exécute plus vite. Mais en remplaçant une fonction claire par une expression plus rapide mais obscure, vous sacrifiez la lisibilité. À l’inverse, un code hyper lisible mais naïf sur le plan des performances peut ralentir l’ensemble de votre application.
Côté sécurité, les choses se compliquent encore. Souvent, on ne détecte les failles que bien trop tard, une fois le code en production. Et si vous pensez que cela ne vous concerne pas parce que votre application n’est pas publique, détrompez-vous. Même les scripts internes ou les petits projets personnels peuvent être exposés à des risques, comme l’injection de données malveillantes ou des dépendances vulnérables.
Heureusement, il existe des outils pour nous aider. À mon avis, apprendre à respecter ces trois piliers passe par leur utilisation régulière. Ces outils vous permettent de détecter vos erreurs, d’apprendre de vos faiblesses et de progresser en tant que développeur. Que ce soit pour analyser la structure de votre code, vérifier vos dépendances ou optimiser vos performances, ils jouent un rôle clé.
Assurer une lisibilité exemplaire
Section intitulée « Assurer une lisibilité exemplaire »La lisibilité est souvent sous-estimée, mais elle est essentielle pour un code maintenable. Écrire un code clair, structuré et conforme aux standards permet non seulement de faciliter votre travail, mais aussi de simplifier celui de vos collègues (ou de votre « vous » du futur !). Voici quelques outils indispensables pour améliorer cet aspect.
Black : le formateur automatique
Section intitulée « Black : le formateur automatique »Black est un outil incontournable pour formater votre code Python. Il reformate automatiquement votre code pour qu'il soit conforme aux normes de style, notamment la PEP 8. Son principal atout ? Vous n’avez pas à réfléchir aux espaces, indentations ou conventions de style : Black s’en occupe pour vous.
Exemple d’utilisation :
pip install blackblack mon_projet/reformatted /home/bob/Projets/control-img/linux_image_checker/__init__.pyreformatted /home/bob/Projets/control-img/setup.pyreformatted /home/bob/Projets/control-img/linux_image_checker/inspector.pyEn quelques secondes, votre code est propre et uniforme. Adieu les débats sans fin sur les conventions de style !
Pylint : un œil attentif sur vos erreurs
Section intitulée « Pylint : un œil attentif sur vos erreurs »Si vous cherchez un outil pour évaluer la qualité globale de votre code, Pylint est votre allié. Il identifie les erreurs potentielles, les mauvaises pratiques et vous alerte sur les violations des standards.
Exemple d’utilisation :
pip install pylintpylint setup.py************* Module setupsetup.py:1:0: C0114: Missing module docstring (missing-module-docstring)setup.py:9:21: R1732: Consider using 'with' for resource-allocating operations (consider-using-with)setup.py:9:21: W1514: Using open without explicitly specifying an encoding (unspecified-encoding)Je corrige les erreurs détectées par Pylint et je m’assure que mon code est conforme aux standards de qualité.
pylint setup.py
--------------------------------------------------------------------Your code has been rated at 10.00/10 (previous run: 0.00/10, +10.00)Pylint attribue une note à votre script et fournit des recommandations pour corriger les problèmes détectés. Pratique pour apprendre et progresser.
Ruff : l’outil rapide et polyvalent
Section intitulée « Ruff : l’outil rapide et polyvalent »Ruff est une solution moderne qui combine les fonctionnalités de plusieurs outils comme Flake8, Pylint et même Black, le tout en un temps record. Ruff est conçu pour être rapide et léger, idéal pour des projets de toutes tailles.
Exemple d’utilisation :
pipx install ruffruff check inspector.pyinspector.py:63:55: F821 Undefined name `os_root` |61 | mountpoint = self.g.inspect_get_mountpoints(self.os_info)62 | if not mountpoint:63 | logger.error(f"No mount points found for {os_root}") | ^^^^^^^ F82164 |65 | logger.info(f"Mounting {mountpoint} at /") |
inspector.py:154:5: F841 Local variable `fs_info` is assigned to but never used |152 | logger.info("Starting the Linux image inspection")153 | inspector = LinuxImageInspector(image)154 | fs_info = inspector.inspect_filesystems() | ^^^^^^^ F841155 | logger.info("Filesystem inspection completed") | = help: Remove assignment to unused variable `fs_info`
Found 2 errors.No fixes available (1 hidden fix can be enabled with the `--unsafe-fixes` option).Dans le code, deux problèmes ont été identifiés :
Variable non définie (os_root) : Une erreur se produisait car le code tentait d'utiliser une variable appelée os_root qui n'existait pas. Cette variable a été remplacée par une information déjà disponible (self.os_info), ce qui corrige l'erreur et rend le message de journalisation fonctionnel.
Variable inutilisée (fs_info) : Une autre erreur signalait que la variable fs_info était assignée mais jamais utilisée. Pour résoudre cela, nous avons supprimé l'affectation inutile et conservé uniquement l'appel de la méthode. Si des détails sur les systèmes de fichiers sont nécessaires, on pourrait les afficher dans les journaux.
ruff check inspector.pyAll checks passed!Ces corrections permettent au code de fonctionner sans erreur tout en restant clair et efficace.
Ruff ne se limite pas à l'analyse : il formate aussi. La commande ruff format réécrit la mise en forme du code à la place de Black, avec le même
résultat mais intégré au même outil :
ruff format . # met en forme, remplace Blackruff check --fix . # analyse et corrige automatiquement ce qui peut l'êtreIl couvre même une partie du travail de Bandit grâce à ses règles de
sécurité (préfixe S, issues du plugin flake8-bandit). Activées, elles
repèrent les motifs risqués directement pendant le lint :
ruff check --select S inspector.py# S307 Use of possibly insecure function; consider using `ast.literal_eval`# S602 `subprocess` call with `shell=True` identified, security issueOptimiser les performances du code
Section intitulée « Optimiser les performances du code »Un code performant n’est pas seulement un atout pour vos utilisateurs, c’est aussi un critère essentiel pour garantir l’efficacité de vos projets. En Python, il est facile de tomber dans des pièges de performance, notamment avec des boucles ou des structures de données mal adaptées. Heureusement, des outils comme Radon et Ruff vous aident à identifier ces faiblesses pour les corriger rapidement.
Radon : l’analyse de la complexité cyclomatique
Section intitulée « Radon : l’analyse de la complexité cyclomatique »La complexité cyclomatique mesure le nombre de chemins logiques qu’un morceau de code peut emprunter. Plus ce chiffre est élevé, plus le code est difficile à comprendre, à tester et, souvent, moins il est performant. Radon est un outil qui calcule cette complexité pour vous aider à identifier les fonctions ou classes nécessitant une refactorisation.
Exemple d’utilisation :
pip install radonradon cc mon_projet/ -alinux_image_checker/inspector.py M 81:4 LinuxImageInspector.check_image_params - B C 26:0 LinuxImageInspector - A M 60:4 LinuxImageInspector.list_users - A M 34:4 LinuxImageInspector.open_image - A M 52:4 LinuxImageInspector.inspect_filesystems - A F 152:0 main - A M 27:4 LinuxImageInspector.__init__ - A
7 blocks (classes, functions, methods) analyzed.Explications des résultats :
-
Type d’élément : Les lettres
M,C, ouFindiquent le type de bloc analysé :M: Méthode (dans une classe).C: Classe.F: Fonction (hors classe).
-
Position : Les chiffres indiquent la ligne de début du bloc analysé (par exemple,
81:4signifie que le bloc commence à la ligne 81, avec un niveau d’indentation de 4). -
Nom de l’élément : Le nom de la classe, de la méthode ou de la fonction analysée.
-
Complexité cyclomatique : La lettre (de
AàF) indique la complexité cyclomatique.A: Très simple (idéal).B: Modérément complexe (peut nécessiter une attention).Cou plus : Complexe (devrait être simplifié).
Dans cet exemple, la méthode check_image_params est modérément complexe et
pourrait être simplifiée. Les autres blocs sont bien conçus et ne nécessitent
pas de modification.
En examinant check_image_params pour réduire sa complexité, on remarque
que la méthode enchaîne plusieurs vérifications similaires. Les découper en
sous-fonctions rend le code plus lisible et plus facile à maintenir.
Quelques astuces pour optimiser votre code Python
Section intitulée « Quelques astuces pour optimiser votre code Python »En plus des outils, voici des pratiques simples qui peuvent booster les performances de vos projets Python :
-
Préférez les compréhensions de liste aux boucles
forclassiques quand c’est possible :# Moins performantresult = []for i in range(10):result.append(i * 2)# Plus performantresult = [i * 2 for i in range(10)] -
Utilisez les structures de données adaptées. Par exemple, pour des recherches rapides, utilisez un dictionnaire plutôt qu’une liste.
-
Évitez les opérations inutiles dans les boucles ou les fonctions critiques.
Optimiser les performances demande un peu de pratique, mais les résultats sont gratifiants. Vos scripts seront non seulement plus rapides, mais aussi plus agréables à maintenir et à développer. Avec des outils comme Radon et Ruff pour vous guider, repérer et corriger les points faibles devient un jeu d’enfant.
Les outils pour vérifier la sécurité du code Python
Section intitulée « Les outils pour vérifier la sécurité du code Python »La sécurité est une priorité pour tous les projets, qu'il s'agisse de scripts simples ou d'applications complexes. Des failles peuvent facilement se glisser dans votre code, que ce soit par négligence, manque de vigilance ou ignorance des meilleures pratiques. Heureusement, plusieurs outils permettent de vérifier et de renforcer la sécurité de votre code.
Bandit : détecter les vulnérabilités dans le code source
Section intitulée « Bandit : détecter les vulnérabilités dans le code source »Bandit est un outil conçu pour analyser le code Python et identifier des problèmes de sécurité courants. Il examine chaque fichier source pour détecter des failles potentielles telles que :
- Utilisation de fonctions non sécurisées comme
eval(). - Mots de passe ou secrets exposés dans le code.
- Vulnérabilités liées aux fichiers ou aux permissions.
Exemple d’utilisation :
pip install bandit[main] INFO profile include tests: None[main] INFO profile exclude tests: None[main] INFO cli include tests: None[main] INFO cli exclude tests: None[main] INFO running on Python 3.12.3Run started:2024-12-11 06:39:35.688743
Test results: No issues identified.
Code scanned: Total lines of code: 137 Total lines skipped (#nosec): 0
Run metrics: Total issues (by severity): Undefined: 0 Low: 0 Medium: 0 High: 0 Total issues (by confidence): Undefined: 0 Low: 0 Medium: 0 High: 0Files skipped (0):Bandit génère un rapport qui détaille :
- La ligne problématique.
- Le niveau de gravité (faible, moyen, élevé).
- Une recommandation pour corriger le problème.
Safety : sécuriser vos dépendances
Section intitulée « Safety : sécuriser vos dépendances »Vos dépendances Python peuvent représenter un risque important si elles contiennent des failles connues. Safety est un outil qui vérifie les versions des bibliothèques utilisées dans votre projet et les compare à une base de données de vulnérabilités.
Étapes pour l’utiliser :
-
Générez un fichier
requirements.txtsi ce n’est pas déjà fait :Fenêtre de terminal pip freeze > requirements.txt.test -
Lancez Safety pour analyser vos dépendances :
Fenêtre de terminal pip install safetysafety scan -r requirements.txt.testSafety 3.2.12 scanning /home/bob/Projets/control-img2024-12-11 06:43:52 UTCAccount: Stéphane ROBERT, xxxxxxxxxxxxxxxxxxxxxxxEnvironment: Stage.developmentScan policy: None, using Safety CLI default policiesPython detected. Found 1 Python requirement file and 1 Python environment✅ requirements.txt: No issues found.✅ .direnv/python-3.12/pyvenv.cfg: No issues found.Tested 57 dependencies for security issues using default Safety CLI policies9 vulnerabilities found, 9 ignored due to policy.0 fixes suggested, resolving 0 vulnerabilities.
Safety liste les bibliothèques vulnérables et propose les versions à jour. Cela vous aide à protéger votre application des attaques exploitant des failles connues. À noter : depuis ses versions récentes, Safety demande un compte pour ses fonctionnalités complètes, ce qui peut gêner en intégration continue.
pip-audit : l'alternative sans compte
Section intitulée « pip-audit : l'alternative sans compte »pip-audit, maintenu par la PyPA (l'organisation derrière pip et PyPI), remplit le même rôle que Safety mais sans compte ni inscription, ce qui le rend idéal en CI/CD. Il compare vos dépendances à la base de vulnérabilités PyPI Advisory et à l'OSV.
pip install pip-auditpip-audit -r requirements.txtSur une dépendance vulnérable, il liste chaque CVE et la version corrective :
Name Version ID Fix Versionsurllib3 1.24.3 CVE-2024-37891 1.26.19, 2.2.2urllib3 1.24.3 CVE-2025-50181 2.5.0Pour un projet où l'on veut un scan de dépendances sans friction, pip-audit est souvent le choix par défaut. Safety reste pertinent pour ses politiques avancées et son suivi centralisé.
Gestion des secrets dans le code
Section intitulée « Gestion des secrets dans le code »L'exposition accidentelle de secrets (clés API, mots de passe, etc.) dans le code source est une faille fréquente et critique. Des outils comme TruffleHog et Gitleaks sont spécialement conçus pour détecter ces informations sensibles dans vos dépôts.
Pour en savoir plus sur leur configuration et leur utilisation, je vous invite à consulter les guides dédiés :
Ces outils sont essentiels pour prévenir l’exposition de données sensibles et garantir un code sûr.
pre-commit et pipelines CI/CD
Section intitulée « pre-commit et pipelines CI/CD »Pour garantir un code Python lisible, performant et sécurisé, il est essentiel d’automatiser l’utilisation des outils d’analyse. Une intégration bien pensée, à la fois en pre-commit et dans les pipelines CI/CD, permet de détecter et corriger les problèmes dès les premières étapes du développement. Le guide dédié pre-commit détaille le fonctionnement du framework ; voici comment l'appliquer à un projet Python.
Configurer des hooks pre-commit
Section intitulée « Configurer des hooks pre-commit »Les hooks pre-commit sont une excellente manière d’appliquer des vérifications avant même que le code ne soit poussé dans un dépôt Git. Ils permettent de gagner du temps en interceptant les erreurs ou failles dès le stade local.
Installez l’outil pre-commit dans votre environnement :
pip install pre-commitAjoutez un fichier de configuration .pre-commit-config.yaml à la racine de
votre projet pour définir les outils que vous souhaitez exécuter.
Par exemple :
repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: v5.0.0 hooks: - id: trailing-whitespace exclude: ^(env|\.venv|\.direnv|site-packages|node_modules)/ - id: end-of-file-fixer exclude: ^(env|\.venv|\.direnv|site-packages|node_modules)/ - repo: https://github.com/astral-sh/ruff-pre-commit rev: v0.15.20 hooks: - id: ruff # analyse - id: ruff-format # mise en forme - repo: https://github.com/PyCQA/bandit rev: 1.9.4 hooks: - id: bandit - repo: https://github.com/gitleaks/gitleaks rev: v8.17.0 hooks: - id: gitleaks args: ["detect", "-v"]Activez les hooks avec la commande suivante :
pre-commit installpre-commit installed at .git/hooks/pre-commitpre-commit autoupdateChaque fois que vous faites un commit, ces outils s’exécutent automatiquement. Si un problème est détecté, le commit sera bloqué jusqu’à ce que le code soit corrigé.
git commit -m "Ajout de la fonction de vérification des images"
trim trailing whitespace.................................................Passedfix end of files.........................................................Passedruff.....................................................................Passedbandit...................................................................PassedDetect hardcoded secrets.................................................Passed[master (root-commit) d3100d6] test 12 files changed, 641 insertions(+) create mode 100644 .gitignore create mode 100644 .pre-commit-config.yaml create mode 100644 LICENSE create mode 100644 README.md create mode 100644 config.yaml create mode 100644 linux_image_checker/__init__.py create mode 100644 linux_image_checker/inspector.py create mode 100644 logging_config.yaml create mode 100644 requirements.txt create mode 100644 requirements.txt.cc create mode 100644 requirements.txt.test create mode 100644 setup.pyIntégration dans un pipeline CI/CD
Section intitulée « Intégration dans un pipeline CI/CD »Automatiser ces outils dans un pipeline CI/CD garantit que les contrôles sont appliqués à chaque modification, indépendamment de l’environnement local des développeurs.
Voici comment intégrer Bandit, Ruff et Safety dans un fichier
.gitlab-ci.yml :
stages: - lint - security
lint: stage: lint image: python:3.12-slim script: - pip install ruff - ruff check . - ruff format --check . only: - merge_requests
security: stage: security image: python:3.12-slim script: - pip install bandit pip-audit - bandit -r . - pip-audit -r requirements.txt only: - merge_requestsEn combinant des hooks pre-commit et des vérifications dans vos pipelines CI/CD, vous établissez une première ligne de défense solide pour votre code Python. Cela permet non seulement de maintenir un code de haute qualité, mais aussi d’automatiser des tâches répétitives et d’éviter les erreurs coûteuses plus tard dans le cycle de développement. Ce processus est un investissement précieux pour des projets stables, performants et sécurisés.
À retenir
Section intitulée « À retenir »- Ruff est la base moderne : il analyse (
ruff check) et formate (ruff format) en un seul outil très rapide, remplaçant Flake8, isort et Black. - Ses règles
S(--select S) couvrent une partie de la sécurité du code, en complément de Bandit pour un audit approfondi. - Radon mesure la complexité cyclomatique et repère les fonctions à simplifier.
- Bandit analyse le code (eval,
shell=True, secrets) ; pip-audit scanne les dépendances vulnérables. - pip-audit (PyPA) fonctionne sans compte, ce qui le rend idéal en CI ; Safety demande désormais une inscription.
- On automatise tout avec pre-commit en local et un pipeline CI/CD, pour un contrôle à chaque commit.
FAQ : analyser son code Python
Section intitulée « FAQ : analyser son code Python »- Lisibilité et erreurs : un linter comme Ruff (qui formate aussi).
- Complexité : Radon (complexité cyclomatique).
- Sécurité du code : Bandit (ou les règles
Sde Ruff). - Dépendances vulnérables : pip-audit.
- Un linter analyse le code et signale erreurs, variables inutilisées, écarts à la PEP 8. Il ne réécrit pas forcément.
- Un formateur réécrit la mise en forme (espaces, indentation, sauts de ligne) pour la rendre uniforme, sans changer le comportement.
ruff check . # analyse (linter)
ruff format . # met en forme (formateur, à la place de Black)
- Flake8, isort, Black : Ruff les remplace, il analyse et formate en un seul outil, bien plus rapide.
- Bandit : Ruff en couvre une partie via ses règles de sécurité
S(flake8-bandit) :
ruff check --select S . # détecte eval, shell=True, etc.
Pour un audit de sécurité approfondi, Bandit reste plus complet. Mais pour la première ligne, activer les règles S de Ruff suffit souvent. Voir le guide Ruff.pip install bandit
bandit -r mon_projet/
Il détecte par exemple :eval()(B307) etsubprocess(..., shell=True)(B602),- des secrets en dur,
- une désérialisation non sûre.
S de Ruff en local et par un scan des dépendances avec pip-audit.- pip-audit (maintenu par la PyPA) fonctionne sans compte ni inscription :
pip install pip-audit
pip-audit -r requirements.txt
- Safety est complet mais nécessite désormais un compte pour ses fonctions récentes.
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.15.20
hooks:
- id: ruff
- id: ruff-format
pre-commit install
À chaque commit, les hooks s'exécutent et bloquent le commit en cas de problème. On rejoue les mêmes contrôles en CI/CD pour couvrir toute l'équipe. Détails dans le guide pre-commit.Prochaines étapes
Section intitulée « Prochaines étapes »L'analyse de code va de pair avec un bon outillage de projet et une automatisation en amont.