Como você já sabe, eu amo a digitação estática opcional. O fato é que, às vezes, não é opcional, mas impossível. Porque temos muitos projetos grandes e não tipados no ecossistema do Python.
Django e Django-Rest-Framework eram dois deles. Foram. Porque agora eles podem ser digitados! Deixe-me apresentar a organização e stubs do drf
django
para django
e drf
.
Este será um tutorial conciso e um guia de introdução.
Kudos
Quero dizer um grande "obrigado" a @mkurnikov por liderar o projeto e a todos os colaboradores que tornaram isso possível. Vocês são todos incríveis!
TLDR
Neste artigo, estou mostrando como os tipos funcionam com django
e drf
. Você pode dar uma olhada no resultado aqui .
E você também pode usar o wemake-django-template
para iniciar seus novos projetos com tudo já configurado. Será exatamente igual ao projeto de exemplo.
Introdução
Neste pequeno tutorial, mostrarei vários recursos de django-stubs
e djangorestframework-stubs
em ação. Espero que isso o convença de que é bom ter alguém para checar as coisas depois de você.
Você sempre pode consultar a documentação original. Todas as etapas também são abordadas lá.
Para começar, precisaremos de um novo projeto e de um ambiente virtual limpo , para que possamos instalar nossas dependências:
pip install django django-stubs mypy
Em seguida, precisaremos configurar o mypy
corretamente. Pode ser dividido em duas etapas. Primeiro, configuramos o mypy
:
# setup.cfg [mypy] # The mypy configurations: https://mypy.readthedocs.io/en/latest/config_file.html python_version = 3.7 check_untyped_defs = True disallow_any_generics = True disallow_untyped_calls = True disallow_untyped_decorators = True ignore_errors = False ignore_missing_imports = True implicit_reexport = False strict_optional = True strict_equality = True no_implicit_optional = True warn_unused_ignores = True warn_redundant_casts = True warn_unused_configs = True warn_unreachable = True warn_no_return = True
Então configuramos o plugin django-stubs
:
# setup.cfg [mypy] # Appending to `mypy` section: plugins = mypy_django_plugin.main [mypy.plugins.django-stubs] django_settings_module = server.settings
O que fazemos aqui?
- Adicionamos um plug - in
mypy
personalizado para ajudar o verificador de tipos a adivinhar tipos em algumas situações complicadas específicas do Django (como modelos, conjunto de consultas, configurações etc.) - Também adicionamos uma configuração personalizada para
django-stubs
para apontar para as configurações que usamos para o Django. Será necessário importá-lo.
O resultado final pode ser encontrado aqui .
Agora temos tudo instalado e configurado. Vamos digitar verificar as coisas!
Exibições de digitação
Vamos começar digitando visualizações, pois é a coisa mais fácil de fazer com este plugin.
Aqui está nossa visão simples baseada em funções:
Vamos correr e ver de que tipos ele conhece. Observe que talvez seja necessário modificar o PYTHONPATH
, para que o mypy
possa importar nosso projeto:
» PYTHONPATH="$PYTHONPATH:$PWD" mypy server server/apps/main/views.py:14: note: Revealed type is 'def () -> builtins.bool' server/apps/main/views.py:15: note: Revealed type is 'django.contrib.auth.models.User'
Vamos tentar quebrar algo:
Não, há um erro de digitação e mypy
vai pegá-lo:
» PYTHONPATH="$PYTHONPATH:$PWD" mypy server server/apps/main/views.py:18: error: Argument 1 to "render" has incompatible type "Dict[str, Any]"; expected "HttpRequest"
Isso funciona! Ok, mas isso é bem direto. Vamos complicar um pouco nosso exemplo e criar um modelo personalizado para mostrar como podemos digitar modelos e conjuntos de consultas.
Modelos de verificação de tipos e conjunto de consultas
O ORM do Django é um recurso matador. É muito flexível e dinâmico. Isso também significa que é difícil digitar. Vamos ver alguns recursos que já são cobertos pelo django-stubs
.
Nossa definição de modelo:
E todos os campos deste modelo são cobertos por django-stubs
. Vamos ver quais tipos são revelados:
» PYTHONPATH="$PYTHONPATH:$PWD" mypy server server/apps/main/models.py:21: note: Revealed type is 'builtins.int*' server/apps/main/models.py:22: note: Revealed type is 'django.contrib.auth.models.User*' server/apps/main/models.py:23: note: Revealed type is 'builtins.str*' server/apps/main/models.py:24: note: Revealed type is 'builtins.bool*' server/apps/main/models.py:25: note: Revealed type is 'datetime.datetime*'
Tudo parece bom! django-stubs
fornece um plugin mypy
personalizado para converter campos de modelo em tipos de instância corretos. É por isso que todos os tipos são revelados corretamente.
A segunda grande característica do plugin django-stubs
é que podemos digitar QuerySet
:
E aqui está como isso pode ser verificado:
reveal_type(published_posts().first())
Podemos até anotar conjuntos de .values()
com .values()
e .values_list()
. Este plugin é inteligente!
Eu lutei com métodos de anotação retornando QuerySet
s por vários anos. Esse recurso resolve um grande problema para mim: não há mais Iterable[BlogPost]
ou List[User]
. Agora posso usar tipos reais.
APIs de digitação automática
Porém, digitar visualizações, modelos, formulários, comandos, URLs e admin não é tudo o que temos. TypedDjango também possui djangorestframework
para djangorestframework
. Vamos instalar e configurá-lo:
pip install djangorestframework djangorestframework-stubs
E podemos começar a criar serializadores:
Visualizações:
E roteadores:
Nem parece que algo mudou, mas tudo é digitado: configurações, serializadores, conjuntos de visualizações e roteadores. Isso permitirá que você adicione gradualmente as tipologias onde mais precisar delas.
Vamos tentar alterar queryset = BlogPost.objects.all()
para queryset = [1, 2, 3]
em nossas visualizações:
» PYTHONPATH="$PYTHONPATH:$PWD" mypy server server/apps/main/views.py:25: error: Incompatible types in assignment (expression has type "List[int]", base class "GenericAPIView" defined the type as "Optional[QuerySet[Any]]")
Não, não vai funcionar! Corrija seu código!
Conclusão
Digitar as interfaces de estrutura é uma coisa incrível de se ter. Quando combinado com ferramentas como returns
e mappers
, permitirá escrever lógica de negócios declarativa e com segurança de tipo, envolvida em interfaces de estrutura digitadas. E para diminuir o número de erros na camada entre esses dois.
A digitação estática gradual opcional também permite iniciar rapidamente e adicionar tipos somente quando sua API estiver estabilizada ou acompanhar o desenvolvimento orientado a tipos desde o início.
No entanto, django-stubs
e djangorestframework-stubs
são novos projetos. Ainda existem muitos bugs, recursos planejados, especificações de tipo ausentes. Congratulamo-nos com todas as contribuições da comunidade para tornar as ferramentas de desenvolvedor em Python realmente incríveis.
Publicado originalmente no meu blog .