typing.assert_type e typing.reveal_type ajudam a testar e compreender a inferência de tipos. reveal_type() pede ao analisador que mostre o tipo inferido de uma expressão. assert_type() declara qual tipo o programador espera e permite transformar essa expectativa em um teste estático que falha quando a inferência muda.
Essas ferramentas são especialmente úteis ao desenvolver bibliotecas, overloads, genéricos, Protocols, TypedDicts, decoradores e funções que refinam tipos. Neste guia, você aprenderá a usá-las em arquivos de teste, CI, debugging de anotações e manutenção de APIs.
O que reveal_type faz
from typing import reveal_type
valor = [1, 2, 3]
reveal_type(valor)Um analisador pode informar que valor é list[int]. A mensagem aparece durante a análise estática. Em runtime, o comportamento depende da implementação da função e pode produzir uma saída diagnóstica, mas o uso principal é com mypy, pyright ou ferramentas equivalentes.
Revelando expressões intermediárias
dados: dict[str, int | None] = {"a": 1}
valor = dados.get("a")
reveal_type(valor)O resultado esperado é uma união como int | None. Esse diagnóstico ajuda a entender por que o analisador exige uma verificação antes de operações numéricas.
Refinamento por condição
if valor is not None:
reveal_type(valor)
print(valor + 1)Dentro do ramo, o tipo deve ser refinado para int. reveal_type permite confirmar se o fluxo foi interpretado como esperado.
O que assert_type faz
from typing import assert_type
resultado = len("python")
assert_type(resultado, int)O analisador compara o tipo inferido de resultado com o tipo esperado. Se não corresponder segundo suas regras, gera um erro. A função retorna o primeiro argumento em runtime e não converte nem valida o valor.
assert_type não é isinstance
valor: object = 10
assert_type(valor, int) # deve falhar estaticamenteEmbora o valor concreto seja um inteiro naquela execução, a variável foi declarada como object. assert_type testa a informação estática disponível, não o tipo observado em runtime.
Testando uma função genérica
from typing import TypeVar
T = TypeVar("T")
def primeiro(itens: list[T]) -> T:
return itens[0]
assert_type(primeiro([1, 2]), int)
assert_type(primeiro(["a", "b"]), str)Esses testes confirmam que o parâmetro genérico é propagado ao retorno.
Testando overloads
from typing import Literal, overload
@overload
def ler(*, binario: Literal[False] = False) -> str: ...
@overload
def ler(*, binario: Literal[True]) -> bytes: ...
def ler(*, binario: bool = False) -> str | bytes:
return b"dados" if binario else "dados"
assert_type(ler(), str)
assert_type(ler(binario=True), bytes)Uma alteração na ordem ou assinatura dos overloads pode quebrar a inferência. assert_type captura a regressão sem precisar executar a função.
Testando Literal
modo = "rapido"
reveal_type(modo)
modo_literal: Literal["rapido"] = "rapido"
assert_type(modo_literal, Literal["rapido"])Variáveis mutáveis podem ser ampliadas para str, enquanto anotações explícitas preservam o valor literal. reveal_type mostra essa diferença.
Testando TypedDict
from typing import TypedDict
class Usuario(TypedDict):
id: int
nome: str
usuario: Usuario = {"id": 1, "nome": "Ana"}
assert_type(usuario["id"], int)
assert_type(usuario["nome"], str)Chaves opcionais exigem teste de presença. É útil revelar o tipo antes e depois de if "chave" in dados.
Testando TypeGuard e TypeIs
from typing import TypeGuard
def eh_str(valor: object) -> TypeGuard[str]:
return isinstance(valor, str)
item: object = "x"
if eh_str(item):
assert_type(item, str)O teste confirma que o predicado refina o ramo verdadeiro. Para TypeIs, também teste o ramo falso. Consulte TypeGuard no Python.
Testando Protocol
from typing import Protocol
class Fechavel(Protocol):
def fechar(self) -> None: ...
class Arquivo:
def fechar(self) -> None: ...
arquivo = Arquivo()
assert_type(arquivo, Arquivo)
fechavel: Fechavel = arquivo
assert_type(fechavel, Fechavel)assert_type verifica o tipo estático da variável, não apenas a compatibilidade estrutural da expressão.
Decoradores e perda de assinatura
Decoradores mal tipados frequentemente transformam funções precisas em Callable[..., Any]. Use reveal_type na função decorada e em seu retorno:
@meu_decorador
def buscar(id_: int) -> str:
...
reveal_type(buscar)
assert_type(buscar(1), str)ParamSpec e TypeVar podem preservar a assinatura. O guia sobre ParamSpec no Python mostra esse padrão.
Arquivos de testes estáticos
Crie arquivos como tests/typing/test_api.py que não precisam ser executados no pytest. O CI roda o analisador sobre eles. Esses testes documentam a experiência esperada do usuário da biblioteca.
Testes positivos e negativos
assert_type cobre expectativas positivas. Para chamadas que devem falhar, use mecanismos do analisador, comentários de erro esperado ou ferramentas como pytest para type checker. A sintaxe varia entre ecossistemas.
Não dependa da mensagem textual
Mensagens de reveal_type podem variar entre analisadores. Use assert_type quando precisar de uma expectativa automatizada. reveal_type é melhor para exploração e debugging.
Tipos equivalentes e normalização
list[int] e formas antigas podem ser tratadas como equivalentes. Uniões podem aparecer em ordem diferente. O analisador decide equivalência sem depender da representação de string.
Any pode esconder problemas
valor: object = obter_dado()
reveal_type(valor)Se uma dependência retorna Any, muitas operações passam sem verificação. Adicione assert_type em fronteiras para detectar quando Any invade a API. Algumas configurações do analisador podem tornar o teste com Any mais rigoroso.
Never e código inalcançável
Em ramos exaustivos, reveal_type pode mostrar Never. Isso ajuda a confirmar que uma união foi totalmente tratada. O guia sobre Never no Python aborda assert_never().
Self e métodos fluentes
builder = BuilderEspecial().configurar()
assert_type(builder, BuilderEspecial)Esse teste garante que um método com Self preserva subclasses. É valioso para factories e APIs fluentes.
Tipos variádicos
TypeVarTuple e Unpack podem produzir inferências difíceis de observar. assert_type documenta a forma resultante:
tupla = adicionar_prefixo((1, "a"))
assert_type(tupla, tuple[str, int, str])Comportamento em runtime
assert_type(valor, Tipo) retorna valor sem fazer checagem. reveal_type(valor) também não substitui validação. Não use essas funções para proteger entradas de usuário ou garantir tipos durante execução.
Remover reveal_type antes da produção
Chamadas de reveal_type são úteis durante desenvolvimento, mas podem gerar saída em runtime ou poluir o código. Mantenha-as em testes de tipagem ou remova após o diagnóstico.
Compatibilidade de versões
Use typing_extensions.assert_type e recursos relacionados quando necessário. O comportamento estático depende mais da versão do analisador que do interpretador. Fixe versões no CI para evitar mudanças inesperadas.
Comparando analisadores
Mypy e pyright podem inferir detalhes diferentes em casos complexos. Se a biblioteca promete suporte aos dois, execute os mesmos testes com ambos. Evite depender de um comportamento não especificado apenas porque um analisador o aceita.
Erros comuns
- Esperar validação em runtime: assert_type não chama isinstance.
- Deixar reveal_type no caminho de produção: pode gerar saída desnecessária.
- Testar apenas implementação: teste também a API vista pelo consumidor.
- Aceitar Any sem perceber: ele pode fazer assertivas perderem valor.
- Comparar strings de diagnóstico: mensagens variam.
- Não fixar o analisador: mudanças de versão podem alterar inferência.
Exemplo completo: API de cache
from typing import TypeVar, overload, assert_type
T = TypeVar("T")
_AUSENTE = object()
@overload
def obter(chave: str) -> object: ...
@overload
def obter(chave: str, default: T) -> object | T: ...
def obter(chave: str, default: object = _AUSENTE) -> object:
...
assert_type(obter("x"), object)
assert_type(obter("x", 0), object | int)
assert_type(obter("x", None), object | None)Os testes registram a relação entre default e retorno. Se a implementação ou os overloads mudarem, o CI informa a regressão.
Estratégia para bibliotecas
Crie uma pasta de casos de uso reais. Importe a biblioteca como um consumidor externo. Teste inferência de retornos, erros esperados, subclasses, overloads e genéricos. Não teste apenas funções internas, pois o empacotamento e os arquivos .pyi também podem alterar os tipos públicos.
Conclusão
reveal_type() é uma lente para investigar o que o analisador inferiu. assert_type() transforma a expectativa em um contrato testável. Juntos, eles ajudam a desenvolver APIs tipadas previsíveis e a detectar regressões antes da publicação.
A documentação oficial de assert_type e reveal_type no módulo typing detalha o comportamento. Use reveal_type para explorar, assert_type para automatizar e sempre execute os testes com as mesmas configurações de tipagem usadas pelo projeto.







