Aller au contenu

Conventions Python

Ce document definit les conventions de codage Python pour l'organisation. Il couvre le nommage, les annotations de type, les docstrings, les patterns interdits et requis, le formatage avec Ruff, et la structure de projet. Tout code Python doit respecter ces regles sans exception.


Portee

Ce standard s'applique a tous les contributeurs (humains et agents IA) qui ecrivent ou modifient du code Python sur les repositories de l'organisation. Cela inclut les scripts de build, les outils internes, les tests, et les applications Python.

Langue obligatoire — Anglais

Tout le code, les commentaires, les noms de variables, les noms de fonctions, les docstrings et la documentation doivent etre en anglais americain (U.S. English). Aucune exception.


Nommage

Conventions generales

Element Convention Exemple
Variables, fonctions snake_case total_bytes, calculate_offset()
Classes PascalCase ConfigLoader, TopologyParser
Constantes SCREAMING_SNAKE_CASE MAX_RETRIES, DEFAULT_TIMEOUT
Fichiers snake_case.py config_loader.py, topology_parser.py
Repertoires snake_case data_utils/, auth_service/
Membres prives _snake_case _internal_state, _parse_header()
Methodes dunder __snake_case__ __init__, __repr__, __enter__

Noms de methodes — verbes obligatoires

Les noms de methodes doivent etre des verbes decrivant l'effet ou la valeur retournee.

Bon Mauvais Pourquoi
is_ready() ready() Un booleen commence par is_, has_, can_
calculate_offset() offset() Le nom doit decrire l'action
get_user() user() Accesseur explicite
validate_input() validation() Un verbe, pas un nom

Noms eviter

Pattern a eviter Alternative
Noms a une lettre (x, d, l) Nom descriptif (index, data, items)
Abbreviations ambigues (cfg, mgr, ctx) Mot complet (config, manager, context)
Noms generiques (data, info, result) seuls Qualifier : user_data, error_info, parse_result
Prefixe my_ ou the_ Supprimer le prefixe

Annotations de type (type hints)

Les annotations de type sont obligatoires sur toutes les fonctions et methodes publiques. Elles sont fortement recommandees sur les fonctions internes.

Regles

Signature typee
def calculate_offset(base: int, size: int) -> int:
    return base + size
Regle Detail
from __future__ import annotations Obligatoire en tete de fichier pour les forward references
Types nullables X \| None (Python 3.10+) ou Optional[X]
Types complexes TypeAlias pour les definitions de type complexes
Fonctions publiques Jamais laisser une signature publique sans type hints
Retour None Annoter explicitement -> None pour les fonctions sans retour

Exemples

Annotations courantes
from __future__ import annotations
from collections.abc import Sequence
from pathlib import Path
from typing import TypeAlias

# TypeAlias pour les types complexes
NodeId: TypeAlias = int
AdjacencyList: TypeAlias = dict[NodeId, list[NodeId]]

def load_config(path: Path) -> dict[str, str]:
    """Load configuration from a YAML file."""
    ...

def find_nodes(graph: AdjacencyList, start: NodeId) -> list[NodeId]:
    """Find all reachable nodes from a starting node."""
    ...

def process_batch(items: Sequence[str], limit: int | None = None) -> int:
    """Process a batch of items, optionally limited."""
    ...

Docstrings

Style Google

Toutes les fonctions, classes et modules publics doivent avoir une docstring au format Google. Les docstrings doivent etre en anglais.

Docstring Google-style complete
def transfer_data(source: int, target: int, count: int) -> bool:
    """Transfer data blocks between storage nodes.

    Moves the specified number of blocks from the source node to the
    target node. The transfer is atomic: either all blocks are moved
    or none are.

    Args:
        source: Source storage node ID.
        target: Target storage node ID.
        count: Number of blocks to transfer.

    Returns:
        True if all blocks were transferred successfully.

    Raises:
        ConnectionError: If the target node is unreachable.
        ValueError: If count is negative.
    """

Regles

Regle Detail
Premiere ligne Resume en une phrase, terminee par un point
Sections Args Un par parametre, description courte
Section Returns Description du type de retour et sa semantique
Section Raises Exceptions que la fonction peut lever
Longueur Concise — ne pas restater ce que la signature dit deja

Classes

Docstring de classe
class ConfigLoader:
    """Load and validate project configuration files.

    Supports YAML and TOML formats. Configuration values are validated
    against a predefined schema at load time.

    Attributes:
        path: Path to the configuration file.
        data: Parsed configuration data.
    """

    def __init__(self, path: Path) -> None:
        self.path = path
        self.data: dict[str, str] = {}

