web-dev-qa-db-fra.com

Python ne trouve pas mon module

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?

23
CrazyJony

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

15
Seth
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
0
parthiban

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.

0
Guiliang Liu