Skip to main content

In this article

10 dimensions de l’analyse statique en Python

Écrit par
feature python linting

17 juillet 2024

0 minutes de lecture

L’analyse statique du code Python, également appelée « linting », est un aspect essentiel du développement logiciel. Elle consiste à examiner votre code Python sans l’exécuter afin de repérer d’éventuels bugs, erreurs de programmation, problèmes de style ou écarts par rapport aux normes de codage prédéfinies. Elle permet aussi d’identifier les vulnérabilités dès les premières étapes du développement et de réduire ainsi le risque de déployer du code non sécurisé en production. Elle peut, par exemple, repérer des pratiques de codage non sécurisées, comme l’utilisation d’identifiants codés en dur, des erreurs courantes susceptibles de provoquer des attaques par injection SQL ou des problèmes potentiels de nettoyage des données.

Python propose plusieurs bibliothèques et outils d’analyse statique, comme Pylint, Pyflakes et Flake8. Pylint peut, par exemple, vous aider à appliquer des normes de codage, à détecter des erreurs et à examiner la complexité du code. Voici un court extrait de code qui montre comment utiliser Pylint :

# test.py

def add(x, y):
    return x + y

add(1, '2')

L’exécution de Pylint sur ce code produirait le résultat suivant :

$ pylint test.py
************* Module test
test.py:5:4: E1136: Value '2' is unsubscriptable (unsubscriptable-object)

--------------------------------------------------
Your code has been rated at -10.00/10

Pylint a détecté une erreur lorsque nous avons tenté d’additionner un entier et une chaîne de caractères, une opération invalide en Python.

1. Vérification des types dans l’analyse statique Python

Python est un langage polyvalent et dynamique, et sa flexibilité explique en partie sa popularité auprès des développeurs. Cependant, ce dynamisme peut parfois entraîner des bugs difficiles à détecter, notamment des erreurs de type. C’est là que l’analyse statique Python entre en jeu.

Avant d’aborder la vérification des types, voyons ce que signifie le typage dynamique en Python. Python est à typage dynamique : le type d’une variable est vérifié à l’exécution et il n’est pas nécessaire de le préciser explicitement. L’extrait de code ci-dessous l’illustre :

# x is an integer
x = 5
# x is now a string
x = "Hello, World!"

Si le typage dynamique peut rendre Python plus facile à utiliser et à lire, il peut aussi entraîner des erreurs de type qui ne sont détectées qu’à l’exécution du code.

Le rôle de la vérification statique des types

La vérification statique des types consiste à détecter les erreurs de type tôt dans le processus de développement, c’est-à-dire pendant le codage ou la compilation, plutôt qu’à l’exécution. Elle peut empêcher d’éventuels bugs d’atteindre le code de production et ainsi renforcer la sécurité et la fiabilité du code. Java et C++ sont des exemples de langages de programmation à typage statique.

Bien que Python soit un langage à typage dynamique, il prend également en charge le typage statique facultatif grâce aux annotations de type. Cette fonctionnalité vous permet d’indiquer les types attendus des variables, des paramètres de fonction et des valeurs de retour. L’environnement d’exécution Python n’impose pas ces types, mais les outils d’analyse statique peuvent s’en servir pour détecter d’éventuelles erreurs de type.

def greet(name: str) -> str:
    return 'Hello, ' + name

Dans cet exemple, name doit être une chaîne de caractères, et la fonction doit également renvoyer une chaîne de caractères.

Outils de vérification statique des types en Python

Plusieurs outils peuvent vous aider à vérifier les types statiquement en Python. Mypy, Pyright et Pyre se distinguent par leur robustesse et leur large adoption au sein de la communauté Python.

  • Mypy : vérificateur de types statique facultatif pour Python, qui vise à combiner les avantages du typage dynamique et du typage statique. Polyvalent, il peut être intégré à un pipeline CI/CD afin de détecter les erreurs de type avant qu’elles n’atteignent la production.

  • Pyright : développé par Microsoft, Pyright est un vérificateur statique des types axé sur les performances. Il est écrit en TypeScript et s’exécute sur Node.js.

  • Pyre : Pyre est un vérificateur de types performant pour Python, développé par Facebook. Il est conçu pour améliorer la qualité du code et accélérer le développement en signalant les erreurs de type de façon interactive dans votre terminal ou votre éditeur préféré.

