3 points par GN⁺ 2025-05-28 | 2 commentaires | Partager sur WhatsApp
  • Pyrefly de Meta et Ty d’Astral, deux vérificateurs de types Python basés sur Rust, ont récemment été dévoilés, affichant des performances écrasantes et un nouveau paradigme de typage face à mypy et pyright
  • Pyrefly mise sur une inférence de types agressive et l’open source, tandis que Ty introduit le principe de la « gradual guarantee » afin de minimiser l’apparition d’erreurs de type
  • Les deux outils sont encore en version alpha précoce, mais les benchmarks sur divers projets montrent que Ty enregistre globalement une vitesse d’exécution supérieure en moyenne
  • Pour l’analyse incrémentale, Pyrefly fonctionne au niveau des modules, tandis que Ty propose une granularité plus fine au niveau des fonctions, avec des différences de structure et d’usage
  • Ty met en avant un système de types innovant, avec notamment les types d’intersection et de négation, et fournit des messages d’erreur plus intuitifs et plus clairs

Présentation de Pyrefly et Ty

  • Pyrefly et Ty sont des vérificateurs de types Python développés en Rust
  • Pyrefly a été développé par Meta (ex-Facebook) et remplace Pyre, auparavant basé sur OCaml
  • Ty est développé par Astral, connue pour ses outils Python comme uv et ruff
  • Les deux projets sont publiés en open source, mais restent encore au stade alpha avant leur sortie officielle
  • Les deux équipes ont présenté leur vision, leurs objectifs et leur approche respectifs au PyCon 2025 Typing Summit

Points communs

  • Tous deux sont développés en Rust et prennent en charge l’analyse incrémentale (Incremental Checking)
  • Ils utilisent ruff pour le parsing AST du code Python
  • Ils offrent aussi une excellente intégration à l’environnement de développement, avec vérification de types en ligne de commande et prise en charge des intégrations LSP/IDE

Différence n°1 : la vitesse

Benchmark PyTorch

  • Ty est environ 2 à 3 fois plus rapide que Pyrefly, et les deux sont 10 à 20 fois plus rapides que mypy et pyright
  • Pyrefly vise un gain de performance de 35x par rapport à Pyre, et de 14x par rapport à mypy/pyright
  • Ty a été conçu avec pour objectif d’être plus rapide d’un à deux ordres de grandeur que les vérificateurs de types de la génération actuelle

Benchmark Django

  • Ty est le plus rapide, suivi de Pyrefly
  • Pyright affiche des résultats nettement plus lents

Benchmark du dépôt mypy

  • Résultat similaire : Ty est le plus rapide, suivi de près par Pyrefly
  • mypy et pyright enregistrent des temps d’exécution nettement plus lents

Différence n°2 : les objectifs de typage

Pyrefly

  • Adopte une stratégie consistant à inférer les types autant que possible afin de détecter les erreurs, même sans types explicitement indiqués dans le code
  • Vise à maximiser la robustesse du code grâce à une inférence de types plus proactive

Ty

  • Applique le principe de Gradual guarantee
  • Conçu pour qu’un code fonctionnel ne produise pas d’erreur de type si l’on retire des types explicites
  • Ne génère pas d’erreurs en l’absence d’annotations de type, et ne demande des annotations supplémentaires que lorsque c’est nécessaire
  • Exemple : même si l’on assigne une valeur à un champ sans type explicite, cela ne produit pas d’erreur de type ; le cas est traité comme Unknown | None, etc.

Différence n°3 : la méthode d’analyse incrémentale

  • Pyrefly : réanalyse uniquement les fichiers (modules) modifiés et leurs dépendances (incrémentalité au niveau du module)
  • Ty : s’appuie sur le framework Salsa de Rust pour offrir une incrémentalité fine jusqu’au niveau des fonctions
  • L’approche par module part du principe qu’elle est suffisamment rapide, tandis que l’approche par fonction peut complexifier la base de code ; il s’agit d’un choix stratégique propre à chaque outil

