Python >> Tutoriel Python >  >> Python

Guide de migration de Python 2.7 vers 3.X :Comment passer de Python 2 à Python 3

Python 2 a perdu le support le 1er janvier 2020. Le moment est venu de passer à Python 3.

Mais existe-t-il un moyen de le faire sans perturber le développement et le fonctionnement de votre application ?

Ce guide vous montrera comment mettre à niveau vers Python 3 rapidement, facilement et à moindre coût.

Nous supposerons que vous disposez déjà de la dernière version de Python 2.7 et que vous ciblez Python 3.6 ou une version plus récente.

Tout ce qui est inférieur à Python 3.5 serait déconseillé, car il s'agit déjà de la version la plus ancienne encore prise en charge et sa fin de vie est prévue pour le 13 septembre 2020.

Une dernière chose avant de commencer avec notre guide de migration :au cas où vous vous demanderiez exactement pourquoi vous devriez migrer vers Python 3, cet article ici est sûr de répondre à toutes les questions que vous pourriez avoir. C'est le "pourquoi" du "comment" du guide suivant

Premiers pas vers la compatibilité Python 3

1. Chaque nouveau morceau de code doit être compatible avec Python 3

Même si vous venez de commencer à penser à migrer vers Python 3, il y a une politique que vous devriez introduire immédiatement dans votre développement de code :chaque nouveau morceau de code validé dans votre référentiel doit être Python 3, du moins en théorie. Il s'agit ici d'un accord de type "meilleur effort".

Si votre produit est en cours de développement actif, suivre ce seul principe rendra la migration réelle beaucoup plus fluide. C'est aussi très bon marché.

Il n'est pas nécessaire de modifier votre pipeline d'intégration continue, aussi agréable soit-il. Retarder l'introduction de la règle simplement parce que vous n'avez pas la capacité d'apporter des modifications au pipeline pour le moment n'a aucun sens.

Vous êtes probablement occupé à introduire de nouvelles fonctionnalités telles quelles. En rendant tout votre nouveau code compatible avec Python 3, vous effectuerez déjà une migration sans y consacrer uniquement du temps de développement.

C'est vraiment l'endroit idéal pour commencer.

2. Les outils d'assurance qualité sont vos amis

Une bonne couverture de test, des linters et d'autres outils exécutés sous vos systèmes d'intégration continue sont des bouées de sauvetage chaque fois que vous introduisez des modifications importantes dans votre application.

Si vous n'utilisez aucun de ces éléments, nous vous recommandons vivement d'en tenir compte.

Voici plusieurs outils d'assurance qualité qui peuvent être extrêmement utiles lors du portage vers Python 3 :

a) Linters

Les linters sont les plus faciles à introduire, mais cela ne veut pas dire qu'ils ont peu de valeur. Ils donneront un coup de pouce bienvenu à vos efforts de migration.

b) Essais

Les tests sont assez indispensables et demandent malheureusement un certain investissement en temps, surtout au début, mais ils en valent largement la peine. Pour une application importante, même les tests de chemin heureux les plus élémentaires vous feront économiser d'innombrables heures que vous auriez autrement consacrées à des tests manuels laborieux et à la lutte contre les régressions.

c) Intégration continue

L'intégration continue rassemble tous vos efforts de développement logiciel de manière automatisée. Encore une fois, il s'agit d'une mesure permettant de gagner du temps, particulièrement importante si plusieurs personnes travaillent sur votre produit.

d) Suivi des erreurs

Le suivi des erreurs est un autre outil qui peut s'avérer très utile si quelque chose passe entre les mailles du filet des tests de pré-production.

Par exemple, Sentry vous fournit un rapport d'erreur complet en cas d'échec. Cela inclut la trace de la pile, qui vous permet de corriger les bogues courants liés à la transition en quelques minutes.

Ces outils d'assurance qualité ne sont pas strictement requis pour migrer vers Python 3. Cependant, il sera beaucoup plus difficile de s'assurer que votre logiciel continue de fonctionner correctement sans eux. L'introduction d'outils d'assurance qualité améliorera également votre flux de travail de développement standard.