Exemple de code : vérifier les types avec Mypy

Pour installer Mypy, il suffit d’exécuter pip install mypy. Une fois installé, vous pouvez l’utiliser pour rechercher des erreurs de type dans vos fichiers Python. Voici un exemple simple :

# file: hello.py
def greet(name: str) -> str:
    return 'Hello, ' + name

# This will cause a type error
greet(123)

Pour vérifier ce fichier avec Mypy, procédez comme suit :

$ mypy hello.py
hello.py:5: error: Argument 1 to "greet" has incompatible type "int"; expected "str"
Found 1 error in 1 file (checked 1 source file)

Comme vous pouvez le constater, Mypy a détecté l’erreur de type avant l’exécution du code.

2. Les linters dans l’analyse statique Python

Les linters sont des outils d’analyse statique du code qui signalent les erreurs de programmation, les bugs, les erreurs de style et les constructions suspectes. Dans l’écosystème Python, ils jouent un rôle essentiel pour maintenir la qualité et la sécurité de votre code. Ils contribuent à appliquer les normes de codage, à détecter tôt les bugs potentiels et les vulnérabilités de sécurité, ainsi qu’à améliorer la lisibilité et la facilité de maintenance de votre code Python.

Dans l’écosystème Python, Pylint, Flake8 et Pyflakes comptent parmi les linters les plus utilisés.

  • Pylint : outil open source hautement configurable, Pylint recherche les erreurs dans le code Python, applique une norme de codage et repère les signes de mauvaise qualité du code. Il peut également servir à créer des plugins personnalisés pour des cas d’utilisation spécifiques.

  • Flake8 : Flake8 est une bibliothèque Python qui regroupe PyFlakes, pycodestyle et le script McCabe de Ned Batchelder. Cette boîte à outils très pratique vérifie la conformité de votre projet à PEP 8, le guide de style de Python.

  • Pyflakes : Pyflakes recherche rapidement les erreurs dans les fichiers source Python, sans les exécuter. Plus rapide que Pylint et Flake8, il n’impose pas de guide de style et constitue donc une bonne solution pour effectuer une vérification rapide et élémentaire de votre code Python.

Les signes de mauvaise qualité du code et l’application des normes de codage

Les signes de mauvaise qualité du code révèlent des problèmes plus profonds. Ce sont des schémas qui indiquent des violations de principes fondamentaux de conception et nuisent à la qualité de celle-ci. Parmi les exemples courants en Python, citons les classes volumineuses, les méthodes trop longues, le code dupliqué et le code mort.

Les linters comme Pylint, Flake8 et Pyflakes aident à détecter ces signes de mauvaise qualité et à appliquer les normes de codage dans votre code Python afin d’en améliorer la qualité et de la maintenir à un niveau acceptable. Pour cela, ils vérifient votre code par rapport à des règles et recommandations prédéfinies, souvent fondées sur des bonnes pratiques adoptées par la communauté, comme PEP 8 pour Python.

Exemple de code : un linter en action

Voici comment utiliser Pylint pour effectuer une analyse statique d’un fichier Python nommé example.py :

# example.py
def add(a, b):
    return a+b

Pour exécuter Pylint sur ce fichier, utilisez la commande suivante :

pylint example.py

Si votre code présente des problèmes, Pylint les signalera et fournira un rapport détaillé. Il peut, par exemple, indiquer que la fonction add ne comporte pas de docstring, ce qui ne respecte pas les recommandations de PEP 8 pour écrire du code Python de qualité.

Règles personnalisées dans les linters

Les linters comme Pylint vous permettent de définir des règles personnalisées pour vos projets Python. Cette fonctionnalité est particulièrement utile lorsque votre projet ou votre organisation suit des normes ou des recommandations de codage spécifiques.

Pour créer une règle personnalisée dans Pylint, il faut créer une classe Python qui hérite de l’une des classes de vérification de Pylint, puis définir des méthodes qui effectuent la vérification du code. Une fois vos règles personnalisées définies, vous pouvez les ajouter au vérificateur Pylint à l’aide de la méthode register_checker.

Voici un exemple simple de règle Pylint personnalisée qui vérifie l’utilisation de l’instruction print :

from pylint.checkers import BaseChecker
from pylint.interfaces import IAstroidChecker

