Contenu
Partie 6 — Comprendre les wheels
20. Qu’est-ce qu’une wheel ?
Une wheel est un format de distribution construit, portant l’extension :
.whl
Elle peut contenir :
- du code Python ;
- des métadonnées ;
- des ressources ;
- des bibliothèques compilées ;
- des extensions natives.
L’intérêt principal est d’éviter de compiler le logiciel pendant l’installation.
On peut comparer :
sdist = code source à construire wheel = paquet déjà construit
21. Anatomie d’un nom de wheel
Exemple :
numpy-2.1.0-cp312-cp312-win_amd64.whl
Décomposition :
numpy nom du paquet 2.1.0 version cp312 interpréteur Python cp312 ABI win_amd64 plateforme
Autre exemple :
requests-2.32.3-py3-none-any.whl
Décomposition :
py3 compatible avec Python 3 none aucune ABI native spécifique any n’importe quelle plateforme
Cette seconde wheel est dite « pure Python ».
Une wheel utilise généralement cette structure :
{python tag}-{ABI tag}-{platform tag}
Python tag
Exemples :
py3 cp311 cp312 cp313
cp312 signifie CPython 3.12.
ABI tag
L’ABI est l’interface binaire entre le code compilé et Python.
Exemples :
none cp312 abi3
Une extension utilisant l’ABI stable peut porter :
abi3
Elle peut alors fonctionner sur plusieurs versions de CPython.
Platform tag
Exemples :
win_amd64 win32 macosx_11_0_arm64 manylinux2014_x86_64 manylinux_2_17_aarch64 musllinux_1_2_x86_64 any
23. Pourquoi une wheel est refusée
Exemple :
ERROR: package.whl is not a supported wheel on this platform
Causes possibles :
- wheel Python 3.11 utilisée avec Python 3.12 ;
- wheel Windows utilisée sous Linux ;
- wheel x86-64 utilisée sur ARM ;
- wheel ARM utilisée sur x86-64 ;
- wheel CPython utilisée avec PyPy ;
- ABI incompatible ;
- version de
piptrop ancienne pour reconnaître les tags ; - système Linux incompatible avec le niveau
manylinux.
Exemple incompatible :
torch-2.4.0-cp312-cp312-manylinux2014_aarch64.whl
Cette wheel cible CPython 3.12, Linux et l’architecture ARM64. Elle ne conviendra pas à un Windows x86-64. Les tags de wheels peuvent encoder la version Python, l’implémentation, le système d’exploitation et l’architecture.
python -m pip debug --verbose
La sortie contient une liste de tags compatibles, par exemple :
cp312-cp312-win_amd64 cp312-abi3-win_amd64 cp311-abi3-win_amd64 py3-none-any
Cela permet de comparer directement l’environnement avec le nom de la wheel.
Partie 7 — Archives source et compilation
25. Qu’est-ce qu’une sdist ?
Une source distribution utilise souvent :
.tar.gz
Exemple :
package-1.2.0.tar.gz
Elle contient le code source et les informations permettant de construire le paquet.
Lorsque aucune wheel compatible n’est disponible, pip peut télécharger la sdist puis tenter de construire une wheel localement.
On voit alors des messages comme :
Building wheel for package...
ou :
Failed building wheel for package
26. Pourquoi une compilation échoue
Un paquet peut contenir du :
- C ;
- C++ ;
- Rust ;
- Fortran ;
- Cython.
Il peut donc nécessiter :
- un compilateur ;
- un linker ;
- des fichiers d’en-tête ;
- le SDK du système ;
- des bibliothèques natives ;
- Rust et Cargo ;
- CMake ;
- Ninja ;
pkg-config.
Sous Windows
Selon le paquet :
- Microsoft C++ Build Tools ;
- Windows SDK ;
- CMake ;
- Rust.
Sous Debian ou Ubuntu
Exemple générique :
sudo apt update sudo apt install build-essential python3-dev
Selon le paquet :
sudo apt install libpq-dev sudo apt install libssl-dev sudo apt install libffi-dev sudo apt install libxml2-dev libxslt1-dev
Exemple PostgreSQL
Le paquet psycopg ou certaines variantes de psycopg2 peuvent nécessiter les bibliothèques PostgreSQL de développement.
Erreur typique :
pg_config executable not found
Solution Debian/Ubuntu :
sudo apt install libpq-dev
27. Forcer l’utilisation de wheels
Pour refuser toute compilation :
python -m pip install --only-binary=:all: package
Exemple :
python -m pip install --only-binary=:all: numpy
Si aucune wheel compatible n’existe, l’installation échoue immédiatement.
C’est utile pour savoir si le problème vient de la compilation.
Préférer les wheels mais autoriser les sources :
python -m pip install --prefer-binary package
Refuser les wheels :
python -m pip install --no-binary=:all: package
Cette dernière commande force une compilation depuis les sources.
28. Construire ses propres wheels
python -m pip wheel -r requirements.txt -w wheels/
Puis installation locale :
python -m pip install --no-index --find-links=wheels -r requirements.txt
Cas d’usage :
- déploiement hors ligne ;
- CI/CD ;
- serveurs sans compilateur ;
- accélération des déploiements ;
- contrôle des artefacts installés.
Partie 8 — Résolution des dépendances
29. Dépendances directes et transitives
Supposons :
mon-projet
└── fastapi
├── starlette
├── pydantic
└── typing-extensions
fastapi est une dépendance directe.
starlette, pydantic et typing-extensions sont des dépendances transitives.
Lorsqu’on demande :
python -m pip install fastapi
pip doit chercher un ensemble de versions compatibles pour toutes ces bibliothèques.
Le processus qui détermine les versions à installer est appelé résolution des dépendances.
30. Exemple de conflit
Un projet demande :
package-a dépend de common-lib >=2,<3 package-b dépend de common-lib >=3,<4
Aucune version de common-lib ne peut satisfaire les deux contraintes.
pip peut afficher :
ResolutionImpossible
Ce message ne signifie pas nécessairement que pip est cassé.
Il signifie souvent que les contraintes sont mathématiquement incompatibles.
Les versions récentes du résolveur sont volontairement plus strictes face aux dépendances contradictoires.
31. Syntaxe des contraintes de versions
requests==2.32.3 requests>=2.30 requests>=2.30,<3 requests~=2.32.0 requests!=2.32.1
Version exacte
requests==2.32.3
Version minimale
requests>=2.30
Intervalle
requests>=2.30,<3
Version compatible
requests~=2.32.0
Cela signifie approximativement :
>=2.32.0,<2.33.0
Alors que :
requests~=2.32
signifie approximativement :
>=2.32,<3.0
32. Version de Python dans pyproject.toml
[project] requires-python = ">=3.11,<3.13"
Cela indique que le projet accepte :
Python 3.11 Python 3.12
mais pas :
Python 3.10 Python 3.13
Ce champ est essentiel pour empêcher l’installation du projet avec une version incompatible.
33. Environment markers
Une dépendance peut être conditionnelle :
dependencies = [
"importlib-metadata; python_version < '3.10'",
"colorama; sys_platform == 'win32'",
]
Ainsi :
coloramasera installé sous Windows ;importlib-metadatane sera installé que pour certaines versions de Python.
Les résolveurs prennent en compte :
python_version;python_full_version;sys_platform;platform_machine;platform_python_implementation.
Partie 9 — requirements.txt, contraintes et verrouillage
34. Le fichier requirements.txt
Exemple simple :
fastapi uvicorn sqlalchemy psycopg
Installation :
python -m pip install -r requirements.txt
Mais ce fichier ne garantit pas nécessairement une reproduction exacte.
Aujourd’hui, il peut installer :
fastapi 0.x pydantic 2.x
Dans six mois, il peut choisir d’autres versions.
35. Versions figées
fastapi==0.116.1 uvicorn==0.35.0 sqlalchemy==2.0.41
Cela améliore la reproductibilité.
Pour exporter l’environnement actuel :
python -m pip freeze > requirements.txt
Mais pip freeze exporte généralement tout ce qui est installé, y compris les dépendances transitives.
Exemple :
fastapi==... pydantic==... pydantic-core==... starlette==... typing-extensions==...
Ce n’est pas toujours un bon fichier à maintenir manuellement.
36. Différence entre dépendances directes et environnement figé
Il est utile de distinguer :
Dépendances voulues
fastapi sqlalchemy psycopg
Résultat exact de la résolution
fastapi==... starlette==... pydantic==... sqlalchemy==... psycopg==... typing-extensions==...
Le premier fichier décrit l’intention.
Le second décrit l’environnement résolu.
Les outils modernes comme uv, Poetry ou PDM maintiennent cette distinction avec :
pyproject.toml;- un fichier de verrouillage.
37. Fichier de contraintes
Exemple constraints.txt :
urllib3<2.3 pydantic==2.11.7
Installation :
python -m pip install -r requirements.txt -c constraints.txt
Une contrainte ne demande pas nécessairement l’installation du paquet.
Elle limite la version si ce paquet doit être installé.