Dans l'ensemble, plus vous implémentez les outils rapidement, mieux c'est pour vous.

3. Correctifs de compatibilité sécurisés

Pour démarrer vos efforts, utilisez la conversion automatique du code.

À cette fin, nous vous suggérons d'utiliser python-modernize, qui est construit au-dessus de l'outil 2to3 et du populaire package six.

Voici ce que vous devez faire, étape par étape :

  1. Ajoutez une nouvelle dépendance "six" à vos dépendances d'application.
  2. Exécutez "pip install modernize".
  3. Exécutez "python-modernize -w" dans le répertoire de votre projet.
  4. Examinez les modifications. Ils doivent être raisonnablement sûrs, mais parfois visiblement inefficaces. Ajustez-les comme bon vous semble.
  5. Testez votre application sur Python 2.

Si tout se passe bien, vous devriez avoir des correctifs de compatibilité relativement sûrs déjà appliqués à votre base de code. Vous pouvez les utiliser comme point de référence lors de l'ajout de nouveau code jusqu'à ce que vous passiez complètement à Python 3.

4. Mettre à jour les dépendances, première partie :les gains faciles

Votre application est déjà en passe d'atteindre la compatibilité totale avec Python 3, mais le problème de ses dépendances demeure.

Il n'est pas rare que les projets accumulent des dépendances qui ne sont plus maintenues et par conséquent ne prennent pas en charge Python 3.

Dans certains cas, tout ce que vous aurez à faire est de mettre à jour une dépendance vers une plus récente version; dans d'autres, vous devrez vous assurer que la mise à jour est la dernière version, compatible avec Python 2 et 3. C'est parce que certains packages ont peut-être déjà abandonné Python 2.

Quoi qu'il en soit, à ce stade, il est préférable de se concentrer sur les victoires faciles.

La plupart de vos packages sont probablement déjà compatibles ou ne nécessitent qu'une mise à jour vers une version plus récente. En règle générale, nous vous suggérons de mettre à jour vers la dernière version de chaque dépendance pour plus de sécurité.