class NoPrintStatementsChecker(BaseChecker):
    __implements__ = IAstroidChecker
    name = 'no-print-statements'
    msgs = {
        'W0001': (
            'Print statement used',
            'no-print-statements',
            'Print statements should not be used',
        ),
    }

    def visit_print(self, node):
        self.add_message('no-print-statements', node=node)

def register(linter):
    linter.register_checker(NoPrintStatementsChecker(linter))

Dans cet exemple, la classe NoPrintStatementsChecker vérifie l’utilisation de l’instruction print et émet un avertissement si elle en trouve une. La fonction register sert ensuite à enregistrer ce vérificateur personnalisé auprès de Pylint.

3. Détection des vulnérabilités de sécurité

La détection des vulnérabilités de sécurité est une dimension essentielle de l’analyse statique Python. Examinons l’importance de la sécurité dans l’analyse statique Python, les risques de sécurité courants dans le code Python et quelques outils de détection des vulnérabilités, comme Bandit et Snyk Code.

Lorsque vous écrivez du code Python, la sécurité ne doit pas être une réflexion après coup, mais faire partie intégrante du processus de développement. L’analyse statique Python joue un rôle essentiel pour garantir la sécurité du code : elle peut aider à repérer les vulnérabilités potentielles dès les premières étapes du cycle de développement, avant même l’exécution du code. Les vulnérabilités comme les attaques par injection, les références directes non sécurisées à des objets, les erreurs de configuration de sécurité et les scripts intersites sont fréquentes dans le code Python.

Voici, par exemple, à quoi pourrait ressembler une vulnérabilité d’injection SQL dans du code Python :

def get_user_details(user_id):
    return database.execute(f'SELECT * FROM users WHERE id = {user_id}')

Dans l’exemple ci-dessus, user_id est directement utilisé dans une requête SQL, ce qui expose à une possible injection SQL si user_id n’est pas correctement nettoyé et est fourni par l’utilisateur.

Outils de détection des vulnérabilités de sécurité

Bandit

Bandit est un outil conçu pour repérer les problèmes de sécurité courants dans le code Python. Il traite chaque fichier, crée un AST (arbre syntaxique abstrait) à partir du code Python, puis exécute les plugins appropriés sur les nœuds de cet arbre.

Voici comment utiliser Bandit pour analyser votre code Python à la recherche de vulnérabilités de sécurité :

$ bandit -r path/to/your/python/code

Bandit détecterait-il une référence directe non sécurisée à un objet en Python ? Vous n’en êtes pas sûr ? Découvrez la suite avec Snyk.

Snyk Code

Snyk Code est un autre outil doté d’un moteur d’analyse symbolique rapide basé sur l’IA. Avec Snyk Code, vous pouvez rapidement trouver des vulnérabilités de sécurité dans votre code Python. Son moteur d’analyse statique est conçu pour comprendre le contexte et le flux de votre code, ce qui lui permet de détecter des vulnérabilités complexes que d’autres outils pourraient manquer.

Snyk Code est également proposé avec un plugin pour l’IDE PyCharm, qui permet aux développeurs de détecter et de corriger les problèmes de sécurité en temps réel pendant qu’ils codent.

Pour commencer à utiliser Snyk Code, il vous suffit de télécharger le plugin Snyk pour l’IDE PyCharm. Vous pourrez ensuite l’utiliser gratuitement.

Intégrer la détection des vulnérabilités de sécurité à votre analyse statique Python est essentiel pour garantir la sécurité de vos logiciels. Des outils comme Bandit et Snyk Code offrent aux développeurs un moyen simple et efficace de détecter et de corriger les vulnérabilités dans leur code Python.

4. Analyse de la complexité du code

La complexité du code est une mesure qui permet d’évaluer la difficulté à comprendre ou à modifier votre code. Une complexité élevée rend souvent le code plus difficile à appréhender, ce qui nuit à sa facilité de maintenance.

La maintenance du code fait partie du travail quotidien des développeurs. Mais lorsque la base de code se complexifie, il devient de plus en plus difficile de la comprendre et de la modifier. Cette difficulté peut entraîner des bugs et réduire la qualité globale du logiciel. L’analyse de la complexité du code est donc essentielle au développement logiciel pour garantir un code de qualité, facile à maintenir.

