Environnements virtuels & Projet Python

Structurer
son projet

Isolation des dépendances avec venv, gestion des paquets avec pip, et structure standard d'un projet Python.

Pourquoi isoler les dépendances ?

🚨

Sans venv : tous les projets partagent les mêmes paquets installés globalement. Projet A a besoin de requests==2.28, projet B a besoin de requests==2.31 → conflit insoluble.

Avec venv : chaque projet a son propre dossier venv/ avec ses propres paquets, indépendants des autres projets et du Python système.

ℹ️

Règle absolue : un projet = un environnement virtuel. Toujours activer le venv avant de travailler sur un projet. Jamais installer des paquets avec pip install globalement (sans venv actif).

venv — module intégré Python

Terminal — macOS / Linux
# 1. Créer l'environnement virtuel
$ python3 -m venv venv
 
# 2. Activer
$ source venv/bin/activate
(venv) $ _ ← préfixe = venv actif
 
# 3. Désactiver
(venv) $ deactivate
Terminal — Windows
# 1. Créer
> python -m venv venv
 
# 2. Activer (PowerShell)
> venv\Scripts\Activate.ps1
 
# 2. Activer (CMD)
> venv\Scripts\activate.bat
 
# Si erreur PowerShell :
> Set-ExecutionPolicy -Scope CurrentUser RemoteSigned
⚠️

Ne jamais committer le dossier venv/ dans Git — il est lourd (~50 Mo) et propre à chaque machine. Toujours l'ajouter au .gitignore.

pip & requirements

pip — commandes essentielles
# Installer un paquet
(venv) $ pip install requests
(venv) $ pip install requests==2.31.0
 
# Mettre à jour
(venv) $ pip install --upgrade requests
 
# Désinstaller
(venv) $ pip uninstall requests
 
# Lister les paquets installés
(venv) $ pip list
 
# Geler les dépendances (partage)
(venv) $ pip freeze > requirements.txt
 
# Réinstaller depuis requirements.txt
(venv) $ pip install -r requirements.txt

requirements.txt — exemple

requirements.txt
# Dépendances exactes (pip freeze)
requests==2.31.0
numpy==1.26.4
pytest==8.1.1

# Ou avec plage de versions
requests>=2.28,<3.0
numpy>=1.24
💡

Séparer les dépendances de développement : requirements.txt pour la prod, requirements-dev.txt pour pytest, black, mypy, etc.

.gitignore Python standard

.gitignore
# Environnement virtuel
venv/
.venv/
env/

# Cache Python
__pycache__/
*.py[cod]
*.pyo

# Distribution / packaging
dist/
build/
*.egg-info/

# Tests
.pytest_cache/
.coverage
htmlcov/

# IDE
.vscode/
.idea/
*.swp

# Variables d'environnement sensibles
.env
*.env
ℹ️

Générer automatiquement un .gitignore complet sur gitignore.io en cherchant "Python".

Structure standard

Une structure claire facilite la collaboration, les tests et le déploiement. Voici la structure recommandée pour un projet Python de taille moyenne.

mon_projet/ ← racine du projet
├── README.md ← documentation
├── .gitignore
├── requirements.txt
├── pyproject.toml ← config moderne
├── mon_projet/ ← package principal
│ ├── __init__.py
│ ├── main.py
│ ├── models/
│ │ ├── __init__.py
│ │ └── utilisateur.py
│ └── utils/
│ ├── __init__.py
│ └── helpers.py
├── tests/ ← tests séparés
│ ├── __init__.py
│ ├── test_models.py
│ └── test_utils.py
└── venv/ ← NON commité
ℹ️

Le dossier tests/ est au même niveau que le package, pas à l'intérieur. Cela évite d'inclure les tests dans la distribution.

Rôle de __init__.py

Marque le dossier comme un package Python importable
Peut contenir des imports pour simplifier l'API publique
Peut être vide — sa présence suffit

Modules & packages

mon_projet/models/utilisateur.py
class Utilisateur:
    def __init__(self, nom: str, email: str):
        self.nom = nom
        self.email = email

    def __repr__(self):
        return f"Utilisateur({self.nom!r})"
mon_projet/models/__init__.py
# Exposer l'API publique du package
from .utilisateur import Utilisateur
# Maintenant : from mon_projet.models import Utilisateur
mon_projet/main.py
# Import absolu (recommandé)
from mon_projet.models import Utilisateur
from mon_projet.utils.helpers import formater

# Import relatif (dans un package)
from .models import Utilisateur
from ..utils import helpers

# Point d'entrée
if __name__ == "__main__":
    u = Utilisateur("Alice", "alice@example.com")
    print(u)
⚠️

if __name__ == "__main__": est essentiel. Sans lui, le code s'exécute même quand le fichier est importé par un autre module.

Imports propres

PEP 8 — ordre des imports
# 1. Bibliothèque standard Python
import os
import sys
from pathlib import Path
from typing import List, Optional

# 2. Paquets tiers (pip install)
import requests
from flask import Flask

# 3. Modules locaux du projet
from mon_projet.models import Utilisateur
from .utils import helpers

# À ÉVITER
from os import *          # import wildcard — pollue le namespace
import os, sys, pathlib  # plusieurs imports sur une ligne

pyproject.toml — configuration moderne

Remplace progressivement setup.py et setup.cfg. Fichier unique de configuration du projet.

pyproject.toml
[build-system]
requires = ["setuptools>=68", "wheel"]
build-backend = "setuptools.backends.legacy:build"

[project]
name = "mon-projet"
version = "0.1.0"
description = "Description du projet"
requires-python = ">=3.10"
dependencies = [
    "requests>=2.28",
]

[project.optional-dependencies]
dev = [
    "pytest>=8.0",
    "black>=24.0",
    "mypy>=1.8",
]

[tool.pytest.ini_options]
testpaths = ["tests"]

[tool.black]
line-length = 88
target-version = ["py310"]

[tool.mypy]
python_version = "3.10"
strict = true

Cheat sheet

venv — commandes

python -m venv venvCréer
source venv/bin/activateActiver (Mac/Linux)
venv\Scripts\activateActiver (Windows)
deactivateDésactiver

pip — commandes

pip install XInstaller
pip install -r req.txtDepuis fichier
pip freeze > req.txtGeler
pip listLister
pip show XInfos sur X

Règles d'or

Un projet= un venv
venv/Dans .gitignore
requirements.txtCommité
__init__.pyDans chaque dossier
tests/Hors du package