Vérifier chaque dépendance une par une peut prendre du temps dans les grands projets. Vous pouvez faciliter le processus en exécutant "caniusepython3" sur votre "requirements.txt" (créez-en un avec "pip freeze> requirements.txt" si vous n'en avez pas).

Cet outil est loin d'être précis, mais il est suffisant pour atteindre notre objectif principal :évaluer la quantité de travail qu'il reste avant de pouvoir passer définitivement à Python 3.

Fourches compatibles Python 3

Il n'est pas rare d'apprendre qu'un paquet a été complètement abandonné par ses auteurs originaux. Cependant, c'est toujours une bonne idée de parcourir le suivi des problèmes du référentiel GitHub ou l'index PyPI du package, car d'autres ont probablement rencontré le même problème que vous et ont déjà créé un fork compatible avec Python 3.

Si vous ne parvenez pas à identifier un remplacement de package Python 3 fonctionnel, reportez la mise à niveau ou le remplacement à une étape ultérieure. Vous avez de plus gros poissons à faire frire.

Traitement des rétroportages

Certaines des fonctionnalités ajoutées à Python 3 ont été rétroportées en tant que packages installables séparés. Les exemples les plus courants incluent "subprocess32" et "functools32".

Ces backports ont tendance à être incompatibles avec Python 3 et échoueront même si vous essayez de les installer. Vous pouvez utiliser des marqueurs d'environnement pour s'assurer que cela n'arrive pas.

Voici comment effectuer une installation conditionnelle de "functools32", uniquement sur Python 2 :

functools32 ; version_python <"3"

Cette syntaxe peut être appliquée à la fois à "requirements.txt" et à "setup.py".

En ce qui concerne le code, utilisez une syntaxe "try-except" pour de tels packages :

1 2 3 4
try:
   from functools import lru_cache
except ImportError:
   from functools32 import lru_cache
5. Lintage de compatibilité Python 3

Une fois que vous avez mis en pratique tous nos correctifs suggérés, vous et votre équipe devriez déjà être familiarisés avec l'écriture de code qui fonctionnera sur Python 3 aussi bien que sur Python 2.

Cela étant dit, nous vous conseillons vivement d'utiliser des linters de code pour vous aider dans cette tâche.

Inspection du code PyCharm

PyCharm a commencé à prendre en charge l'analyse statique de compatibilité il y a 8 ans. Si vous êtes un utilisateur de PyCharm travaillant avec des bases de code Python 2, assurez-vous que la fonctionnalité est activée.

Mais si vous n'utilisez pas PyCharm, cette fonctionnalité à elle seule est une raison suffisante pour changer.

pylint --py3k

Pylint est connu pour être assez verbeux et parfois trop zélé, mais c'est toujours un excellent outil pour localiser les petits problèmes avant qu'ils ne se transforment en gros problèmes.

Installez "pylint" et exécutez "pylint --py3k application/*" pour obtenir un rapport sur les problèmes possibles dans le code. N'oubliez pas d'examiner au moins chaque message unique.

Au cours du processus, vous pourriez apprendre une ou deux choses sur les changements et les nouvelles fonctionnalités introduites dans Python 3, ce qui est précieux en soi.

Aide-mémoire sur la migration Python 2 vers 3 pour pylint

Voici un aide-mémoire rapide des messages et correctifs pylint les plus courants.

Nous avons laissé de côté les erreurs fréquentes qui peuvent être corrigées automatiquement avec "python-modernize".

1. suffixe long (E1606); longue durée (W1608)

Utiliser le suffixe long ; long intégré référencé

1 2 3
# Python 2
123L
long(123)
1 2 3 4 5 6 7 8 9 10 11
# Python 3
123

# or if you indeed need the long type when using Python 2

try:
   long
except NameError:
   long = int

long(123)
2. exception-message-attribut (W1645)

Message d'exception supprimé dans Python 3

1 2
# Python 2
exception.message
1 2
# Python 3
exception.args[0]
3. using-cmp-argument (W1640)

Utilisation de l'argument cmp pour list.sort/sorted

1 2
# Python 2
sorted(iterable, cmp=cmp_func)
1 2
# Python 3
sorted(iterable, key=functools.cmp_to_key(cmp_func))
4. cmp intégré (W1604)

Cmp intégré référencé

1 2
# Python 2
cmp
1 2 3 4
# Python 3
# use key function if possible, otherwise use
def cmp(x, y):
   return (y > x) - (y < x)
5. ancienne division (W1619)

Division sans instruction __future__

1 2
# Python 2
1 / 3 == 0  # True
1 2 3 4 5
# Python 3
from __future__ import division

1 // 3 == 0  # True
1 / 3 == 0.3333333333333333  # True
6. arrêt-itération-retour (R1708)

Ne déclenchez pas StopIteration dans le générateur ; utilisez plutôt l'instruction return

1 2 3 4 5
# Python 2
def gen():
   yield 1
   raise StopIteration()
   yield 2
1 2 3 4 5
# Python 3
def gen():
   yield 1
   return
   yield 2

Exécuter Python 3

1. Mettre à jour les dépendances, deuxième partie :terminer le travail

Après un certain temps, vous pouvez à nouveau rechercher des alternatives compatibles Python 3 à vos dépendances que vous n'aviez pas pu trouver auparavant.

Si vous êtes toujours vide, vous feriez mieux de vous demander si vous voulez être coincé avec un paquet non pris en charge et non maintenu. Et si le supprimer de votre base de code prendrait trop de temps, faites-en un fork et appliquez exactement le même processus. Dans le cas de la plupart des packages, une seule exécution de "python-modernize" pourrait très bien résoudre le problème.

Une fois que vous avez terminé, publiez votre fork sur PyPI pour que d'autres en bénéficient ou installez-le directement à partir du référentiel et utilisez-le de cette façon. Assurez-vous simplement de créditer l'auteur et n'oubliez pas d'inclure la licence d'origine, car elle est requise par la plupart des licences open source.

2. Dernières étapes de votre migration Python 3

À ce stade, vous êtes sur le point d'être prêt à 100 % pour Python 3. Cependant, il reste encore plusieurs étapes à franchir pour vous aider à éviter les problèmes potentiels lors du déploiement en production.

a) Intégration continue

