O módulo runpy executa código Python localizado pelo sistema de importação ou por um caminho de arquivo, retornando o namespace global resultante. Ele implementa parte da lógica usada por comandos como python -m pacote.modulo e é útil em launchers, test harnesses, ferramentas educacionais, wrappers de CLI e sistemas que precisam executar um módulo como se fosse o programa principal.
O módulo não cria isolamento. O código é executado no processo atual, pode alterar estado global, importar dependências, abrir arquivos, iniciar threads e encerrar o programa. Use-o apenas com código confiável e entenda como ele manipula variáveis especiais como __name__, __spec__, __package__ e sys.argv.
run_module
runpy.run_module(mod_name, ...) localiza um módulo pelo sistema de importação e executa seu código.
import runpy
namespace = runpy.run_module("meu_pacote.modulo")
print(namespace.keys())
O nome deve ser importável no ambiente atual.
O retorno é um dicionário
Depois da execução, o retorno contém os globals definidos pelo módulo.
resultado = runpy.run_module("configuracao")
valor = resultado.get("CONFIG")
Objetos retornados continuam vivos e podem referenciar módulos, arquivos, locks ou outros recursos.
run_name
O parâmetro run_name controla o valor de __name__ durante a execução.
runpy.run_module(
"meu_pacote.cli",
run_name="__main__",
)
Isso ativa blocos condicionais como if __name__ == "__main__":.
Executar como __main__
Executar um módulo com run_name="__main__" aproxima o comportamento de python -m, mas detalhes de sys.argv e sys.modules dependem de outras opções.
Para uma CLI pública, normalmente é mais simples invocar o interpretador com -m em um subprocesso.
Pacotes e __main__.py
Quando o nome identifica um pacote, o mecanismo pode localizar e executar o submódulo pacote.__main__.
meu_pacote/
__init__.py
__main__.pyEsse é o padrão para pacotes executáveis com python -m meu_pacote.
alter_sys
Com alter_sys=True, runpy altera temporariamente alguns elementos de sys, como sys.argv[0] e uma entrada em sys.modules.
runpy.run_module(
"meu_pacote.cli",
run_name="__main__",
alter_sys=True,
)
As alterações são restauradas ao final, inclusive quando ocorre exceção.
alter_sys não é thread-safe
Outras threads podem observar o estado temporário e receber um módulo parcialmente inicializado ou um valor de argv inesperado.
Não use alter_sys=True enquanto threads concorrentes dependem desses globals. Prefira um processo separado.
init_globals
init_globals fornece valores iniciais para o namespace.
namespace = runpy.run_module(
"relatorio",
init_globals={"AMBIENTE": "teste"},
)
O módulo pode sobrescrever essas chaves durante a execução.
Não use init_globals como segurança
Fornecer um dicionário reduzido não impede o código de importar builtins, acessar filesystem ou introspectar objetos.
Ele é um mecanismo de configuração e teste, não sandbox.
Variáveis especiais
runpy define valores apropriados para variáveis como __name__, __file__, __cached__, __loader__, __package__ e __spec__.
Esses valores permitem que imports relativos e diagnósticos funcionem de forma semelhante ao sistema normal de importação.
__spec__
__spec__ descreve como o módulo foi localizado e carregado. Em pacotes executáveis, o nome real do spec continua relacionado ao módulo encontrado, mesmo quando __name__ é alterado.
Ferramentas devem usar __spec__.name para identidade importável e __name__ para o contexto de execução.
run_path
runpy.run_path(path_name, ...) executa código a partir de um caminho.
namespace = runpy.run_path("scripts/tarefa.py")
O caminho pode apontar para um arquivo Python ou para uma entrada válida de sys.path que contenha __main__.py.
Diretórios executáveis
Se path_name é um diretório, runpy adiciona temporariamente a entrada e procura um __main__.py.
Confirme que o diretório contém o entry point esperado. Caso contrário, outro __main__ visível no path pode causar comportamento surpreendente em alguns cenários.
Arquivos ZIP
Um ZIP válido no sistema de importação pode conter __main__.py e ser executado por run_path().
Isso é a base de aplicações .pyz. Veja zipapp no Python.
run_path e run_name
O padrão de run_name em run_path() é um valor especial. Defina __main__ quando quiser ativar o comportamento de programa principal.
runpy.run_path(
"scripts/tarefa.py",
run_name="__main__",
)
Diferença para importlib.import_module
importlib.import_module() importa e registra um módulo de forma normal em sys.modules. Imports repetidos normalmente reutilizam a mesma instância.
run_module() executa o código em um namespace novo e é voltado ao comportamento de script, não ao carregamento convencional de uma biblioteca.
Execuções repetidas
Chamar runpy duas vezes pode executar efeitos de nível de módulo duas vezes.
Isso inclui registros duplicados, criação de threads, handlers, escrita em arquivos e conexões. O código executado deve ser projetado para esse lifecycle ou rodar em processo descartável.
sys.modules
Dependendo de alter_sys, o módulo executado pode não permanecer registrado como uma importação normal.
Imports feitos pelo código permanecem em sys.modules e alteram o processo.
Estado global
O namespace retornado não captura todas as mudanças. O código pode alterar variáveis de outros módulos, logging, locale, diretório atual, sinais e caches.
Não espere desfazer uma execução simplesmente descartando o dicionário.
Exceções
Exceções lançadas pelo código são propagadas para o caller.
try:
runpy.run_module("meu_pacote.cli", run_name="__main__")
except SystemExit as erro:
print("código de saída", erro.code)
CLIs frequentemente chamam sys.exit(), que gera SystemExit.
KeyboardInterrupt
Uma interrupção pode atravessar a execução. Defina se o launcher deve encerrar, cancelar apenas a tarefa ou traduzir o estado.
Não capture BaseException sem uma política clara.
Argumentos de linha de comando
runpy não é uma API completa de subprocesso. Para simular argumentos, alterações em sys.argv afetam o processo inteiro.
Prefira chamar uma função main(argv) diretamente ou usar subprocesso.
Arquitetura de CLI recomendada
def main(argv=None):
args = parser.parse_args(argv)
return executar(args)
if __name__ == "__main__":
raise SystemExit(main())
Essa estrutura permite testes sem runpy e mantém o entry point fino.
Testes
runpy é útil para verificar que um módulo funciona como -m.
resultado = runpy.run_module(
"meu_pacote",
run_name="__main__",
)
Porém, se a CLI altera sys, abre processos ou chama exit, um subprocesso oferece isolamento mais fiel.
Use subprocess para fidelidade
subprocess.run(
[sys.executable, "-m", "meu_pacote"],
check=True,
)
Isso separa argv, módulos, sinais, ambiente e código de saída.
Performance
Execuções repetidas recompilam ou reutilizam caches conforme o sistema de importação, mas o corpo é executado novamente.
Não use runpy como mecanismo de chamada frequente entre componentes. Importe uma função e chame-a.
Plugins
Runpy não é o mecanismo ideal para plugins. Plugins devem expor APIs, entry points ou funções claras.
Executar um plugin inteiro como script dificulta contratos, cleanup e tratamento de erros.
Ferramentas educacionais
Um ambiente de aprendizagem pode usar runpy para executar exemplos em processo separado.
O isolamento deve limitar filesystem, rede, CPU, memória e tempo. Código de aluno não deve rodar no processo da aplicação.
Launchers internos
Um launcher pode selecionar módulos confiáveis a partir de uma allowlist e executá-los.
Não aceite diretamente um nome de módulo fornecido por usuário; isso pode permitir executar qualquer código importável no ambiente.
Validação de nomes
Mapeie comandos públicos a nomes internos fixos.
COMANDOS = {
"relatorio": "minhaapp.comandos.relatorio",
"limpeza": "minhaapp.comandos.limpeza",
}
Autorização deve ser aplicada antes da seleção.
Código não confiável
runpy executa Python com os privilégios do processo. Não é seguro para arquivos enviados, snippets ou pacotes de origem desconhecida.
Use processo ou container isolado com políticas de recursos.
Paths não confiáveis
run_path() pode executar qualquer script acessível. Resolva paths dentro de uma raiz permitida e recuse symlinks ou escapes.
Não execute diretamente arquivos temporários compartilhados.
Diretório atual
O código pode depender do current working directory. runpy não cria automaticamente um contexto isolado de paths relativos.
Prefira paths absolutos e APIs de recursos de pacote.
Logging
O módulo executado pode configurar handlers globais e duplicá-los em execuções repetidas.
Bibliotecas devem evitar basicConfig() automático; a aplicação deve possuir a configuração.
Threads e tarefas
Threads iniciadas pelo código podem continuar depois do retorno.
Um subprocesso descartável fornece cleanup mais previsível.
Integração com faulthandler
Para módulos confiáveis que podem travar, ative faulthandler e imponha deadline em processo separado.
Um dump antes do encerramento ajuda a identificar a linha bloqueada.
Empacotadores
Ferramentas congeladas podem implementar -m e runpy de maneiras específicas. Módulos e recursos precisam estar incluídos no artefato.
Teste no executável final, não apenas no ambiente de desenvolvimento.
__cached__ e bytecode
O namespace pode incluir o caminho de cache associado ao módulo.
Não use esse valor como garantia de que o arquivo existe ou pode ser distribuído. Caches dependem da versão do Python.
Observabilidade
Registre nome lógico, versão da aplicação, duração, resultado e código de saída traduzido. Evite registrar todo o namespace retornado.
O dicionário pode conter segredos e objetos com representações caras.
Testes de concorrência
Se uma aplicação usar runpy enquanto outras threads estão ativas, teste alterações em sys, imports e handlers.
A recomendação geral para execução independente continua sendo subprocesso.
Erros comuns
Os erros mais frequentes são confundir runpy com import normal, usar alter_sys=True em programa multithread, compartilhar estado entre execuções, simular argv globalmente, aceitar nomes ou paths arbitrários, esperar cleanup completo e usar runpy como sandbox.
Conclusão
runpy executa módulos e scripts usando a infraestrutura do Python e retorna o namespace resultante. Use run_module() para nomes importáveis, run_path() para caminhos e run_name="__main__" quando quiser comportamento de entry point.
Para isolamento, argumentos e códigos de saída reais, prefira subprocessos. Consulte a documentação oficial de runpy e o artigo de pkgutil no Python para descobrir módulos antes de selecioná-los.







