Pular para o conteúdo principal

Makefile: verificar o código

O enunciado exige que o código siga o padrão do flake8 e passe no mypy sem erros, duas ferramentas de verificação. Esta página explica o que cada uma confere e escreve as duas regras do Makefile que as rodam: lint, com as opções que o enunciado fixa, e lint-strict, a versão mais rigorosa. Como na página anterior, cada trecho entra no fim do Makefile.

lint: o que o flake8 e o mypy fazem​

Lint é o nome que se dá a verificar o código sem executá-lo, à procura de erros e de desvios do padrão.

O flake8 confere o estilo, segundo a PEP 8, o guia de estilo oficial do Python (linhas de até 79 caracteres, espaços em volta de operadores, duas linhas em branco entre funções...). Ele também acusa erros simples, como um import que não é usado. Um exemplo, só para ver a saída (não precisa criar o arquivo), num estilo.py com um import os que nunca é usado e um = sem espaços em volta:

import os


def area(largura: int, altura: int) -> int:
resultado=largura * altura
return resultado

flake8 estilo.py responde:

estilo.py:1:1: F401 'os' imported but unused
estilo.py:5:14: E225 missing whitespace around operator

Cada linha diz o arquivo, a linha, a coluna, o código do problema e a explicação.

O mypy confere as anotações de tipo: o : int de um parâmetro e o -> int do retorno de uma função. O Python ignora essas anotações na hora de rodar; o mypy as lê e acusa quando o código as contradiz. Outro exemplo, num exemplo.py com uma função anotada -> int que devolve um texto (str), e outra função sem anotação nenhuma:

def dobro(numero: int) -> int:
return str(numero * 2)


def metade(numero):
return numero // 2

Com as opções da regra lint (logo abaixo), o mypy responde:

exemplo.py:2: error: Incompatible return value type (got "str", expected "int") [return-value]
exemplo.py:5: error: Function is missing a type annotation [no-untyped-def]
Found 2 errors in 1 file (checked 1 source file)

lint: a regra​

O enunciado fixa os dois comandos, com estas opções exatas:

MYPY_FLAGS = --warn-return-any --warn-unused-ignores --ignore-missing-imports \
--disallow-untyped-defs --check-untyped-defs
lint:
$(PY) -m flake8 .
$(PY) -m mypy . $(MYPY_FLAGS)

O . quer dizer "a pasta atual e tudo dentro dela". As opções ficam numa variável só porque a linha não caberia na tela: a \ no fim da primeira linha continua a variável na linha de baixo, e na hora de rodar o make junta tudo numa linha só.

Opção do mypyEfeito
--warn-return-anyacusa uma função com tipo de retorno declarado que devolve um valor de tipo Any ("qualquer coisa", sem tipo conhecido)
--warn-unused-ignoresacusa um # type: ignore (o comentário que manda o mypy pular uma linha) que não está pulando erro nenhum
--ignore-missing-importsnão acusa bibliotecas de terceiros que não têm anotações de tipo
--disallow-untyped-defsacusa toda função ou método sem anotação de tipo
--check-untyped-defsconfere também o corpo das funções sem anotação

As duas últimas parecem repetidas: se toda função precisa ter anotação, não sobra função sem anotação para conferir. O projeto usa as duas porque o enunciado fixa a linha do mypy com as cinco opções, palavra por palavra.

O flake8 . confere todos os arquivos .py do projeto; as pastas que ele deve pular ficam no arquivo .flake8 (explicado adiante).

lint-strict​

lint-strict:
$(PY) -m flake8 .
$(PY) -m mypy . --strict

--strict liga quase todas as verificações do mypy, inclusive quatro das cinco do lint; só --ignore-missing-imports fica de fora, e o projeto não precisa dela, porque não usa biblioteca de terceiros. O enunciado deixa a regra lint-strict opcional, mas "fortemente recomendada".

O projeto passa nas duas regras sem nenhum # type: ignore nem # noqa (o comentário que manda o flake8 pular uma linha). Isso é uma escolha: calar a ferramenta numa linha esconderia o problema em vez de resolvê-lo.

Experimente​

make -n lint lint-strict
.venv/bin/python -m flake8 .
.venv/bin/python -m mypy . --warn-return-any --warn-unused-ignores --ignore-missing-imports --disallow-untyped-defs --check-untyped-defs
.venv/bin/python -m flake8 .
.venv/bin/python -m mypy . --strict

A segunda linha é o comando do enunciado, palavra por palavra, só que com o Python do .venv.

Faltam duas regras, clean, que apaga os arquivos que as ferramentas criam sozinhas, e build, que monta o pacote do gerador. As duas e o Makefile completo estão na próxima página.