Patterns interdits

Pattern interdit Raison Alternative
from module import * Pollue le namespace, conflits de noms Imports explicites
Arguments par defaut mutables (def f(x=[])) Valeur partagee entre tous les appels None + creation conditionnelle
except: nu (sans type) Capture tout, y compris KeyboardInterrupt Capturer des exceptions specifiques
print() en production Pas de niveaux, pas de filtrage Module logging
Etat global mutable Couplage fort, tests impossibles Injection de dependance
Francais dans le code Incoherence, lisibilite reduite Anglais exclusivement
Exemple — argument mutable par defaut
# INTERDIT
def process(items: list[str] = []) -> None:
    items.append("new")  # Bug : modifie la valeur par defaut !

# CORRECT
def process(items: list[str] | None = None) -> None:
    if items is None:
        items = []
    items.append("new")

Patterns requis

Pattern requis Raison A eviter
if __name__ == "__main__": guard Empeche l'execution a l'import Code au top-level
Context managers (with) Liberation garantie des ressources open() sans with
f-strings pour le formatage Lisibilite, performance % ou .format()
pathlib.Path pour les chemins API objet, cross-platform os.path
Exemple — pathlib et context manager
from pathlib import Path

config_path = Path("config") / "settings.yaml"
if config_path.exists():
    content = config_path.read_text()

Formatage et linting

Ruff — outil unique

L'organisation utilise Ruff comme outil unique de formatage et de linting.

Outil Commande Role
Formatage ruff format Formatage automatique du code
Linting ruff check Verification des regles de qualite
Fix automatique ruff check --fix Correction automatique des problemes simples

Obligation : toujours executer ruff format et ruff check avant chaque commit.

Regles de formatage

Regle Valeur
Indentation 4 espaces (jamais de tabulations)
Largeur de ligne 88 colonnes
Guillemets Doubles (") par defaut
Virgule finale Oui, dans les collections multi-lignes
Lignes vides 2 entre les definitions de top-level, 1 entre les methodes

Configuration dans pyproject.toml

Configuration Ruff minimale
[tool.ruff]
line-length = 88
target-version = "py312"

[tool.ruff.lint]
select = ["E", "F", "W", "I", "N", "UP", "B", "SIM", "RUF"]

[tool.ruff.format]
quote-style = "double"

Structure de projet

pyproject.toml obligatoire

Tout projet Python utilise pyproject.toml pour sa configuration. L'utilisation de setup.py ou setup.cfg est obsolete et interdite pour les nouveaux projets.

pyproject.toml — structure type
[project]
name = "my-project"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = [
    "pyyaml>=6.0,<7",
    "httpx>=0.27,<1",
]

[project.optional-dependencies]
dev = [
    "pytest>=8.0",
    "ruff>=0.8",
]

Dependances

Regle Detail
Contraintes de version Toujours epingler avec >=X.Y,<Z
Dependances dev Separees dans [project.optional-dependencies]
Environnements virtuels venv, poetry, uv ou equivalent
Lock file Recommande pour les applications (pas les libraries)

Arborescence type

my_project/
+-- pyproject.toml
+-- src/
|   +-- my_project/
|       +-- __init__.py
|       +-- config.py
|       +-- services/
|           +-- __init__.py
|           +-- auth.py
+-- tests/
|   +-- __init__.py
|   +-- test_config.py
|   +-- test_auth.py
+-- scripts/
    +-- setup_env.py
Repertoire Role
src/ Code source (layout src recommande)
tests/ Tests (miroir de la structure source)
scripts/ Scripts utilitaires et d'automatisation

Resume des regles critiques

Regle Statut
Tout en anglais (code, commentaires, docstrings) Obligatoire
snake_case pour variables et fonctions Obligatoire
PascalCase pour les classes Obligatoire
Type hints sur les fonctions publiques Obligatoire
Docstrings Google-style sur les APIs publiques Obligatoire
from module import * Interdit
Arguments par defaut mutables Interdit
except: nu Interdit
print() en production Interdit
Guard __main__ dans les scripts Obligatoire
with pour les fichiers et ressources Obligatoire
f-strings pour le formatage Obligatoire
pathlib.Path pour les chemins Obligatoire
ruff format + ruff check avant commit Obligatoire
pyproject.toml pour la configuration Obligatoire

References