Différence n°4 : fonctionnalités (système de types et support)

Atouts de Pyrefly

  • Son inférence implicite de types est très puissante
  • Même sans types explicites, il analyse des types complexes comme les valeurs de retour de fonctions, les dictionnaires ou les listes afin de détecter les erreurs
  • Il a été conçu en mettant l’accent sur les problèmes de typage complexes comme les génériques, les overloads et les imports wildcard
  • Sa précision d’inférence des types génériques est meilleure que celle de Ty

Particularités de Ty

  • En raison de la « gradual guarantee », il permet des variations de type libres même en l’absence de types explicites
  • Prend en charge des innovations de système de types comme les types d’intersection (Intersection Types) et de négation (Negation Types)
  • Ses messages d’erreur sont conçus pour être très clairs et intuitifs
  • Il autorise librement l’affectation de types variés, notamment dans les listes, et introduit de façon systématique la valeur de type Unknown

Limites / état alpha

  • Les deux produits sont encore en phase alpha, avec une inférence de types ou certaines fonctionnalités encore incomplètes
  • Par exemple, certains résultats, comme l’inférence des types de listes dans Ty, manquent encore de maturité

Comparaison détaillée des fonctionnalités

Inférence implicite de types

  • Pyrefly infère activement les types de retour et les types des objets de collection, puis affiche clairement les revealed type et les erreurs
  • Ty renvoie Unknown ou @Todo lorsque l’inférence est insuffisante

Génériques

  • Pyrefly et Ty résolvent bien tous deux les problèmes courants liés aux types génériques
  • Pyrefly a l’avantage pour l’interprétation du type d’instances créées sans paramètre de type
  • Les deux vérificateurs montrent des faiblesses face aux problèmes de covariance/contravariance, comparés à mypy et pyright

Messages d’erreur

  • Ty met l’accent sur des messages d’erreur concis et faciles à lire
  • Il fournit des messages plus faciles à comprendre d’un coup d’œil que ceux de Pyrefly, mypy ou pyright

Types d’intersection / négation

  • Seul Ty prend en charge les types d’intersection (&) et de négation (~), ce qui lui permet de traiter des opérations de types complexes comme ci-dessous

    • Exemple : avec un type WithX | Other, lorsqu’un attribut x existe, Ty bifurque automatiquement vers WithX
    • Exemple : lorsqu’il ne s’agit pas d’une sous-classe spécifique, le type est interprété comme MyClass & ~MySubclass
  • Ces types d’intersection et de négation constituent des fonctionnalités très avancées en théorie des types

Autres exemples avancés

  • Ty peut aussi être utilisé, via son système de types, pour des opérations complexes comme les équations diophantiennes
  • Les tests sont rédigés en Markdown (référence : les ressources mdtest de ruff chez Astral)

Conclusion et perspectives

  • L’écosystème Python voit apparaître des vérificateurs de types nouveaux et extrêmement rapides
  • Ty fait de la stabilité progressive du typage sa stratégie principale, tandis que Pyrefly mise sur une inférence de types proactive
  • Les deux outils en sont encore à leurs débuts, et leurs fonctionnalités ont encore une large marge de convergence ou d’évolution
  • Il est possible de les essayer sur leurs sites officiels, et des plugins sont aussi proposés pour des éditeurs majeurs comme VSCode et Cursor
  • Une rumeur évoque également l’open source à venir, par Google, d’un vérificateur de types basé sur Go, ce qui pourrait encore enrichir le domaine de l’analyse de types pour Python

Utilisation / références

  • Pyrefly: pyrefly.org/sandbox
  • Ty: play.ty.dev
  • Le Ty d’Astral utilise des tests basés sur Markdown (pour le chemin détaillé, voir mdtest dans le dépôt ruff)
  • La documentation officielle, les plugins d’éditeur et les commandes d’installation des paquets sont également fournis

2 commentaires

 
q8840 2025-05-29

