python-project-structure

Par wshobson · agents

Organisation de projets Python, architecture modulaire et conception d'API publiques. À utiliser lors de la création de nouveaux projets, de l'organisation de modules, de la définition d'interfaces publiques avec `__all__`, ou de la planification de la structure des répertoires.

npx skills add https://github.com/wshobson/agents --skill python-project-structure

Architecture et Structure de Projets Python

Concevez des projets Python bien organisés avec des limites de modules clairs, des interfaces publiques explicites et des structures de répertoires maintenables. Une bonne organisation rend le code découvrable et les modifications prévisibles.

Quand utiliser cette compétence

  • Démarrer un nouveau projet Python à partir de zéro
  • Réorganiser une base de code existante pour plus de clarté
  • Définir les API publiques de modules avec __all__
  • Choisir entre des structures de répertoires plates et imbriquées
  • Déterminer les stratégies de placement des fichiers de test
  • Créer des packages de bibliothèque réutilisables

Concepts fondamentaux

1. Cohésion des modules

Regroupez le code connexe qui change ensemble. Un module doit avoir un objectif unique et clair.

2. Interfaces explicites

Définissez ce qui est public avec __all__. Tout ce qui n'est pas listé est un détail d'implémentation interne.

3. Hiérarchies plates

Privilégiez les structures de répertoires peu profondes. Ajoutez de la profondeur uniquement pour les véritables sous-domaines.

4. Conventions cohérentes

Appliquez les modèles de dénomination et d'organisation uniformément dans le projet.

Démarrage rapide

myproject/
├── src/
│   └── myproject/
│       ├── __init__.py
│       ├── services/
│       ├── models/
│       └── api/
├── tests/
├── pyproject.toml
└── README.md

Modèles fondamentaux

Modèle 1 : Un concept par fichier

Chaque fichier doit se concentrer sur un seul concept ou un ensemble étroitement lié de fonctions. Envisagez une division quand un fichier :

  • Gère plusieurs responsabilités sans rapport
  • Dépasse 300-500 lignes (varie selon la complexité)
  • Contient des classes qui changent pour différentes raisons
# Bon : Fichiers focalisés
# user_service.py - Logique métier utilisateur
# user_repository.py - Accès aux données utilisateur
# user_models.py - Structures de données utilisateur

# À éviter : Fichiers fourre-tout
# user.py - Contient service, repository, modèles, utilitaires...

Modèle 2 : API publiques explicites avec __all__

Définissez l'interface publique pour chaque module. Les membres non listés sont des détails d'implémentation interne.

# mypackage/services/__init__.py
from .user_service import UserService
from .order_service import OrderService
from .exceptions import ServiceError, ValidationError

__all__ = [
    "UserService",
    "OrderService",
    "ServiceError",
    "ValidationError",
]

# Les aides internes restent privées par omission
# from .internal_helpers import _validate_input  # Non exporté

Modèle 3 : Structure de répertoires plate

Privilégiez l'imbrication minimale. Les hiérarchies profondes rendent les imports verbeux et la navigation difficile.

# Préféré : Structure plate
project/
├── api/
│   ├── routes.py
│   └── middleware.py
├── services/
│   ├── user_service.py
│   └── order_service.py
├── models/
│   ├── user.py
│   └── order.py
└── utils/
    └── validation.py

# À éviter : Imbrication profonde
project/core/internal/services/impl/user/

Ajoutez des sous-packages uniquement s'il y a un véitable sous-domaine nécessitant une isolation.

Modèle 4 : Organisation des fichiers de test

Choisissez une approche et appliquez-la de manière cohérente dans tout le projet.

Option A : Tests colocalisés

src/
├── user_service.py
├── test_user_service.py
├── order_service.py
└── test_order_service.py

Avantages : Les tests vivent à côté du code qu'ils vérifient. Facile de voir les lacunes de couverture.

Option B : Répertoire de test parallèle

src/
├── services/
│   ├── user_service.py
│   └── order_service.py
tests/
├── services/
│   ├── test_user_service.py
│   └── test_order_service.py

Avantages : Séparation nette entre le code de production et le code de test. Standard pour les projets plus grands.

Modèles avancés

Modèle 5 : Initialisation de package

Utilisez __init__.py pour fournir une interface publique propre aux consommateurs du package.

# mypackage/__init__.py
"""MyPackage - A library for doing useful things."""

from .core import MainClass, HelperClass
from .exceptions import PackageError, ConfigError
from .config import Settings

__all__ = [
    "MainClass",
    "HelperClass",
    "PackageError",
    "ConfigError",
    "Settings",
]

__version__ = "1.0.0"

Les consommateurs peuvent alors importer directement depuis le package :

from mypackage import MainClass, Settings

Modèle 6 : Architecture en couches

Organisez le code par couche architecturale pour une séparation nette des préoccupations.

myapp/
├── api/           # Gestionnaires HTTP, requête/réponse
│   ├── routes/
│   └── middleware/
├── services/      # Logique métier
├── repositories/  # Accès aux données
├── models/        # Entités du domaine
├── schemas/       # Schémas API (Pydantic)
└── config/        # Configuration

Chaque couche ne doit dépendre que des couches en dessous, jamais des couches au-dessus.

Modèle 7 : Structure orientée domaine

Pour les applications complexes, organisez par domaine métier plutôt que par couche technique.

ecommerce/
├── users/
│   ├── models.py
│   ├── services.py
│   ├── repository.py
│   └── api.py
├── orders/
│   ├── models.py
│   ├── services.py
│   ├── repository.py
│   └── api.py
└── shared/
    ├── database.py
    └── exceptions.py

Dénomination des fichiers et modules

Conventions

  • Utilisez snake_case pour tous les noms de fichiers et modules : user_repository.py
  • Évitez les abréviations qui obscurcissent le sens : user_repository.py au lieu de usr_repo.py
  • Associez les noms de classes aux noms de fichiers : UserService dans user_service.py

Style d'import

Utilisez les imports absolus pour la clarté et la fiabilité :

# Préféré : Imports absolus
from myproject.services import UserService
from myproject.models import User

# À éviter : Imports relatifs
from ..services import UserService
from . import models

Les imports relatifs peuvent se casser quand les modules sont déplacés ou réorganisés.

Résumé des bonnes pratiques

  1. Gardez les fichiers focalisés - Un concept par fichier, envisagez une division à 300-500 lignes (varie selon la complexité)
  2. Définissez __all__ explicitement - Rendez les interfaces publiques claires
  3. Privilégiez les structures plates - Ajoutez de la profondeur uniquement pour les véritables sous-domaines
  4. Utilisez les imports absolus - Plus fiables et plus clairs
  5. Soyez cohérent - Appliquez les modèles uniformément dans le projet
  6. Associez les noms au contenu - Les noms de fichiers doivent décrire leur objectif
  7. Séparez les préoccupations - Gardez les couches distinctes et les dépendances circulant dans une direction
  8. Documentez votre structure - Incluez un README expliquant l'organisation

Skills similaires