Los tipos de fantasma para Python lo ayudarán a que los estados ilegales no sean representables y eviten el análisis de la escopeta permitiéndole practicar "analizar, no validar".
$ python3 -m pip install phantom-typesHay algunos extras disponibles que se pueden usar para habilitar una función o instalar una versión compatible de una biblioteca de terceros.
| Nombre extra | Característica |
|---|---|
[dateutil] | Instala Python-DateUtil. Requerido para el análisis de las cuerdas con TZAware y TZNaive . |
[phonenumbers] | Instala fonenumbres. Requerido para usar phantom.ext.phonenumbers . |
[pydantic] | Instala Pydantic. |
[hypothesis] | Instala hipótesis. |
[all] | Instala todo lo anterior. |
$ python3 -m pip install phantom-types[all]Al introducir un tipo fantasma, podemos definir una condición previa para un argumento de función.
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 } !" )Ahora esta será una llamada válida.
greet ( Name . parse ( "Jane" ))... y también lo hará esto.
joe = "Joe"
assert isinstance ( joe , Name )
greet ( joe )Pero esto producirá un error de verificación de tipo estático.
greet ( "bird" ) Para ser claros, la razón por la que pasa el primer ejemplo no es porque el comprobador de tipo de alguna manera conoce mágicamente sobre nuestro predicado, sino porque proporcionamos el verificador de tipos con prueba a través de la assert . Todo el tipo de verificador de tipo es que el tiempo de ejecución no puede continuar ejecutando más allá de la afirmación, a menos que la variable sea un Name . Si movemos las llamadas como en el ejemplo a continuación, el comprobador de tipo daría un error para la llamada greet() .
joe = "Joe"
greet ( joe )
assert isinstance ( joe , Name )Al combinar los tipos de fantasma con un verificador de tipo de tiempo de ejecución como Beartype o Typeguard, podemos lograr el mismo nivel de seguridad que ganar al usar contratos.
import datetime
from beartype import beartype
from phantom . datetime import TZAware
@ beartype
def soon ( dt : TZAware ) -> TZAware :
return dt + datetime . timedelta ( seconds = 10 ) La función soon validará que tanto su argumento como su valor de retorno son conscientes de la zona horaria, por ejemplo, condiciones previas y postales.
Los tipos de fantasma están listos para usar con Pydantic y tienen soporte integrado fuera de la caja. Las subclases de Phantom funcionan con la validación de Pydantic y su generación de esquemas.
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 ))El código anterior genera el siguiente JSonschema.
{
"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 " ]
}Instalación de requisitos de desarrollo, preferiblemente en VirtualEnv:
$ python3 -m pip install .[all,test,type-check]Ejecutar pruebas:
$ pytest
# or
$ make testCamplor de tipo Ejecutar:
$ mypyLos revestimientos y los formateros están configurados con ganso, después de instalarlo, puede ejecutarlo como:
# run all checks
$ goose run --select=all
# or just a single hook
$ goose run mypy --select=allAdemás de la verificación de tipo estático, el proyecto está configurado con pytest-mypy-plugins para probar que los tipos de mypy expuestos funcionan como se esperaba, estas verificaciones se ejecutarán junto con el resto del conjunto de pruebas, pero puede destacarlos con el siguiente comando.
$ make test-typing