Mesurer la complexité cyclomatique avec Radon

Plusieurs outils permettent de mesurer la complexité du code Python, notamment Radon. Cet outil Python calcule différentes métriques à partir des informations extraites de l’arbre syntaxique abstrait (AST). La complexité cyclomatique en fait partie.

La complexité cyclomatique est une métrique logicielle qui indique la complexité d’un programme. Elle mesure quantitativement le nombre de chemins linéairement indépendants dans le code source d’un programme. Radon analyse votre code Python et lui attribue une note de A à F : A signifie que le code est simple et facile à comprendre, tandis que F indique qu’il est trop complexe.

Pour utiliser Radon, vous devez d’abord l’installer. Vous pouvez le faire avec pip :

pip install radon

Exemple de code illustrant l’analyse de la complexité du code

Une fois Radon installé, vous pouvez l’utiliser pour analyser votre code Python. Prenons le code Python suivant :

def calculate_sum(n):
    if n < 0:
        return "Negative number"
    else:
        return sum(range(n+1))

Pour mesurer la complexité du code ci-dessus, exécutez la commande suivante :

radon cc your_file.py

Cette commande renvoie la complexité cyclomatique du code. Dans l’exemple ci-dessus, elle est de 2, ce qui signifie que le code n’est pas très complexe.

Examinons maintenant une fonction plus complexe, par exemple :

def complex_function(a, b, c):
    if a > b:
        if a > c:
            return a
        else:
            return c
    else:
        if b > c:
            return b
        else:
            return c

L’exécution de Radon sur ce code renverrait une complexité de 5, signe d’un niveau de complexité plus élevé.

L’utilisation d’outils de mesure de la complexité cyclomatique contribue à préserver la qualité du code et à le rendre plus facile à comprendre et à modifier. Des outils comme Radon offrent un moyen simple de mesurer la complexité du code Python, pour le rendre plus facile à maintenir et moins sujet aux bugs.

5. Analyse des dépendances

Dans le monde des logiciels open source, pilier du développement logiciel, l’analyse des dépendances est un aspect important que les développeurs ne peuvent pas se permettre de négliger. Cette procédure est essentielle lorsqu’on travaille sur de grandes bases de code dans des langages comme Python. L’analyse des dépendances consiste à identifier les dépendances entre les différents éléments d’un projet logiciel. Découvrons pourquoi il est important de comprendre et de gérer les dépendances, les outils d’analyse comme Snyk et Snyk Advisor, ainsi qu’un exemple pratique illustrant l’analyse des dépendances.

Pourquoi comprendre et gérer les dépendances est important

Dans les projets Python, les dépendances sont les packages ou bibliothèques externes utilisés par votre projet. Il peut s’agir de frameworks web comme Django ou Flask, ou de bibliothèques de data science comme NumPy ou pandas.

Comprendre et gérer les dépendances est essentiel pour plusieurs raisons :

  • Cela contribue à préserver la stabilité et la fiabilité de vos logiciels. Si une dépendance dont votre projet a besoin contient un bug ou cesse de fonctionner, votre logiciel risque lui aussi de ne plus fonctionner.

  • Cela contribue à renforcer la sécurité de votre projet. Les dépendances peuvent présenter des vulnérabilités susceptibles d’affecter votre projet si elles ne sont pas corrigées.

  • Cela permet de respecter les exigences en matière de licences. Chaque dépendance peut avoir sa propre licence, et vous devez veiller à les respecter toutes.

Snyk Advisor pour l’analyse des dépendances

Snyk Advisor est un outil qui fournit des informations sur les dépendances de votre projet Python, notamment sur les vulnérabilités de sécurité, les problèmes de licence et les packages obsolètes. Il vous aide à comprendre les risques liés à vos dépendances et vous indique les mesures à prendre pour les atténuer.

Score de santé du package Python requests de PyPI affiché sur Snyk Advisor


Vous pouvez utiliser la CLI Snyk pour analyser les dépendances de votre projet Python et vous signaler les packages open source vulnérables installés depuis PyPI ou le code non sécurisé de votre programme Python. Après avoir installé la CLI Snyk, vous pouvez exécuter la commande suivante pour analyser votre projet :

snyk test --all-projects

