J'ai un projet Python (que je lance dans un virtualenv) et qui a la structure suivante:
Project
├───.git
├───venv
└───src
├───__init__.py
├───mymodules
│ ├───__init__.py
│ ├───module1.py
│ └───module2.py
└───scripts
├───__init__.py
└───script.py
script.py
import src.mymodules.module1
...
Je lance le projet avec venv activé et à partir du répertoire Project en utilisant la commande suivante:
(venv)$ python src/scripts/script.py
Le script s'exécute mais génère l'erreur suivante avant de quitter:
Traceback (most recent call last):
File "src/scripts/script.py", line 1, in <module>
import src.mymodules.module1
ImportError: No module named src.mymodules.module1
J'ai essayé d'exécuter le shell python et d'essayer d'importer le module à partir de là et cela n'a généré aucune erreur. J'ai _ _init__.py dans tous les répertoires de src. Python considère-t-il que le répertoire de travail est src/scripts? Pourquoi cela se produit-il et comment puis-je faire de src le répertoire de travail si c'est le cas?
En gros, lorsque vous exécutez script.py
directement, il ne sait pas qu'il fait partie d'un sous-module de src
ni où se trouve un module nommé src
. C'est le cas en python 2 ou 3.
Comme vous le savez, Python trouve des modules basés sur le contenu de sys.path
. Pour importer un module, celui-ci doit se trouver dans un répertoire répertorié dans sys.path
ou dans le même répertoire que le script que vous exécutez.
Lorsque vous dites python src/scripts/script.py
, sys.path
inclut le Project/src/scripts/
(car c'est là que se trouve script.py
), mais pas Project
. Comme Project
n'est pas dans le chemin, les modules de ce répertoire (src
) ne peuvent pas être importés.
Pour résoudre ce problème:
Je suppose que votre script.py
est un point d’entrée pour votre module src
(par exemple, c’est peut-être le programme principal). Si c'est le cas, vous pouvez résoudre ce problème en déplaçant script.py
jusqu'au même niveau que src
:
Project
├───.git
├───venv
|───script.py <--- script.py moves up here
└───src
├───__init__.py
└───mymodules
├───__init__.py
├───module1.py
└───module2.py
De cette façon, script.py
peut importer librement n'importe quoi dans src
, mais rien dans src
ne peut importer script.py
.
Si ce n'est pas le cas et que script.py
fait vraiment partie de src
, vous pouvez utiliser l'argument -m
de python pour exécuter script.py
dans le cadre du module src
, comme suit:
$ python -m src.scripts.script
Parce que vous avez indiqué à python le module que vous utilisez (src
), il sera dans le chemin. Donc, script.py
saura qu'il s'agit d'un sous-module de src
et pourra ensuite importer à partir de src
.
Soyez prudent dans cette situation, car il est possible de créer une importation circulaire si quelque chose dans src
imports src.scripts.script
.
Comme alternative à ces deux approches, vous pouvez modifier le sys.path
directement dans script.py
:
import sys
sys.path.insert(0, '/path/to/Project') # location of src
Bien que cela fonctionne, ce n'est généralement pas ma préférence. script.py
doit savoir exactement comment votre code est structuré et peut créer une confusion lors de l’importation si un autre programme python tente d’importer script.py
.
Project
├───.git
├───venv
└───src
├───__init__.py
├───mymodules
│ ├───__init__.py
│ ├───module1.py
│ └───module2.py
└───scripts
├───__init__.py
└───script.py
Sinon, vous pouvez importer comme suit dans votre script.py
import os
import sys
sys.path.append(os.path.join(os.path.dirname(__file__),'../../'))
import src.mymodules.module1
Vous pouvez maintenant exécuter le fichier script.py à partir de n’importe quel emplacement.
e.g :
python script.py
python /path to folder/script.py
Une autre solution consiste à créer le nom de fichier 'xxx (n'importe quel nom) .pth' et à écrire le répertoire de votre projet (répertoire principal de votre src). Placez ce fichier dans '/ virtual_env/lib/pythonXX/site-packages /'. De cette façon, vous n'avez pas besoin d'importer sys.path dans votre script.