Cansado de hacks sys.path?
Existem muitos sys.path.append
truques disponíveis, mas eu encontrei uma maneira alternativa de resolver o problema em questão.
Resumo
- Coloque o código em uma pasta (por exemplo
packaged_stuff
)
- Use o
setup.py
script create onde você usa setuptools.setup () .
- O Pip instala o pacote no estado editável com
pip install -e <myproject_folder>
- Importar usando
from packaged_stuff.modulename import function_name
Configuração
O ponto de partida é a estrutura de arquivos que você forneceu, agrupada em uma pasta chamada myproject
.
.
└── myproject
├── api
│ ├── api_key.py
│ ├── api.py
│ └── __init__.py
├── examples
│ ├── example_one.py
│ ├── example_two.py
│ └── __init__.py
├── LICENCE.md
├── README.md
└── tests
├── __init__.py
└── test_one.py
Vou chamar a .
pasta raiz e, no meu exemplo, está localizada em C:\tmp\test_imports\
.
api.py
Como caso de teste, vamos usar o seguinte ./api/api.py
def function_from_api():
return 'I am the return value from api.api!'
test_one.py
from api.api import function_from_api
def test_function():
print(function_from_api())
if __name__ == '__main__':
test_function()
Tente executar test_one:
PS C:\tmp\test_imports> python .\myproject\tests\test_one.py
Traceback (most recent call last):
File ".\myproject\tests\test_one.py", line 1, in <module>
from api.api import function_from_api
ModuleNotFoundError: No module named 'api'
Também tentar importações relativas não funcionará:
O uso from ..api.api import function_from_api
resultaria em
PS C:\tmp\test_imports> python .\myproject\tests\test_one.py
Traceback (most recent call last):
File ".\tests\test_one.py", line 1, in <module>
from ..api.api import function_from_api
ValueError: attempted relative import beyond top-level package
Passos
- Crie um arquivo setup.py no diretório no nível raiz
O conteúdo para o setup.py
seria *
from setuptools import setup, find_packages
setup(name='myproject', version='1.0', packages=find_packages())
- Use um ambiente virtual
Se você estiver familiarizado com ambientes virtuais, ative um e pule para a próxima etapa. O uso de ambientes virtuais não é absolutamente necessário, mas eles realmente o ajudarão a longo prazo (quando você tiver mais de um projeto em andamento ..). As etapas mais básicas são (executadas na pasta raiz)
- Criar ambiente virtual
- Ativar env virtual
source ./venv/bin/activate
(Linux, macOS) ou ./venv/Scripts/activate
(Win)
Para saber mais sobre isso, basta pesquisar no "python virtual env tutorial" ou similar. Você provavelmente nunca precisará de outros comandos além de criar, ativar e desativar.
Depois de criar e ativar um ambiente virtual, seu console deve dar o nome do ambiente virtual entre parênteses
PS C:\tmp\test_imports> python -m venv venv
PS C:\tmp\test_imports> .\venv\Scripts\activate
(venv) PS C:\tmp\test_imports>
e sua árvore de pastas deve ficar assim **
.
├── myproject
│ ├── api
│ │ ├── api_key.py
│ │ ├── api.py
│ │ └── __init__.py
│ ├── examples
│ │ ├── example_one.py
│ │ ├── example_two.py
│ │ └── __init__.py
│ ├── LICENCE.md
│ ├── README.md
│ └── tests
│ ├── __init__.py
│ └── test_one.py
├── setup.py
└── venv
├── Include
├── Lib
├── pyvenv.cfg
└── Scripts [87 entries exceeds filelimit, not opening dir]
- pip instale seu projeto em estado editável
Instale seu pacote de nível superior myproject
usando pip
. O truque é usar a -e
bandeira ao fazer a instalação. Dessa forma, ele é instalado em um estado editável e todas as edições feitas nos arquivos .py serão automaticamente incluídas no pacote instalado.
No diretório raiz, execute
pip install -e .
(observe o ponto, significa "diretório atual")
Você também pode ver que ele está instalado usando pip freeze
(venv) PS C:\tmp\test_imports> pip install -e .
Obtaining file:///C:/tmp/test_imports
Installing collected packages: myproject
Running setup.py develop for myproject
Successfully installed myproject
(venv) PS C:\tmp\test_imports> pip freeze
myproject==1.0
- Adicione
myproject.
em suas importações
Observe que você precisará adicionar myproject.
apenas importações que não funcionariam de outra maneira. As importações que funcionaram sem o setup.py
& pip install
ainda funcionarão bem. Veja um exemplo abaixo.
Teste a solução
Agora, vamos testar a solução usando api.py
definido acima e test_one.py
definido abaixo.
test_one.py
from myproject.api.api import function_from_api
def test_function():
print(function_from_api())
if __name__ == '__main__':
test_function()
executando o teste
(venv) PS C:\tmp\test_imports> python .\myproject\tests\test_one.py
I am the return value from api.api!
* Consulte os documentos setuptools para obter mais exemplos detalhados de setup.py.
** Na realidade, você pode colocar seu ambiente virtual em qualquer lugar do seu disco rígido.
sys.path
hacks e ler a única solução real publicada até agora (após 7 anos!).