Cette commande analysera les dépendances de votre projet et générera un rapport sur les éventuelles vulnérabilités de sécurité, les problèmes de licence ou les packages obsolètes. Par exemple, lors de l’analyse d’un projet Python FastAPI, elle peut vous signaler des vulnérabilités :

Testing FastAPI...
✗ High severity vulnerability found in requests
  Description: Out-of-bounds Read
  Info: https://snyk.io/vuln/SNYK-PYTHON-REQUESTS-174006
  Introduced through: requests@2.25.1
  From: requests@2.25.1 > urllib3@1.26.3 > requests
  Fix: https://snyk.io/vuln/SNYK-PYTHON-REQUESTS-174006

Organization:      snyk
Package manager:   pip
Target file:       requirements.txt

Commencez avec Snyk pour sécuriser Python afin de protéger votre première ligne de code, jusqu’à votre dernière dépendance pip et vos applications Python conteneurisées déployées.

Analysez votre code Python en temps réel et recevez des suggestions de correction contextuelles basées sur l’IA, directement dans vos IDE préférés, notamment Visual Studio Code et PyCharm.

Analyser les dépendances avec pipenv graph

Prenons une simple application Python Flask pour illustrer l’analyse des dépendances. Voici le fichier app.py :

from flask import Flask
app = Flask(__name__)

@app.route('/')
def hello_world():
    return 'Hello, World!'

Nous utiliserons Pipenv dans cet exemple. Commencez par l’initialiser et installer Flask :

pipenv install flask

L’exécution de pipenv graph affichera alors :

flask==1.1.2
  - click [required: >=5.1, installed: 7.1.2]
  - itsdangerous [required: >=0.24, installed: 1.1.0]
  - Jinja2 [required: >=2.10.1, installed: 2.11.2]
    - MarkupSafe [required: >=0.23, installed: 1.1.1]
  - Werkzeug [required: >=0.15, installed: 1.0.1]

Cette sortie montre que Flask, la dépendance directe de notre projet, dépend de click, itsdangerous, Jinja2 et Werkzeug. Jinja2 dépend à son tour de MarkupSafe. Nous avons donc analysé avec succès les dépendances de notre projet.

Si vous découvrez pipenv et souhaitez en savoir plus, je vous recommande de lire Maîtriser les environnements virtuels Python : guide complet de venv, Docker et de la sécurisation de votre code pour vous familiariser avec le concept d’environnements virtuels en Python.

En conclusion, l’analyse régulière des dépendances dans les projets Python est nécessaire pour préserver la fiabilité du code, renforcer la sécurité et garantir le respect des licences. Des outils comme Snyk, Snyk Advisor et Pipenv facilitent cette tâche et donnent une vue claire de l’arborescence des dépendances.

6. Outils de formatage du code

Respecter un style et un format de code cohérents contribue également à sa lisibilité et à son efficacité. Les outils de formatage jouent un rôle essentiel à cet égard. Ils aident les développeurs à formater automatiquement leur base de code selon un ensemble de règles prédéfinies. Cela améliore non seulement la qualité globale du code, mais réduit aussi le temps et les efforts consacrés aux revues manuelles. Découvrons des formateurs de code populaires comme Black et YAPF.

Prenons un exemple pour comprendre la différence qu’un formateur de code peut apporter. Voici un extrait de code Python avant et après son formatage avec Black.

Avant le formatage :

def function(arg1,arg2,arg3=4,arg4=8,arg5=16):
    return arg1+arg2+arg3+arg4+arg5
print(function(1,2))

Après le formatage avec Black :

def function(arg1, arg2, arg3=4, arg4=8, arg5=16):
    return arg1 + arg2 + arg3 + arg4 + arg5

print(function(1, 2))

Le formateur de code Python YAPF

YAPF (Yet Another Python Formatter) est un autre formateur de code Python qui va au-delà de PEP8 pour offrir un style de code plus uniforme. Contrairement à PEP8, YAPF tient compte de l’apparence du code et le rend plus lisible.

Voici un exemple d’utilisation de YAPF :

# install yapf
pip install yapf

# use yapf to format a python file
yapf -i your_python_file.py

7. Arbres de syntaxe abstraite (AST) en Python