On dirait qu'avec ty, si le type de retour n'est pas indiqué sur une fonction utilisée, c'est automatiquement unknown ; il ne le vérifie qu'une fois enregistré.
Pyrefly, lui, l'infère même si ce n'est pas indiqué, et le vérifie aussi pendant la saisie.

 
GN⁺ 2025-05-28
Avis Hacker News
  • Un développeur de ty se dit heureux de voir ty et pyrefly attirer de plus en plus l’attention, tout en rappelant une nouvelle fois que les deux projets sont encore loin d’être terminés ; certains exemples problématiques viennent simplement de fonctionnalités non encore implémentées, donc si quelque chose semble « étrange », il faut garder à l’esprit que ce n’est peut-être tout simplement pas encore développé ; il faut aussi reconnaître que Python est un langage immense et très varié

    • Quelqu’un dit beaucoup aimer la façon dont ty fait ses tests au format markdown : le fait que les tests servent aussi de documentation est une excellente idée ; il se demande si cette approche s’inspire des exemples de code documentés de Rust

    • Le fait de marquer les parties révélant les types avec @TODO l’a fait rire, mais en y réfléchissant, il trouve cela assez malin et utile

    • Du point de vue de quelqu’un ayant de l’expérience en TypeScript, les expérimentations autour de l’inférence de types, du type narrowing et des différences de comportement entre les type checkers Python sont intéressantes ; il estime qu’il manque toujours un type checker à la fois rapide et fiable, et que Python est très en retard sur ce point ; selon lui, un type checker devrait améliorer la productivité et la fiabilité du code, et il soutient donc ce genre de projets

    • Du point de vue d’un développeur Rust, quelqu’un pose la question d’un « langage de script pour Rust » : existe-t-il un réseau ou des travaux de recherche sur un langage dont la syntaxe s’accorderait bien avec Rust, qui pourrait importer nativement des types Rust et compiler rapidement avec hot reload ? Il demande aussi si Python pourrait éventuellement remplir ce rôle, même avec une syntaxe différente ; lien associé https://news.ycombinator.com/item?id=44050222

  • Avis extérieur de quelqu’un ayant peu d’expérience avec Python : si l’on s’intéresse aux type hints, il recommande de lire ce post Reddit https://www.reddit.com/r/Python/comments/10zdidm/why_type_hinting_sucks/ ; il précise qu’il ne faut pas le prendre trop au sérieux, mais insiste sur le fait que même avec d’excellents outils de typage, les « bonnes pratiques » passent d’abord ; il prend pour exemple Django ou Meta, où l’on ne peut obtenir un usage cohérent et un typage strict sur de très grandes bases de code qu’en imposant aux développeurs certaines conventions ; selon lui, Python, comme C++, a trop de fonctionnalités et un runtime trop permissif, si bien qu’il faut au final n’en utiliser qu’un sous-ensemble pour garder les choses gérables ; mais ce sous-ensemble peut varier selon les personnes et les objectifs ; il compare cela aux frictions entre développeurs Rust, plus attachés à un système de types strict, et les mainteneurs du noyau Linux

    • Dans les commentaires les mieux classés de ce post Reddit, certains balaient le débat d’un « il suffit d’utiliser Any » ; un autre répond que dans des cas réels, des déclarations de type plus explicites permettraient d’éviter en amont des erreurs liées à de futurs changements dans les fonctions d’une bibliothèque ou à des valeurs d’entrée inattendues ; il affirme avec force que le type checking est indispensable pour qu’un code Python reste maintenable et fiable

    • Conclusion avancée par certains : plutôt que de consacrer trop de temps et d’efforts au type checking Python, il vaudrait mieux migrer vers un langage statiquement typé plus adapté, puis n’utiliser Python qu’au besoin via une couche d’interop ; ce n’est pas toujours possible, mais ils estiment que vouloir à tout prix faire rentrer Python dans ce moule fait perdre beaucoup de temps

    • Critique de fonctionnalités Python puissantes et complexes comme les metaclasses, les descripteurs, l’usage de __call__, object.__new__, le name mangling ou self.__dict__, jugées trop « magiques » et nuisibles à la lisibilité du code ; l’intervenant déclare personnellement qu’il préfère ne pas utiliser ce genre de choses

    • Quelqu’un se demande d’où vient cette habitude de donner des avis sans réellement utiliser le langage concerné ; les développeurs Python ont une compréhension profonde du langage par la pratique, et il trouve curieux que des non-utilisateurs le critiquent sur la base d’arguments extérieurs ; il pointe aussi une tendance à débattre à partir de cas artificiels

    • De l’avis d’une personne utilisant Python depuis de nombreuses années, la plus grosse erreur est tout simplement de ne pas utiliser du tout les type hints ni les type checkers

  • L’idée de « garantie graduelle » de ty intrigue certains : retirer une annotation de type ne devrait jamais provoquer d’erreur de type, ce qui leur semble particulièrement bien adapté à Python, où le code dynamique est courant

    • D’autres rappellent que le typage graduel signifie qu’il peut y avoir du any partout dans le code sans même déclencher d’avertissement, y compris dans des parties importantes qui ne bénéficient donc pas d’une réelle sûreté de type ; selon leur expérience avec mypy, c’était un défaut majeur, et il faudrait absolument une façon de déclarer « ce fichier est vérifié en typage statique complet » ; à leurs yeux, le typage « graduel » ressemble plutôt à un anti-pattern, et le terme « soft typing » serait peut-être plus approprié

    • Un autre point de vue soutient que sur une base de code existante, il n’y a pas vraiment d’alternative au typage graduel ; d’après une expérience concrète d’ajout de type hints avec mypy sur plusieurs bases Python legacy, l’opt-in au niveau du module est l’approche la plus raisonnable ; si pyrefly ne le prend pas en charge, son utilité pratique serait limitée ; en revanche, dans la perspective de génération de code par LLM, un type checker très rapide et strict aurait une vraie utilité

    • Certains y voient une situation comparable aux débuts de TypeScript : il faut privilégier une adoption progressive dans de grands projets existants, puis activer petit à petit des options comme noImplicitAny ou strict module par module jusqu’à obtenir un environnement de vérification fort

    • Même du point de vue d’un programmeur Rust, la « garantie graduelle » semble l’approche la plus raisonnable

    • D’autres disent ne pas être particulièrement attirés par ce mode de prise en charge du typage graduel ; puisque le système de typage dynamique de Python est jugé peu sûr, la moitié de l’intérêt des annotations de type consiste précisément à en contrôler les dysfonctionnements ; ils souhaitent donc impérativement des options comme no-implicit-any ou un mode strict

  • Les outils d’Astral apportent une énergie nouvelle à l’écosystème Python, mais certains s’interrogent sur leur vision à long terme : seront-ils intégrés un jour à Python lui-même ? Auront-ils disparu d’ici cinq ans ? Ou y aura-t-il un rug pull sous forme d’abonnement ?

    • Avec une licence de type Business Source, Astral pourrait facilement pousser vers un abonnement entreprise obligatoire pour les déploiements en production utilisant ses outils ; les produits actuels ne sont pas exactement conçus pour cela, mais du point de vue d’un investisseur en capital-risque, un modèle proche semblerait logique

    • Dans ses annonces officielles, Astral indique explicitement vouloir vendre divers services au-dessus de ses outils ; lien de référence https://astral.sh/blog/announcing-astral-the-company-behind-ruff

    • D’autres rappellent que cette inquiétude ne vaut pas seulement pour Astral mais pour tous les projets, et avertissent en particulier que l’outillage de Facebook présente souvent un risque d’abandon avec le temps ; au bout du compte, les utilisateurs doivent toujours assumer eux-mêmes le risque

    • Citation d’un avis lu sur Reddit : le modèle de base du capital-risque consiste souvent soit à espérer un rachat par un FAANG, soit à faire grossir l’entreprise de façon suffisamment agressive pour viser un acqui-hire ; Astral pourrait donc aussi suivre un scénario de fusion-acquisition avec absorption des talents

    • Il circule aussi des rumeurs selon lesquelles Astral préparerait des outils destinés aux grandes entreprises, comme un registry privé de packages hébergé

  • À propos de l’exemple my_list = [1, 2, 3], certains reprochent à ty d’autoriser my_list.append("foo") sans annotation explicite, alors que mypy, pyrefly et pyright le signalent comme erreur de type ; ils affirment qu’en pratique on utilise presque toujours des listes homogènes et qu’un type checker devrait partir de cette hypothèse ; le fait que Python l’autorise ne devrait pas conduire à relâcher la vérification de types ; certains y voient une politique pensée pour du code de débutant

    • Un développeur de ty répond que « l’inférence de type pour les littéraux de liste n’est pas encore terminée » : pour l’instant, l’outil n’utilise que list[Unknown], où Unknown est un type graduel proche de Any, ce qui rend tous les append acceptables ; une inférence plus précise est prévue plus tard, avec un lien vers l’issue correspondante https://github.com/astral-sh/ty/issues/168

    • D’autres expliquent que ce n’est pas tant une optimisation pour débutants qu’une nécessité pour rester compatible avec du code legacy ; pour introduire un type checker dans une grande base non typée, il faut que l’existant continue à fonctionner autant que possible afin de limiter le coût d’adoption

    • Contre-argument : « ignorer ce que Python autorise pour fabriquer un outil selon ses préférences personnelles n’est pas convaincant »

    • Certains voient dans l’approche de pyrefly un problème pour les grandes bases de code non typées : une adoption globale serait difficile car il faudrait modifier beaucoup de code, ce qui est compliqué sans adhésion organisationnelle ; cela peut fonctionner chez Meta, où l’on peut l’imposer en interne, mais pour une adoption progressive, une approche plus permissive comme celle de ty paraît plus réaliste ; en même temps, certains disent préférer personnellement des outils qui avertissent sur les types mixtes

    • Autre avis : « si c’est du code Python exécutable, alors il est normal qu’il n’y ait pas d’erreur de type tant qu’on n’a pas explicitement restreint les types » ; si l’on veut un sous-ensemble statique plus strict, il suffit d’ajouter soi-même des annotations de type

  • Des utilisateurs estiment que l’approche de Pyrefly, plus ambitieuse sur l’inférence de types, demande bien moins d’annotations sur de grandes bases de code réellement sûres du point de vue des types ; même si l’adoption initiale est plus difficile, elle serait plus efficace à long terme ; à leurs yeux, ty revient en pratique à un noImplicitAny désactivé

  • Certains espèrent un type checker avec une vraie prise en charge des notebooks et du live coding : pouvoir détecter statiquement des erreurs avant d’exécuter de longues cellules serait un gain énorme en efficacité

    • Quelqu’un demande si d’autres ont utilisé les notebooks Jupyter dans VSCode, en faisant remarquer que l’application de type checkers comme pylance peut parfois gêner le code exploratoire

    • Réponse : l’expérience offerte par le Language Server de VSCode, avec intégration des notebooks et retours immédiats en live coding, est justement recommandée comme solution à ce besoin de type checking interactif

  • Certains trouvent la conception de Pyrefly plus raisonnable parce qu’elle ressemble davantage à l’inférence de types de TypeScript, tout en estimant qu’une adoption graduelle au niveau du module est idéale ; aller jusqu’au niveau de la fonction leur semble trop fin et pas vraiment nécessaire ; du point de vue des performances aussi, le niveau module leur paraît suffisant

  • D’autres pensent que, même dans des projets très dynamiques, ils préféreraient une inférence de types plus forte comme celle de Pyrefly, quitte à accepter les contraintes que cela impose

  • Certains utilisent actuellement basedpyright dans leur IDE et en CI, et se disent globalement satisfaits de sa stabilité ; à l’inverse, ils n’aiment pas mypy, qu’ils jugent souvent défaillant même sur des tâches de typage simples