Se um arquivo Python dentro de um pacote gera ImportError: attempted relative import with no known parent package quando você o executa diretamente, inicie-o como um módulo a partir do diretório acima do pacote. No macOS, mude para a raiz do projeto no Terminal e execute python3 -m package.module. Isso fornece ao Python o contexto de pacote que um caminho de arquivo direto não fornece.

Por que uma importação relativa falha quando executo um arquivo diretamente?

Uma importação relativa como from .helpers import format_result depende do nome do pacote do módulo. O Python usa pontos iniciais para identificar o pacote atual e seus pais. Quando você executa um arquivo com python3 path/to/file.py, o Python executa esse arquivo como o módulo de nível superior __main__; ele não fornece a ele os metadados de pacote necessários para resolver o ponto. Portanto, a importação pode falhar mesmo que helpers.py esteja ao lado do arquivo. A referência de importação do Python descreve importações relativas e o tratamento especial de __main__.

Por exemplo, suponha que seu projeto esteja organizado assim:

project/
└── myapp/
    ├── __init__.py
    ├── cli.py
    └── helpers.py

Se cli.py contiver from .helpers import format_result, executar python3 myapp/cli.py a partir de project é a invocação errada. O problema é como o Python foi solicitado a executar o arquivo, não necessariamente que a importação relativa ou a localização do arquivo estejam erradas.

Execute o módulo a partir da raiz do projeto no macOS

Abra o Terminal e mude para o diretório que contém myapp. Substitua o caminho de exemplo pela localização real do seu projeto. Coloque o caminho entre aspas para que os espaços sejam tratados pelo shell; o shell padrão do Terminal do macOS é o zsh. O guia do Terminal da Apple documenta esse padrão.

cd "/Users/yourname/Projects/project"
python3 -m myapp.cli

A opção -m solicita ao Python que encontre e execute o módulo pelo seu nome de pacote com pontos. Mantenha o nome do pacote no comando e omita .py e barras do sistema de arquivos. O caminho de busca de módulos do Python começa com o diretório atual quando invocado com -m, e é por isso que executar a partir da raiz do projeto é importante. A documentação de sys.path do Python explica esse caminho inicial.

Se o comando usar a instalação errada do Python, ative primeiro o ambiente virtual existente do projeto e, em seguida, use o mesmo padrão python -m. Para um .venv típico na raiz do projeto:

cd "/Users/yourname/Projects/project"
source .venv/bin/activate
python -m myapp.cli

Usar python após a ativação seleciona o interpretador do ambiente. Se o seu ambiente tiver um nome ou local diferente, ajuste o caminho de ativação; não presuma que .venv existe. Você pode verificar o interpretador selecionado com python -c 'import sys; print(sys.executable)'.

Se você quiser executar o pacote em si

Para um comando destinado a iniciar o pacote, adicione __main__.py dentro do pacote e mantenha o ponto de entrada enxuto:

myapp/
├── __init__.py
├── __main__.py
├── cli.py
└── helpers.py

Em myapp/__main__.py, importe e chame a função de entrada do pacote. Depois, execute python3 -m myapp a partir da raiz do projeto. O Python executa o __main__.py do pacote para essa forma de invocação de -m, e esse arquivo pode usar importações relativas ao pacote. A documentação de __main__ do Python explica esse padrão de ponto de entrada de pacote.

Verifique estes detalhes se o erro persistir

  • Confirme seu diretório de trabalho. Execute pwd no Terminal e certifique-se de que ele exibe a raiz do projeto, o diretório que contém myapp. Se o pacote estiver aninhado sob src, por exemplo, use o nome do pacote importável e garanta que o ambiente configurado do projeto o disponibilize; simplesmente mudar para a pasta mãe errada não resolverá a descoberta do módulo.
  • Use o nome real do pacote. Em python3 -m myapp.cli, myapp deve ser o nome do diretório do pacote (ou seu nome de importação), e cli o nome do arquivo do módulo sem .py.
  • Verifique a linha do traceback. Se a importação relativa for resolvida, mas uma importação posterior falhar, isso pode ser um módulo ou dependência ausente diferente. Corrigir o contexto de inicialização resolve apenas a falha de contexto de pacote.
  • Evite o PYTHONPATH como a primeira correção. Ele altera o caminho de busca de importação do Python, mas não transforma por si só um arquivo executado diretamente em um módulo de pacote nomeado adequadamente. O Python também alerta que PYTHONPATH pode afetar várias versões e ambientes do Python. A referência de inicialização de caminho do Python descreve seu escopo.
  • Se a execução direta do arquivo for um requisito, considere alterar o código para usar uma importação absoluta apropriada e garantir que o pacote esteja instalado ou de outra forma importável naquele ambiente. Essa é uma escolha de configuração diferente; não misture uma importação relativa ao pacote com a expectativa de que o arquivo se comporte como um script autônomo.

A regra prática é corresponder o comando ao estilo de importação: para uma importação relativa ao pacote, execute o módulo a partir do diretório pai do pacote com python -m. Para um comando de pacote, forneça __main__.py e execute o pacote com -m.

Fontes