Qu’est-ce qu’un arbre de syntaxe abstraite (AST) ? Un arbre de syntaxe abstraite est une représentation arborescente de la structure syntaxique du code source écrit dans un langage de programmation. Chaque nœud de l’arbre correspond à une construction du code source. La syntaxe est dite « abstraite » parce qu’elle ne représente pas tous les détails de la syntaxe réelle.

En Python, lorsque l’interpréteur exécute du code, il le convertit d’abord en une forme intermédiaire appelée bytecode. Ce processus de conversion implique la création d’un AST. En Python, un AST est une représentation simplifiée de la structure du code. Il élimine les détails comme le formatage et les espaces, et se concentre uniquement sur les instructions et leur ordre, offrant ainsi une vue structurelle du code.

Le module ast de Python et ses fonctionnalités

La bibliothèque standard de Python comprend le module ast, qui permet de créer, de manipuler et d’inspecter des AST. Ce module fournit un ensemble de classes, de fonctions et de méthodes auxiliaires pour travailler par programmation avec les AST Python.

La fonction ast.parse() est un point d’entrée courant pour créer des AST. Elle analyse le code source Python et le convertit en nœud AST, qui peut ensuite être manipulé ou inspecté.

Le module ast fournit également une classe NodeVisitor qui parcourt l’AST et appelle une fonction de visite pour chaque nœud trouvé. Cette classe peut être utilisée telle quelle ou étendue pour remplacer des méthodes et ajouter des fonctionnalités propres à certains types de nœuds.

Inspection et manipulation d’AST : exemple pratique

Examinons un exemple simple d’utilisation du module ast pour inspecter et manipuler un AST en Python.

import ast

# Parse some code into an AST
root = ast.parse("print('Hello, World!')")

# Print all the nodes in the AST
for node in ast.walk(root):
    print(type(node))

# Modify the AST to print a different message
for node in ast.walk(root):
    if isinstance(node, ast.Str):  # Change the string literal in the Print node
        node.s = 'Hello, AST!'

# Convert the modified AST back into code
code = compile(root, filename="<ast>", mode="exec")

# Execute the modified code
exec(code)

Dans cet exemple, nous commençons par convertir une simple instruction Python print en AST à l’aide de ast.parse(). Nous inspectons ensuite l’AST en parcourant tous les nœuds et en affichant leurs types. Puis, nous modifions l’AST en changeant la chaîne de caractères dans le nœud Print. Enfin, nous reconvertissons l’AST modifié en code à l’aide de compile() et l’exécutons avec exec(). Ce code affichera « Hello, AST! » et non « Hello, World! ».

Cet exemple illustre les fonctionnalités d’inspection et de modification du module ast en Python. Les applications potentielles des AST dans les domaines de la sécurité du code et du développement logiciel sont nombreuses, du refactoring automatisé du code à l’analyse statique avancée pour détecter les vulnérabilités de sécurité.

8. Analyse du flux de contrôle et du flux de données

L’analyse du flux de contrôle et du flux de données est essentielle. Cette technique facilite la détection des erreurs, améliore la lisibilité du code et renforce la qualité globale des applications Python.

L’analyse du flux de contrôle consiste à évaluer l’ordre d’exécution des instructions dans un programme, tandis que l’analyse du flux de données suit et analyse l’évolution des valeurs des données au fil du programme. Voici pourquoi ces analyses sont importantes :

  1. Détection des erreurs potentielles : l’analyse du flux de contrôle et du flux de données peut aider à repérer des bugs et des vulnérabilités potentiels dans le code, comme des boucles infinies, du code inaccessible ou des variables inutilisées.

  2. Optimisation du code : en comprenant comment les données circulent dans votre code et comment s’enchaînent les instructions, vous pouvez repérer les inefficacités et apporter les améliorations nécessaires.

  3. Amélioration de la lisibilité du code : l’analyse du flux de contrôle et du flux de données peut rendre le code plus compréhensible en mettant en évidence les dépendances et les interactions entre ses différentes parties.

  4. Garantie de sécurité : comprendre les flux de données et de contrôle de votre application est essentiel pour en assurer la sécurité. Cela peut aider à repérer des vulnérabilités potentielles, comme les fuites de données ou les attaques par injection.

Exemple de code illustrant l’analyse du flux de contrôle et du flux de données

Pour illustrer le concept d’analyse du flux de contrôle et du flux de données en Python, prenons une fonction Python simple :

