Ce que change la fin de vie de Python 3.10
Le guide du développeur Python publie le calendrier de chaque branche. Python 3.10, sortie en octobre 2021, y figure en fin de vie depuis le 1er octobre 2026. Concrètement, la branche ne reçoit plus de correctif, pas même de sécurité : une faille découverte dans l'interpréteur ou dans sa bibliothèque standard restera ouverte.
Votre code continue de tourner et vos tests passent, ce qui rend la situation trompeuse. La fin de vie ne casse rien le jour même. Elle retire le filet pour tous les jours suivants, tandis que les distributions, les images de base et les bibliothèques tierces s'en désintéressent peu à peu.
Ce que coûte un interpréteur figé
- Failles sans correctif — toute vulnérabilité de l'interpréteur publiée après la fin de vie reste ouverte sur la branche 3.10 ; seule une montée de version la referme.
- Dépendances qui décrochent — les bibliothèques relèvent tôt ou tard leur version minimale de Python ; une installation neuve finit par résoudre d'anciennes versions, ou par échouer.
- Images de base figées — une image de conteneur construite sur la branche 3.10 repose sur un interpréteur sans correctif amont, et vos analyses de vulnérabilités le signalent à chaque build.
- Audits qui coincent — un interpréteur hors support est une ligne rouge dans les revues de sécurité et les questionnaires fournisseurs de vos clients.
- Migration subie — de 3.10 à 3.12, l'écart couvre deux versions mineures ; plus vous attendez, plus la liste des ruptures s'allonge, et un chantier planifié coûte moins qu'une urgence après incident.
Calendrier de support des branches Python
Faites défiler le tableau
| Version | Fin de support | Lecture pour votre VPS |
|---|---|---|
| 3.9 | octobre 2025 | Hors support depuis plus d'un an : à quitter sans attendre |
| 3.10 | octobre 2026 | Hors support depuis le 1er octobre : plus aucun correctif |
| 3.11 | octobre 2027 | Palier minimal : il règle le problème du jour, pas celui de l'an prochain |
| 3.12 | octobre 2028 | Cible recommandée : deux ans de marge et un écosystème installé |
| 3.13 | octobre 2029 | Supportée plus longtemps encore ; à adopter une fois vos dépendances validées |
| 3.14 | octobre 2030 | Branche la plus récente de ce tableau, dont la fin de support est la plus lointaine |
Quelle version cible choisir
Python 3.12 est la cible que nous recommandons pour une application existante : sa fin de support est planifiée en octobre 2028, soit deux ans de marge, et les frameworks courants la prennent en charge. Python 3.11 est un palier minimal, qui vous ramène devant la même migration en octobre 2027.
Python 3.13 est supportée plus longtemps encore, jusqu'en octobre 2029. Nous ne la jugeons pas inadaptée : elle suppose seulement que chacune de vos dépendances publie ses paquets pour cette version, ce qui se vérifie dans votre environnement de test. Rappel du guide officiel : les dates des branches encore actives sont planifiées et peuvent être ajustées, seules celles de 3.9 et 3.10 sont acquises. Relisez la page avant de figer votre calendrier.
Savoir quel interpréteur sert vraiment la production
python3 --version dans votre shell ne dit pas quel interpréteur sert l'application. Le service peut lancer un environnement virtuel créé il y a des années, un Python compilé à la main, ou une image figée dans un FROM python:3.10.
Recensez chaque source : la ligne ExecStart de l'unité systemd (systemctl cat monapp), le résultat de /srv/monapp/venv/bin/python --version, un grep -rn "FROM python" . sur vos Dockerfiles, le champ requires-python de pyproject.toml et la version utilisée par votre CI. Notez aussi les workers et les tâches planifiées : ils ont souvent leur propre environnement et restent sur l'ancien interpréteur longtemps après le site.
Prérequis avant de commencer
Cette migration ne demande pas de machine particulière, mais un accès complet au serveur et de la place pour deux environnements en parallèle : le second occupe autant de disque que le premier, plus un cache de compilation si une dépendance n'a pas de paquet précompilé.
Il vous faut un fichier de dépendances verrouillé avec des versions exactes, une suite de tests exécutable hors production, une sauvegarde récente de la base de données et l'accès root pour installer, si vos dépendances compilées l'exigent, un compilateur et les en-têtes de développement. Une première passe sur un VPS de test, même éphémère, vaut mieux qu'un essai sur le serveur de production.
Migrer sans interrompre le service
Figer l'existant
Depuis l'environnement actuel, exportez les versions exactes :
/srv/monapp/venv/bin/pip freeze > requirements.lock.txt. Ce fichier décrit précisément ce qui tourne aujourd'hui ; il est votre point de retour. Versionnez-le avant de continuer.Installer Python 3.12 sans toucher au système
uv python install 3.12télécharge un interpréteur 3.12 géré par uv, sans remplacer lepython3de la distribution dont dépendent ses propres outils. Si vous préférez les paquets de votre distribution, installez la branche 3.12 depuis un dépôt qui la fournit et utilisezpython3.12 -m venv.Créer le second environnement à côté du premier
uv venv --python 3.12 /srv/monapp/venv312crée l'environnement neuf ; sans uv,python3.12 -m venv /srv/monapp/venv312fait le même travail. L'ancien continue de servir le trafic : rien n'est modifié. Un environnement virtuel ne se déplace pas, c'est pourquoi le nouveau porte un autre nom.Réinstaller depuis le fichier verrouillé
VIRTUAL_ENV=/srv/monapp/venv312 uv pip sync requirements.lock.txtinstalle exactement les versions listées. Avec pip :/srv/monapp/venv312/bin/pip install -r requirements.lock.txt. Si une version figée n'existe pas pour 3.12 ou refuse de se compiler, l'installation s'arrête ici : c'est le but, vous découvrez la rupture avant la production. Notez chaque paquet à relever.Rejouer la suite de tests
Lancez les tests avec le nouvel interpréteur :
/srv/monapp/venv312/bin/python -m pytest, ou/srv/monapp/venv312/bin/python manage.py testpour Django, précédé demanage.py check. Lisez le résumé des avertissements de dépréciation : ils annoncent les ruptures de la version suivante. Les tests doivent passer avec les deux interpréteurs avant de continuer.Monter uniquement ce qui a cassé
Relevez les paquets en cause, montez-les un par un, puis régénérez le fichier verrouillé depuis le nouvel environnement :
/srv/monapp/venv312/bin/pip freeze > requirements.312.txt. Gardez les deux listes, une par interpréteur, le temps de la bascule.Démarrer l'application en parallèle sur un port local
Lancez-la avec le nouvel environnement sur un port libre, par exemple
/srv/monapp/venv312/bin/gunicorn monapp.wsgi --bind 127.0.0.1:8001(ouuvicornpour FastAPI). Envoyez-y des requêtes réelles aveccurl: page d'accueil, connexion, une écriture en base. Le trafic public reste sur l'ancien processus ; seul un résultat identique justifie de passer à la bascule.
Basculer et revenir en arrière en une ligne
La bascule ne doit modifier qu'un chemin. Faites pointer l'unité systemd sur un lien plutôt que sur l'environnement : ExecStart=/srv/monapp/venv-actif/bin/gunicorn monapp.wsgi --bind 127.0.0.1:8000. Créez d'abord le lien vers l'état actuel avec ln -sfn /srv/monapp/venv /srv/monapp/venv-actif, puis systemctl daemon-reload et un redémarrage qui ne change rien.
La bascule vers 3.12 devient alors ln -sfn /srv/monapp/venv312 /srv/monapp/venv-actif && systemctl restart monapp, et le retour arrière est la même ligne avec l'ancien chemin. Pour une application en conteneur, le levier est l'image de base : passez de FROM python:3.10-slim à FROM python:3.12-slim, reconstruisez avec docker compose up -d --build et revenez en arrière en rétablissant la ligne précédente.
Dans les deux cas, gardez l'ancien environnement ou l'ancienne image quelques jours, et suivez les journaux avec journalctl -u monapp -f pendant la première heure.
Les points de casse à contrôler
Entre 3.10 et 3.12, la rupture vient rarement de votre code et presque toujours de ce qui l'entoure. Trois familles reviennent : les modules retirés de la bibliothèque standard, les dépendances compilées et la version minimale de vos frameworks. Les notes de version de Python 3.12 listent ce qui disparaît ; lisez-les avec votre fichier verrouillé ouvert à côté.
Liste de contrôle avant la bascule
- Modules retirés — Python 3.12 supprime
distutils,asynchat,asyncoreetimp;grep -rnE "distutils|asyncore|asynchat|import imp" .repère vos usages directs, la liste de vos dépendances révèle les indirects. - setuptools n'est plus préinstallé — les environnements créés par
venvne l'embarquent plus en 3.12 ; un paquet qui importepkg_resourcessans le déclarer échoue tant que vous n'avez pas faitpip install setuptools. - Paquets précompilés — les dépendances compilées (pilotes de base de données, traitement d'image, cryptographie) doivent publier un paquet pour 3.12 ;
pip install --only-binary=:all: -r requirements.lock.txtéchoue vite au lieu de lancer une compilation. - Versions minimales des frameworks — Django 4.2 ne prend en charge Python 3.12 qu'à partir de la 4.2.8, et Django 5.0 et les suivantes l'acceptent ; pour FastAPI, relisez les classifiers Python de la version exacte que vous épinglez.
- Avertissements de dépréciation —
datetime.utcnow()etdatetime.utcfromtimestamp()sont dépréciées en 3.12 ; remplacez-les pardatetime.now(datetime.UTC)etdatetime.fromtimestamp(ts, datetime.UTC). - Bibliothèques système partagées — l'environnement parallèle isole les paquets Python, pas les bibliothèques de l'OS (client PostgreSQL, par exemple) : notez-les, une mise à jour du système peut les changer sous vos pieds.
Dépannage : les erreurs qui reviennent
Ces messages apparaissent dès la première exécution des tests sous Python 3.12. Chacun a une cause connue et un remède court.
Message observé et remède
- ModuleNotFoundError: No module named 'distutils' — le module a quitté la bibliothèque standard. Installez
setuptoolsdans l'environnement, qui continue d'en fournir une version, puis montez la dépendance fautive. - ModuleNotFoundError: No module named 'imp' —
impest retiré,importlible remplace. Si l'import vient d'un paquet tiers, montez ce paquet vers une version qui ne l'utilise plus. - ModuleNotFoundError: No module named 'pkg_resources' — setuptools n'est plus installé d'office dans les environnements venv de 3.12.
pip install setuptoolsrétablit le module en attendant que le paquet fautif s'en passe. - DeprecationWarning: datetime.datetime.utcnow() is deprecated — ce n'est pas une erreur mais un signal : remplacez l'appel par un objet conscient du fuseau horaire.
- Failed building wheel for <paquet> — ce paquet n'a pas de version précompilée pour 3.12 et pip tente de le compiler. Montez-le, ou installez compilateur et en-têtes de développement si la montée est impossible.
Épingler la cible, pas seulement migrer
Profitez de la migration pour fixer l'interpréteur au lieu de le subir : requires-python = ">=3.12" dans pyproject.toml, un tag d'image précis plutôt que python:3, et la version de Python dans la matrice de votre CI. Ajoutez 3.13 à cette matrice en simple observation : vous saurez à l'avance si la prochaine montée sera simple.
Faire de la montée de version un geste habituel
Une branche de Python arrive en fin de vie chaque année, en octobre. La méthode décrite ici (environnement parallèle, fichier verrouillé, tests, bascule réversible) ne dépend d'aucune version précise : elle se rejoue telle quelle pour 3.11 en octobre 2027 et pour 3.12 en octobre 2028, d'après le calendrier actuel.
Si votre application n'est pas encore sur un serveur dont vous maîtrisez l'interpréteur, notre guide de déploiement de Django sur un VPS couvre le premier déploiement. Les guides sur la fin de vie de Node.js et de PHP suivent la même logique pour les autres runtimes d'un parc.