Vous en avez assez des bidouillages de sys.path ?
Il y a beaucoup de sys.path.append
-Mais j'ai trouvé un autre moyen de résoudre le problème en question.
Résumé
- Enveloppez le code dans un seul dossier (par ex.
packaged_stuff
)
- Créer
setup.py
script où vous utilisez setuptools.setup() . (voir minimal setup.py
ci-dessous)
- Pip installe le paquet dans un état modifiable avec
pip install -e <myproject_folder>
- Importer en utilisant
from packaged_stuff.modulename import function_name
Configuration
Le point de départ est la structure de fichier que vous avez fournie, enveloppée dans un dossier appelé 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
Je vais appeler le .
le dossier racine, et dans mon exemple, il se trouve à l'adresse suivante C:\tmp\test_imports\
.
api.py
Comme cas de test, utilisons le fichier ./api/api.py suivant
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()
Essayez d'exécuter 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'
Les importations relatives ne fonctionnent pas non plus :
Utilisation de from ..api.api import function_from_api
se traduirait par
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
Étapes
- Créez un fichier setup.py dans le répertoire racine.
Le contenu pour le setup.py
serait*
from setuptools import setup, find_packages
setup(name='myproject', version='1.0', packages=find_packages())
- Utiliser un environnement virtuel
Si vous êtes familier avec les environnements virtuels, activez-en un et passez à l'étape suivante. L'utilisation des environnements virtuels n'est pas absolument nécessaires, mais ils realmente vous aider à long terme (lorsque vous avez plus d'un projet en cours ). Les étapes les plus simples sont les suivantes (à exécuter dans le dossier racine)
- Créer un environnement virtuel
- Activer l'environnement virtuel
-
source ./venv/bin/activate
(Linux, macOS) ou ./venv/Scripts/activate
(Win)
Pour en savoir plus, il suffit de chercher sur Google "python virtual env tutorial" ou similaire. Vous n'aurez probablement jamais besoin d'autres commandes que la création, l'activation et la désactivation.
Une fois que vous avez créé et activé un environnement virtuel, votre console devrait donner le nom de l'environnement virtuel entre parenthèses
PS C:\tmp\test_imports> python -m venv venv
PS C:\tmp\test_imports> .\venv\Scripts\activate
(venv) PS C:\tmp\test_imports>
et votre arborescence de dossiers devrait ressembler à ceci**
.
├── 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 installer votre projet dans un état modifiable
Installez votre paquet de premier niveau myproject
en utilisant pip
. L'astuce consiste à utiliser le -e
lors de l'installation. De cette façon, il est installé dans un état modifiable, et toutes les modifications apportées aux fichiers .py seront automatiquement incluses dans le paquet installé.
Dans le répertoire racine, exécutez
pip install -e .
(notez le point, il signifie "répertoire actuel")
Vous pouvez également voir qu'il est installé en utilisant 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
- Ajouter
myproject.
dans vos importations
Notez que vous devrez ajouter myproject.
uniquement dans les importations qui ne fonctionneraient pas autrement. Les importations qui fonctionnaient sans le setup.py
& pip install
fonctionnera toujours très bien. Voir un exemple ci-dessous.
Testez la solution
Maintenant, testons la solution en utilisant api.py
définis ci-dessus, et test_one.py
définis ci-dessous.
test_one.py
from myproject.api.api import function_from_api
def test_function():
print(function_from_api())
if __name__ == '__main__':
test_function()
exécution du test
(venv) PS C:\tmp\test_imports> python .\myproject\tests\test_one.py
I am the return value from api.api!
* Voir le Documentation sur les outils d'installation pour des exemples plus verbeux de setup.py.
** En réalité, vous pouvez placer votre environnement virtuel n'importe où sur votre disque dur.