def calculate_total(price, quantity):
    if quantity <= 0:
        return "Invalid quantity"
    else:
        total = price * quantity
        return total

Dans cette fonction, le flux de contrôle est déterminé par l’instruction if-else. Si la quantity est inférieure ou égale à 0, la fonction renvoie un message d’erreur. Sinon, elle calcule et renvoie le prix total.

Le flux de données, quant à lui, peut être suivi depuis les paramètres d’entrée (price et quantity) jusqu’au résultat final (total). Les valeurs de ces variables changent au fil de leur passage dans la fonction.

Un outil d’analyse statique analyserait les flux de contrôle et de données de cette fonction pour détecter d’éventuels problèmes. Par exemple, il pourrait signaler un problème si price ou quantity était utilisé avant d’être défini, ou s’il existait un chemin possible dans la fonction où total n’était pas défini avant d’être renvoyé.

Grâce à l’analyse du flux de contrôle et du flux de données, vous pouvez développer des applications Python efficaces, compréhensibles et sécurisées. En intégrant ce processus à votre cycle de développement logiciel, vous pouvez préserver la qualité du code et empêcher l’introduction de vulnérabilités dans votre application.

9. Intégration aux environnements de développement Python

Les outils d’analyse statique Python ne sont pas conçus pour fonctionner de manière isolée. Ils sont plus efficaces lorsqu’ils s’intègrent parfaitement à l’environnement de développement, ce qui peut améliorer les workflows de développement, les pipelines d’intégration continue (CI) et les éditeurs de code.

Voici le rôle des outils d’analyse statique Python dans ces différents domaines, ainsi qu’un exemple pratique d’intégration :

  • Rôle dans les workflows de développement : les outils d’analyse statique jouent un rôle essentiel dans les workflows de développement. Les développeurs Python peuvent s’en servir pour repérer et corriger d’éventuels problèmes pendant le développement, avant même l’exécution du code. Cette détection précoce peut faire gagner beaucoup de temps lors du débogage et améliorer la qualité du code.

  • Rôle dans les pipelines CI : dans les pipelines d’intégration continue, les outils d’analyse statique peuvent analyser automatiquement le code de chaque commit ou pull request. Cela garantit que toute nouvelle modification respecte les normes de codage et n’introduit pas de vulnérabilités potentielles. Ces outils peuvent être intégrés à des pipelines CI comme Jenkins, GitLab CI, GitHub Actions, etc.

  • Rôle dans les éditeurs de code : la plupart des éditeurs de code modernes, comme Visual Studio Code, PyCharm, Atom et Sublime Text, prennent en charge l’intégration d’outils d’analyse statique. Les développeurs peuvent ainsi obtenir un retour en temps réel sur la structure et le style de leur code, ainsi que sur ses vulnérabilités potentielles, pendant qu’ils écrivent.

Exemple pratique : intégrer PyLint à Visual Studio Code

PyLint est un outil d’analyse statique Python populaire. Voici comment l’intégrer à Visual Studio Code, un éditeur de code très utilisé.

Commencez par vérifier que PyLint est installé dans votre environnement Python. Si ce n’est pas le cas, vous pouvez l’installer avec pip :

pip install pylint

Ensuite, ouvrez Visual Studio Code et installez l’extension Python de Microsoft depuis la vue Extensions.

Une fois l’extension installée, ouvrez les paramètres (File > Preferences > Settings). Dans la section User Settings, recherchez Python Linting. Vérifiez que la case Enabled est cochée et que Pylint est sélectionné dans la liste déroulante Linter.

Désormais, chaque fois que vous ouvrirez un fichier Python dans Visual Studio Code, PyLint analysera automatiquement le code et signalera les problèmes détectés.

Voici un exemple de code Python et la manière dont PyLint signalerait un problème :

def add_numbers(a, b):
    return a + c

Dans le code ci-dessus, PyLint soulignera c et affichera le message d’avertissement Undefined variable 'c', ce qui vous permettra de détecter l’erreur avant d’exécuter le code.

10. Profilage des performances

Le profilage des performances est une dimension essentielle de l’analyse statique de Python. Il consiste à examiner votre code pour repérer les goulots d’étranglement, les sections inefficaces ou les parties du code qui consomment beaucoup de ressources processeur ou mémoire. Un profilage approfondi des performances permet aux développeurs d’optimiser leur code et d’améliorer ainsi la vitesse et l’efficacité globales de l’application.

