Les types fantômes pour Python vous aideront à rendre les états illégaux non représentables et à éviter l'analyse de fusil de chasse en vous permettant de pratiquer "analyse, ne validez pas".
$ python3 -m pip install phantom-typesIl existe quelques extras disponibles qui peuvent être utilisés pour activer une fonctionnalité ou installer une version compatible d'une bibliothèque tierce.
| Nom supplémentaire | Fonctionnalité |
|---|---|
[dateutil] | Installe Python-Dateutil. Requis pour l'analyse des cordes avec TZAware et TZNaive . |
[phonenumbers] | Installe des phonénimbers. Requis pour utiliser phantom.ext.phonenumbers . |
[pydantic] | Installe Pyndantique. |
[hypothesis] | Installe l'hypothèse. |
[all] | Installe tout ce qui précède. |
$ python3 -m pip install phantom-types[all]En introduisant un type fantôme, nous pouvons définir une condition préalable à un argument de fonction.
from phantom import Phantom
from phantom . predicates . collection import contained
class Name ( str , Phantom , predicate = contained ({ "Jane" , "Joe" })): ...
def greet ( name : Name ):
print ( f"Hello { name } !" )Maintenant, ce sera un appel valide.
greet ( Name . parse ( "Jane" ))... Et cela aussi.
joe = "Joe"
assert isinstance ( joe , Name )
greet ( joe )Mais cela donnera une erreur de vérification de type statique.
greet ( "bird" ) Pour être clair, la raison pour laquelle le premier exemple passe n'est pas parce que le vérificateur de type connaît comme par magie notre prédicat, mais parce que nous avons fourni le vérificateur de type avec des preuves via l' assert . Tout le type de damier, c'est que l'exécution ne peut pas continuer à exécuter après l'affirmation, à moins que la variable ne soit un Name . Si nous déplaçons les appels comme dans l'exemple ci-dessous, le vérificateur de type donnerait une erreur pour l'appel greet() .
joe = "Joe"
greet ( joe )
assert isinstance ( joe , Name )En combinant des types de fantômes avec un vérificateur de type d'exécution comme BearType ou Typeguard, nous pouvons atteindre le même niveau de sécurité que vous obtiendrez des contrats.
import datetime
from beartype import beartype
from phantom . datetime import TZAware
@ beartype
def soon ( dt : TZAware ) -> TZAware :
return dt + datetime . timedelta ( seconds = 10 ) La fonction soon validera désormais que son argument et sa valeur de retour sont conscients du fuseau horaire, par exemple les conditions pré et post.
Les types fantômes sont prêts à l'emploi avec Pyndantic et ont intégré le support hors de la boîte. Les sous-classes de Phantom travaillent à la fois avec la validation de Pydantique et sa génération de schéma.
class Name ( str , Phantom , predicate = contained ({ "Jane" , "Joe" })):
@ classmethod
def __schema__ ( cls ) -> Schema :
return super (). __schema__ () | {
"description" : "Either Jane or Joe" ,
"format" : "custom-name" ,
}
class Person ( BaseModel ):
name : Name
created : TZAware
print ( json . dumps ( Person . schema (), indent = 2 ))Le code ci-dessus produit le jsonschema suivant.
{
"title" : " Person " ,
"type" : " object " ,
"properties" : {
"name" : {
"title" : " Name " ,
"description" : " Either Jane or Joe " ,
"format" : " custom-name " ,
"type" : " string "
},
"created" : {
"title" : " TZAware " ,
"description" : " A date-time with timezone data. " ,
"type" : " string " ,
"format" : " date-time "
}
},
"required" : [ " name " , " created " ]
}Installez les exigences de développement, de préférence dans un virtualenv:
$ python3 -m pip install .[all,test,type-check]Exécutez des tests:
$ pytest
# or
$ make testExécuter le vérificateur de type:
$ mypyLes linceurs et les formateurs sont configurés avec l'oie, après l'avoir installé, vous pouvez l'exécuter en tant que:
# run all checks
$ goose run --select=all
# or just a single hook
$ goose run mypy --select=allEn plus de la vérification des types statiques, le projet est configuré avec des plugins pytest-mypy-plagins pour tester que les types mypy exposés fonctionnent comme prévu, ces vérifications s'exécuteront avec le reste de la suite de tests, mais vous pouvez les distinguer avec la commande suivante.
$ make test-typing