Si vous ne le faites pas déjà, commencez à exécuter votre application sous Python 3 parallèlement à Python 2 dans votre environnement d'intégration continue. Même si les tests commencent à échouer, cela vous aidera à mesurer vos progrès et à prévenir les régressions.

Si vous ne disposez pas d'une intégration continue complète, envisagez d'utiliser tox pour les tests locaux sous plusieurs versions de Python.

b) État du cache et de l'application partagée

N'oubliez pas de vider votre cache juste avant le déploiement. Avec un changement aussi important, un état d'application autre que vide rendra le débogage beaucoup plus fastidieux.

Cela est particulièrement vrai pour les objets picklés à l'aide du module « pickle » sous Python 2 ; ils ne seront pas compatibles avec Python 3, alors assurez-vous de les supprimer ou de les recréer avant le déploiement. Sinon, votre application risque d'échouer carrément, même si elle fonctionnait parfaitement lors des tests sur un environnement de test propre.

c) Tests de régression manuels

Aussi complets que soient vos tests, vous pouvez toujours passer à côté de certaines choses, comme des différences dans la configuration ou les données traitées. Pour vous assurer que ce n'est pas le cas, une dernière vérification manuelle des régressions est indispensable avant de commencer le déploiement en production.

A côté des chemins heureux, qui sont les plus importants, pensez à tester ce qui est le plus souvent manqué, mais qui peut devenir un vrai problème lors de la mise en production. Votre application doit fonctionner correctement avec :

  1. le serveur de production WSGI (par opposition au serveur intégré en mode développement) ;
  2. les e-mails et autres moyens de communication externes qui peuvent avoir été moqués lors de la configuration de développement/test ;
  3. des données de type production ainsi qu'une base de données vide.
3. Déploiement progressif ou acte de foi

En fonction d'un certain nombre de facteurs, tels que les ressources disponibles ou votre contrat de niveau de service, vous devez envisager un déploiement progressif.

Si votre service est équilibré sur plusieurs instances de serveur, il peut être judicieux de lancer Python 3 sur une seule d'entre elles, puis de commencer à augmenter le rôle de Python 3 en fonction de votre confiance dans la migration. grandit.

C'est l'option la plus sûre, mais elle nécessite un travail supplémentaire, d'autant plus que certains artefacts, tels que le cache susmentionné, doivent être séparés dans les instances Python 2 et Python 3.

Ou... vous pouvez simplement vous lancer et déployer le tout d'un coup !

Dans tous les cas, certains bogues mineurs sont susceptibles d'apparaître, alors soyez prêt à y répondre rapidement. Un outil d'agrégation d'erreurs ou une bonne gestion de la journalisation devrait vous permettre de les résoudre au premier signe de problème en un rien de temps.

Réflexions finales

Si vous souhaitez accélérer votre migration Python 3, il est utile d'avoir quelqu'un ayant de l'expérience dans les bases de code Python 2 et Python 3.

Même si une partie substantielle du processus est automatisée, elle est encore loin d'être parfaite. Pire encore, des étapes telles que la mise à jour ou même l'échange de certaines dépendances ne peuvent pas être effectuées sans une connaissance pratique approfondie de celles-ci.

Pour cette raison, lorsqu'il s'agit d'applications plus importantes, nous vous suggérons d'embaucher des spécialistes externes si vous n'avez pas actuellement les bonnes personnes pour le travail en interne.