Le profilage des performances permet de mesurer la complexité de votre code en termes de temps et d’espace. La complexité temporelle correspond au temps total nécessaire à l’exécution d’un programme, tandis que la complexité spatiale concerne la quantité de mémoire utilisée. Un profil détaillé des performances indique le nombre d’appels de fonctions, le temps passé dans chaque fonction et d’autres informations utiles pour optimiser les performances de l’application.

Exemple de code Python illustrant le profilage des performances

Python propose plusieurs outils de profilage des performances, dont l’un des plus courants est le module intégré cProfile, un profileur robuste et flexible. Voici un exemple simple de son utilisation :

import cProfile
import re

def re_test():
    re.compile("foo|bar")

cProfile.run('re_test()')

Lorsque vous exécutez ce code, cProfile génère un rapport indiquant le temps passé dans chaque fonction. Le résultat peut ressembler à ceci :

   200 function calls (195 primitive calls) in 0.002 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.000    0.000    0.001    0.001 :0(setprofile)
       43    0.000    0.000    0.000    0.000 :0(time)
        5    0.000    0.000    0.000    0.000 <ipython-input-26-6e8e8b2a9e4f>:1(re_test)
...

Ce résultat indique le nombre d’appels de chaque fonction (ncalls), le temps total passé dans la fonction, hors appels aux sous-fonctions (tottime), le temps cumulé passé dans la fonction, sous-fonctions comprises (cumtime), ainsi que d’autres informations utiles.

Le profilage des performances liées aux fuites et à l’utilisation de la mémoire est également essentiel pour les applications en production. Drew Wright a rédigé un excellent article sur le diagnostic et la correction des fuites de mémoire en Python, inspiré de son expérience et des difficultés liées aux fuites de mémoire qu’il a rencontrées lorsqu’il faisait partie de l’équipe d’ingénierie de Snyk.

Le profilage des performances a un impact direct sur votre code. Il vous aide à repérer les parties de votre code qui constituent des goulots d’étranglement, afin de concentrer vos efforts d’optimisation sur ces zones. Le profilage peut également aider à trouver des bugs qui ne seraient pas visibles lors des tests habituels. De plus, il peut influencer votre façon d’écrire du code. Une bonne compréhension des complexités temporelle et spatiale peut vous guider vers un code plus efficace et, au bout du compte, de meilleures performances pour vos applications.

Conclusion

L’analyse statique est un outil puissant qui peut considérablement améliorer la qualité de votre code et le rendre plus sûr. En vous appuyant sur les dix dimensions de l’analyse statique de Python présentées dans cet article, vous pouvez améliorer votre processus de développement logiciel, empêcher l’introduction de bugs dans votre base de code et réduire la vulnérabilité de vos applications face aux menaces de sécurité.

Les différentes dimensions de l’analyse statique de Python fonctionnent de concert pour révéler les problèmes potentiels avant qu’ils ne surviennent en production. En détectant les bugs tôt, vous réduisez les coûts liés à leur correction ultérieure. L’analyse statique de Python est également essentielle pour garantir la sécurité du code. Elle peut révéler des vulnérabilités potentielles qui passeraient facilement inaperçues lors de revues de code manuelles. En intégrant l’analyse statique de Python à votre processus de développement logiciel, vous pouvez sécuriser vos applications et les protéger contre les attaques potentielles.

Encourager les développeurs à améliorer la qualité et la sécurité du code

J’espère que cet article vous a aidé à mieux comprendre les dix dimensions de l’analyse statique de Python et la façon dont elles peuvent améliorer la qualité et la sécurité du code. N’oubliez pas qu’un code de qualité et sécurisé ne consiste pas seulement à prévenir les bugs ou les vulnérabilités : il s’agit de créer des logiciels fiables, robustes et capables de relever les défis du monde réel.

Savez-vous comment prévenir l’injection de commandes en Python ? Comment vous protéger contre l’injection de code en Python ?

Suivre les bonnes pratiques de sécurité Python est essentiel pour garantir la sécurité de vos applications Python. Commencez dès aujourd’hui avec un compte Snyk gratuit et installez l’extension Snyk pour votre IDE afin de détecter et de corriger rapidement et facilement les vulnérabilités de votre code Python.