Stanco degli hack di sys.path?
Ce ne sono molti sys.path.append -hack disponibili, ma ho trovato un modo alternativo per risolvere il problema in mano.
Sommario
- Avvolgere il codice in una cartella (ad es.
packaged_stuff)
- Usa lo
setup.pyscript di creazione in cui usi setuptools.setup () .
- Pip installa il pacchetto in stato modificabile con
pip install -e <myproject_folder>
- Importa utilizzando
from packaged_stuff.modulename import function_name
Impostare
Il punto di partenza è la struttura del file che hai fornito, racchiusa in una cartella chiamata 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
Chiamerò la .cartella principale e nel mio caso di esempio si trova in C:\tmp\test_imports\.
api.py
Come test case, usiamo il seguente ./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()
Prova a eseguire 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'
Anche provare le importazioni relative non funzionerà:
L'uso from ..api.api import function_from_apisarebbe risultato in
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
passi
- Crea un file setup.py nella directory di livello principale
I contenuti per il setup.pysarebbero *
from setuptools import setup, find_packages
setup(name='myproject', version='1.0', packages=find_packages())
- Usa un ambiente virtuale
Se hai familiarità con gli ambienti virtuali, attivane uno e vai al passaggio successivo. L'uso di ambienti virtuali non è assolutamente necessario, ma ti aiuteranno davvero a lungo termine (quando hai in corso più di 1 progetto ...). I passaggi più basilari sono (esegui nella cartella principale)
- Crea un ambiente virtuale
- Attiva env virtuale
source ./venv/bin/activate(Linux, macOS) o ./venv/Scripts/activate(Win)
Per saperne di più su questo, basta uscire da Google "tutorial virtuale su Python" o simili. Probabilmente non avrai mai bisogno di altri comandi oltre a creare, attivare e disattivare.
Dopo aver creato e attivato un ambiente virtuale, la console dovrebbe fornire il nome dell'ambiente virtuale tra parentesi
PS C:\tmp\test_imports> python -m venv venv
PS C:\tmp\test_imports> .\venv\Scripts\activate
(venv) PS C:\tmp\test_imports>
e l'albero delle cartelle dovrebbe apparire così **
.
├── 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 installa il tuo progetto in stato modificabile
Installa il tuo pacchetto di livello superiore myprojectutilizzando pip. Il trucco è usare la -ebandiera durante l'installazione. In questo modo viene installato in uno stato modificabile e tutte le modifiche apportate ai file .py verranno automaticamente incluse nel pacchetto installato.
Nella directory principale, eseguire
pip install -e . (notare il punto, sta per "directory corrente")
Puoi anche vedere che è installato 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
- Aggiungi
myproject.alle tue importazioni
Tieni presente che dovrai aggiungere myproject.solo le importazioni che altrimenti non funzionerebbero. Le importazioni che hanno funzionato senza setup.pye pip installfunzioneranno ancora bene. Vedi un esempio di seguito.
Prova la soluzione
Ora, testiamo la soluzione usando api.pydefinito sopra e test_one.pydefinito di seguito.
test_one.py
from myproject.api.api import function_from_api
def test_function():
print(function_from_api())
if __name__ == '__main__':
test_function()
eseguendo il test
(venv) PS C:\tmp\test_imports> python .\myproject\tests\test_one.py
I am the return value from api.api!
* Vedi i documenti setuptools per esempi più dettagliati di setup.py.
** In realtà, potresti mettere il tuo ambiente virtuale ovunque sul tuo disco rigido.
sys.pathhack e di leggere l'unica vera soluzione che è stata pubblicata finora (dopo 7 anni!).