Cet article est la traduction d'un article écrit par Tim Abbott le jeudi 13 octobre 2016.
Cet article est un article traduit ** non officiel ** (nous avons confirmé que la traduction sera publiée à l'auteur Tim Abbott). Tim Abbott et Dropbox n'assument aucune responsabilité quant au contenu de cet article.
Si vous avez des erreurs de traduction, veuillez m'envoyer une demande de modification.
Merci d'avoir amélioré ma mauvaise traduction!
13 octobre 2016
— Tim Abbott
Au cours des dernières années, des vérificateurs statiques ont été utilisés en PHP (Hack) et JavaScript (Flow et [TypeScript](https: /). Il est devenu disponible dans les langages populaires à typage dynamique tels que /www.typescriptlang.org/)) et est de plus en plus largement adopté. Il y a deux ans, la Syntaxe temporaire pour les annotations de type statique a été ajoutée à Python 3. Cependant, les types statiques en Python ne sont pas encore largement adoptés. La raison en est que l'outil de vérification des annotations de type mypy n'était pas d'une qualité qui pouvait être utilisée en production. Mais c'est l'histoire jusqu'à présent!
Il y a des nouvelles intéressantes de l'année dernière. Une équipe de Dropbox (y compris Guido van Rossum, le créateur de Python!) A travaillé sur mypy pour bien fonctionner en tant que vérificateur de type qui apporte l'intégrité de type statique aux programmes Python. Il y a des nouvelles encore plus intéressantes pour de nombreux développeurs avec de grandes bases de code Python 2. mypy prend également pleinement en charge la vérification du type de programme Python 2, peut prendre en charge de grandes bases de code Python et l'utilisation de mypy simplifie considérablement la mise à niveau vers Python 3.
Tout au long de 2016, la communauté de développement de Zulip a été témoin de ces avantages pour mypy. Zulip est une application de discussion de groupe open source populaire. Il propose des applications pour toutes les principales plates-formes, des API REST et de nombreux outils d'extension. Pour vous aider à comprendre l'échelle, Zulip est un produit en Python 2 avec environ 50000 lignes et des centaines de commits par des dizaines de développeurs chaque mois. Tout au long de 2016, nous avons des annotations de type 100% statique avec mypy sur le backend (!). Et, grâce à mypy, je suis sur le point de passer à Python 3. Zulip est maintenant le plus grand projet Python open source avec des types entièrement statiques. Cependant, je suis sceptique quant à savoir si je peux conserver ce titre pendant longtemps à l'avenir :)
Dans cet article, je vais vous expliquer comment fonctionne mypy, les avantages et les douleurs que nous avons ressentis avec mypy. Et partagez un guide détaillé sur l'adoption de mypy pour les grandes bases de code en production (trouver et résoudre des dizaines de défis pour les grands projets qui se produisent dans les premiers jours d'utilisation de mypy. Y compris les méthodes!).
Voici un bref exemple de la syntaxe d'annotation pour mypy / PEP-484 en Python 3.
def sum_and_stringify(nums: List[int]) -> str:
"""Adds up the numbers in a list and returns the result as a string."""
return str(sum(nums))
Et je vais vous montrer à quoi ressemble le même code avec la syntaxe de commentaire disponible dans Python 2 et 3.
def sum_and_stringify(nums):
# type: (List[int]) -> str
"""Adds up the numbers in a list and returns the result as a string."""
return str(sum(nums))
Avec cette syntaxe de commentaire, mypy prend en charge la vérification régulière du type de programme Python 2. Et les programmes annotés avec mypy fonctionneront normalement dans n'importe quel environnement d'exécution Python (cette grande propriété de mypy est également commune au vérificateur JavaScript Flow). Ceci est incroyable. Cela signifie que vous pouvez adopter mypy pour votre projet sans changer la façon dont Python s'exécute.
L'exécution de mypy comme linter imprime une erreur dans un format sophistiqué de style compilateur. Par exemple, si vous annotez par erreur que sum_and_stringify
renvoie un float, mypy retournera une sortie similaire à ce qui suit:
$ mypy /tmp/test.py
/tmp/test.py: note: In function "sum_and_stringify":
/tmp/test.py:6: error: Incompatible return value type: expected builtins.float, got builtins.str
Si vous êtes intéressé par la façon d'annoter feuille de triche de syntaxe mypy (utilisation simple) et [PEP-484](https: // Consultez www.python.org/dev/peps/pep-0484/) (pour des utilisations complexes). Ce sont d'excellents documents. Si vous voulez essayer mypy maintenant, vous pouvez l'installer avec pip3 install mypy-lang
.
Lorsque mypy a également des annotations de type complet sur les modules et leurs packages dépendants, vous obtenez une fonction de vérification de cohérence très puissante. C'est similaire à ce que le compilateur obtient dans un langage typé statiquement. mypy utilise typehed, qui est un référentiel de type "stub" (stub: définition de type de module de style de fichier d'en-tête), bibliothèque standard Python, requêtes, six et Il fournit des informations de type pour des dizaines de bibliothèques populaires telles que sqlalchemy. Surtout, mypy est conçu pour ajouter progressivement des types. Si les informations de type de celui importé ne sont pas disponibles, elles sont simplement traitées comme cohérentes avec n'importe quel type.
Voici quelques-uns des avantages que nous avons trouvés avec mypy. Nous ramasserons les plus importants dans l'ordre.
List
ou Tuple
) se démarque vraiment.Je pense qu'il est également important de parler de la douleur de l'utilisation de mypy aujourd'hui pour donner une image complète de l'expérience de l'adoption de mypy.
(qui sera bientôt plus explicite ʻif typing.TYPE_CHECKING
). Mais cela ne fonctionne pas lors de la migration vers la syntaxe Python 3. J'espère que quelqu'un trouvera une bonne solution au problème qui m'a obligé à créer cet import circulaire. La solution peut simplement être une configuration recommandée de votre code pour éviter ce problème.Dans cette section, je crains que cela puisse être un problème (avant d'essayer mypy), mais je vais regarder en arrière après avoir adopté mypy et considérer ce que je ne pense pas être un gros problème.
type: ignore
qui ignore les faux positifs pour obtenir une sortie sans erreur. Et enfin, là où il existe de nombreuses parties dynamiques de notre système (par exemple Framework pour l'analyse des requêtes API REST Heureusement, même request-variables)) a été tapé avec succès.type: ignore
et taper annoter notre code plutôt que signaler des bogues. J'ai l'impression d'avoir pris le temps.Cette section détaille ce que vous devez faire pour pouvoir bénéficier de l'utilisation de mypy dans une grande base de code. Pour vous donner une idée de l'ampleur du travail nécessaire, cette section a écrit tout ce que j'ai fait pendant le hackathon de quatre jours en janvier (bien que mypy n'ait pas été mature à l'époque, j'ai donc passé la moitié de mon temps moi-même. Je suis allé écrire un rapport de bogue approprié sur le bogue que j'ai trouvé). Si vous envisagez d'utiliser mypy mais souhaitez plus d'informations pour prendre cette décision, je vous recommande de suivre toutes les étapes décrites dans cette section. Cela vaut bien l'effort que vous avez payé.
** Lire la feuille de triche mypy. ** La feuille de triche mypy (http://mypy.readthedocs.io/en/latest/cheat_sheet.html) fournit un aperçu clair de la syntaxe PEP-484. Et vous y ferez souvent référence lorsque vous commencerez à écrire des annotations de type.
** Standardisez la manière dont mypy est exécuté. ** Installez mypy
sur votre base de code (https://github.com/zulip/zulip/blob/master/tools/install-mypy) et exécutez (https: // github.com/zulip/zulip/blob/master/tools/run-mypy) Créez un outil pour le faire. Assurez-vous que tous les membres du projet peuvent exécuter le vérificateur de type de la même manière. Deux fonctionnalités sont importantes pour exécuter mypy.
mypy --py2 --silent-importations --fast-parser -i <chemin>
. Vous devriez pouvoir faire de même avec le fichier mypy.ini.Évitez de recevoir une erreur lorsque vous ** exécutez ** mypy sur votre base de code. Vous devez généralement ajouter des annotations de type à la structure de données vide globale. Vers janvier, ce processus a pris 2-3 heures (y compris le temps de rapporter un bogue qui a écrit comment le reproduire). Probablement beaucoup moins de temps de travail maintenant. Par défaut, mypy ne vérifie que les fonctions annotées. C'est pourquoi les bases de code non annotées vous permettent d'abord d'analyser l'intégralité de la base de code mypy.
** Vérifiez l'intégrité de base. ** Ajoutez --check-untyped-defs
à l'argument de mypy. Et assurez-vous que vous n'obtenez pas d'erreur lorsque vous exécutez mypy sur cette base de code. Cette option oblige mypy à vérifier l'intégrité interne de tous les def
s dans la base de code. En d'autres termes, mypy détecte de nombreux bugs et erreurs dans la base de code même si aucune annotation de type n'est écrite.
Dans de nombreux cas, vous voudrez corriger des bogues et du code terrible, mais vous pouvez également utiliser l'annotation # type: ignore
ou exclure des fichiers pour reporter le problème. Par exemple, nous avons d'abord exclu tous les tests Zulip. C'est parce que cela ne vaut pas la peine d'être tapé et qu'il y avait beaucoup de correctifs de singe et de scripts Python suspects. Dans Zulip, j'ai passé environ deux jours à travailler dur pour effacer l'erreur de la sortie de --check-untyped-defs
et fusionné dans la base de code de Zulip pour résoudre environ 40 problèmes.
J'ai passé un jour ou deux à essayer de trouver un bon moyen de reproduire le bug mypy que j'ai rencontré et d'améliorer le typage. Mypy n'est plus dans son développement initial et il est plus rare de rencontrer des bugs dans mypy. Cependant, vous devez vous attendre à ce que dans les grands projets, vous rencontriez des bogues et corrigiez les bogues typés (envoyez simplement un PR!).
** Exécutez mypy avec intégration continue. ** Une fois que votre base de code passe mypy --check-untyped-defs
, c'est une bonne idée d'exécuter un vérificateur de type pour mypy
dans votre environnement CI pour conclure votre progression.
L'annotation de type de mypy est facultative. Une fois que vous avez terminé les étapes de configuration ci-dessus, vous pouvez annoter votre base de code à votre propre rythme. Au fil du temps, vous bénéficierez de types statiques dans les parties annotées de votre base de code. Vous n'avez rien à faire de spécial pour le reste de la base de code (la merveille de la frappe progressive!). Dans la section suivante, nous examinerons les stratégies pour obtenir la base de code entièrement annotée.
Dans cette section, nous verrons ce qu'il faut pour obtenir des annotations de type dans votre base de code à partir du moment où vous avez configuré mypy.
L'avantage de mypy est que vous pouvez effectuer tout le travail de manière progressive. Après la configuration initiale, nous n'avons rien fait pendant 2-3 mois. Le changement s'est produit lorsque nous avons présenté l'annotation de type de mypy comme l'un de nos projets Google Summer of Code (GSOC). Dans ce projet, nous avons rencontré une merveilleuse étudiante nommée Eklavya Sharma. Eklavya a fait la plupart du travail acharné pour annoter Zulip. Il a mis à jour nos outils, annoté la bibliothèque de base, contribué aux rapports de bogues et aux relations publiques en amont de mypy et typé, et a corrigé toutes les erreurs que nous avions commises au début. fait. Étonnamment, il a également migré Zulip pour utiliser virtualenv cet été-là et mis à niveau Zulip vers Python 3!
La tâche d'annoter un grand projet peut être divisée en plusieurs phases.
** Phase 1: annoter la bibliothèque principale. ** Stratégiquement, vous voudrez d'abord annoter le code dans les bibliothèques de base qui sont utilisées partout dans d'autres fichiers. Les annotations de type pour ces fonctions imposent des contraintes sur les types utilisés ailleurs dans le code. En conséquence, si vous travaillez d'abord sur ces fichiers, vous passerez moins de temps à corriger les annotations incorrectes et à détecter plus rapidement les vrais bogues. De plus, cette phase rédige de la documentation sur comment le projet utilise mypy (et sur l'échec de mypy dans le système CI). (Lien vers la documentation) C'est aussi une bonne opportunité.
** Phase 2: annoter la plupart de la base de code. ** De nombreux projets prendront probablement des mois aux développeurs pour travailler lentement sur différentes parties de la base de code. C'est une stratégie très rationnelle.
Cela fonctionne également bien pour se concentrer sur l'annotation de la base de code. Il serait utile de parler de la façon dont Zulip a fait ce travail. Environ la moitié de l'été de code d'Eklavya, nous visions à annoter Zulip autant que possible et nous PyCon Sprint. PyCon Sprint est mon événement préféré à PyCon. C'est le meilleur rallye de quatre jours après la conférence centrale PyCon. Là, des centaines de développeurs travaillent ensemble sur des projets open source. C'est une excellente opportunité d'être totalement libre de participer et de contribuer à des projets open source.
Nous avons réservé une table à côté des développeurs mypy et nous nous sommes ajustés pour attirer à tour de rôle 5 à 10 développeurs dans le projet d'annotation mypy de Zulip chaque jour. Au cours du sprint PyCon, le pourcentage de Zulip annoté est passé de 17% à 85% (25-30 ingénieurs travaillent quotidiennement, dont la plupart sont inexpérimentés en Zulip et mypy. fait) . Nous avons utilisé le support de couverture de mypy et coveralls.io pour suivre les progrès, mais la barre de progression sur une grande feuille de papier est plus intéressante. Cela a été pris au début du dernier jour.
Je pense que notre expérience avec PyCon a clairement prouvé que mypy est facile à travailler avec de nouveaux développeurs. À l'exception de moi, tous les contributeurs qui ont ajouté des annotations n'avaient pas d'expérience avec Zulip et mypy. Avec la bonne démo de 5 minutes et une bonne documentation, nous avons constaté que les nouveaux contributeurs travaillent efficacement dans l'heure suivant le début de leur contact avec mypy. Je recommande avec confiance cette approche mypy hackason pour d'autres projets open source. Cette excellente approche peut avoir un impact significatif sur les contributeurs, même sur des projets inconnus.
** Phase 3: 100%. ** Annoter les derniers fichiers est une tâche plus difficile qu'auparavant. La raison en est que cette phase déboguera toutes les erreurs que vous avez commises lors de la phase 2. En faisant cela, il est important de nettoyer jusqu'à 100% des fichiers et répertoires, c'est pourquoi l'indicateur mypy
a l'option --disallow-untyped-defs
(avec des annotations de type). Evitons la régression en ajoutant (rapporter des fonctions qui ne le sont pas).
Eklavya a réussi 85% à 96% avant la réouverture de l'université. Après cela, nous avons fait 2-3 heures de travail il y a quelques semaines pour atteindre 100%. Tout le nouveau code Python ajouté à Zulip est maintenant annoté avec mypy (bien qu'avec un nombre réduit, à l'exception de certains scripts, paramètres et fichiers de test).
** Phase 4: Célébrez et rédigez un article de blog! ** Au moins, c'était la prochaine étape pour Zulip :)
Dans l'ensemble, c'est le hackathon d'une semaine, le projet GSOC et le rassemblement de sprint PyCon qui ont conduit à l'annotation complète de Zulip pendant le travail intensif. Bien sûr, c'est un effort insignifiant.
Je dois dire que bien que Zulip soit annoté à 100%, le voyage mypy de Zulip n'est pas encore terminé. Finalement, nous voulons ajouter un stub à la typographie pour les bibliothèques les plus importantes utilisées par Zulip (par exemple Django).
Il existe des recommandations qui peuvent vous faire gagner du temps lors de l'annotation.
str
ou Text
. Les erreurs octets ou str et str ou unicode représentent la plupart des problèmes qui se produisent lors de la migration d'une base de code de Python 2 vers Python 2 + 3. Si vous effectuez correctement la migration tout en annotant votre base de code, vous gagnerez beaucoup de temps lors de la mise à niveau vers Python 3. Nous avons constaté que la mise à niveau vers Python 3 est très rapide lorsque la majeure partie de la base de code est annotée. Finalement, nous avons [plusieurs fonctions d'assistance](https: :) pour transtyper correctement (et lisibles!) Entre str
, Text
et bytes
en Python 2 et 3 dans notre base de code. //github.com/zulip/zulip/blob/master/zerver/lib/str_utils.py) a été ajouté.type: ignore
pour contourner les bogues potentiels mypy et typés, nous vous recommandons d'utiliser le style suivant pour consigner le problème GitHub sous-jacent:bad_code # type: ignore # https://github.com/python/typeshed/issues/372
Cette méthode permet de voir facilement si les problèmes qui ont été évités avec type: ignore
à l'avenir ont été résolus en amont. Si vous avez besoin d'ajouter beaucoup d'annotations type: ignore
à un fichier, vous pouvez l'ajouter à la liste d'exclusion (une fonctionnalité de notre wrapper run-mypy
) et la reporter. ..
Tout au long, l'expérience avec mypy (et le système de type PEP-484) a été formidable. Et nous pensons que l'adoption de mypy est un grand pas en avant pour le projet Zulip. mypy améliore la lisibilité, détecte les bogues sans exécution, a très peu de faux positifs et n'a pas d'inconvénients majeurs. Tirer parti de mypy dans une large base de code était un investissement relativement faible dans notre projet. De plus, l'annotation de la base de code présente l'avantage supplémentaire de faciliter la transition vers Python 3.
Si vous avez une grande base de code Python et que vous souhaitez améliorer votre base de code, vous devriez vous donner une semaine pour commencer à utiliser mypy!
Enfin, si vous êtes curieux de savoir à quoi ressemblent les types statiques Python dans une grande base de code, consultez le projet de serveur Zulip sur GitHub (https://github.com/zulip/zulip/). .. Nous souhaitons la bienvenue aux nouveaux contributeurs!
Un merci spécial à Guido van Rossum, Alya Abbott, Steve Howell, Jason Chen, Eklavya Sharma, Anurag Goel et Joshua Simmons pour leurs commentaires sur ce billet de blog.
Tim Abbott est le développeur principal du projet open source Zulip. Il était le CTO de Ksplice (avant d'être racheté par Dropbox) et plus tard de Zulip.
San Francisco https://zulip.org
Recommended Posts