Estou trabalhando em um Python 3.13.1
projeto usando mypy 1.14.0
para verificação de tipo estático.
Tenho um módulo chamado module.py
com uma function
função que retorna um tipo com um nome muito longo,
Type_whose_name_is_so_long_that_we_do_not_want_to_call_it_over_and_over_again
.
Para tornar o código mais legível, defini um alias de tipo T
no arquivo stub correspondente module.pyi
.
Aqui está uma versão simplificada do meu código module.pyi
:
T = Type_whose_name_is_so_long_that_we_do_not_want_to_call_it_over_and_over_again
def function()->T: pass
class Type_whose_name_is_so_long_that_we_do_not_want_to_call_it_over_and_over_again: pass
Quero evitar illegal_usage_of_T.py
que o seguinte use o T
alias de tipo.
import module
foo:module.T = module.function()
O ideal é que, ao executar mypy illegal_usage_of_T.py
, eu receba uma mensagem de erro indicando que o tipo T
é indefinido.
O que eu tentei
Pesquisa Google
Pesquisei no Google por "mypy type alias only used in stub file", mas não consegui encontrar uma solução que impeça o mypy de reconhecer o type alias em outros módulos. Eu esperava que definir T
apenas no arquivo stub limitaria seu escopo, mas parece que o mypy consegue encontrar o type alias mesmo em outros módulos.
consertando código
Tentei várias abordagens, incluindo:
- Renomeando o alias do tipo: mudei
T
para_T
para torná-lo menos provável de ser encontrado por outros módulos, mas isso não resolveu o problema. - Usando
if TYPE_CHECKING
: Tentei definir condicionalmente o alias de tipo dentro de umif TYPE_CHECKING
bloco, mas isso também não impediu que o alias de tipo fosse usado em outros módulos. - Limitando exportações: adicionei
__all__ = ["function", "Type_whose_name_is_so_long_that_we_do_not_want_to_call_it_over_and_over_again"]
aomodule.pyi
arquivo para controlar explicitamente quais nomes são exportados, mas o alias do tipoT
ainda estava acessível.
Aqui está o código modificado para module.pyi
:
from typing import TYPE_CHECKING
if TYPE_CHECKING:
_T = Type_whose_name_is_so_long_that_we_do_not_want_to_call_it_over_and_over_again
def function()->_T: pass
class Type_whose_name_is_so_long_that_we_do_not_want_to_call_it_over_and_over_again: pass
__all__ = ["function", "Type_whose_name_is_so_long_that_we_do_not_want_to_call_it_over_and_over_again"]
E aqui está o illegal_usage_of_T.py
arquivo:
import module
foo:module._T = module.function() # Still works
Eu esperava que pelo menos uma dessas abordagens impedisse illegal_usage_of_T.py
o acesso ao _T
alias de tipo, mas nenhuma delas funcionou.
Além de escrever seu próprio plugin mypy , não há realmente uma maneira de fazer isso.
Prefixar itens com um sublinhado é de longe a convenção predominantemente adotada para indicar nomes que não devem ser exportados (usados fora do módulo em que são definidos); você pode ver essa convenção adotada no próprio projeto typeshed do Python . Alguns IDEs (como PyCharm ou VSCode com direitos de autor) de fato mostram erros se você tentar acessar itens prefixados com sublinhado de um módulo, mas isso não faz parte do mypy.
Além de usar apenas pyright em vez de mypy, a coisa mais próxima que existe é
import-private-name
a regra de Ruff, mas ela não é ativada a menos que você use o nome em um contexto de tempo de execução (anotações de tipo, comofoo: module.T
, não contam e não acionarão o linting).Quanto aos outros:
if TYPE_CHECKING
- isso não tem efeito em.pyi
arquivos stub.__all__
- isso só tem efeito para importações de estrelas (from module import *
). O acesso direto aos atributos do módulo (comomodule.T
) nunca é impedido devido à falta de um nome (T
) em__all__
.