Python kan mijn module niet vinden

Ik heb een python-project (dat ik binnen een virtualenv uitvoer) en dat heeft de volgende structuur:

Project
├───.git
├───venv
└───src
    ├───__init__.py
    ├───mymodules
    │   ├───__init__.py
    │   ├───module1.py
    │   └───module2.py
    └───scripts
        ├───__init__.py
        └───script.py

script.py

import src.mymodules.module1
...

Ik voer het project uit met venv geactiveerd en vanuit de map Project met het volgende commando:

(venv)$ python src/scripts/script.py

Het script wordt uitgevoerd, maar geeft de volgende foutmelding voordat het wordt afgesloten:

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

Ik heb geprobeerd de python-shell uit te voeren en de module van daaruit te importeren en het gaf geen fouten. Ik heb _ _init__.py in elke map binnen src. Overweegt python de werkdirectory als src/scripts? Waarom gebeurt dat en hoe kan ik src de werkdirectory maken als dat het geval is?


Antwoord 1, autoriteit 100%

In wezen, wanneer u script.pyrechtstreeks uitvoert, weet het niet dat het deel uitmaakt van een submodule van src, en ook niet waar een module met de naam srczou kunnen zijn. Dit is het geval in python 2 of 3.

Zoals u weet, vindt Python modules op basis van de inhoud van sys.path. Om een module te kunnen importeren, moet deze zich ofwel in een map bevinden die wordt vermeld in sys.path, of in dezelfde map als het script dat u uitvoert.

Als je python src/scripts/script.pyzegt, bevat sys.pathhet Project/src/scripts/(omdat dat waar script.pyzich bevindt), maar niet Project. Omdat Projectniet in het pad staat, kunnen de modules in die map (src) niet worden geïmporteerd.

Om dit op te lossen:

Ik neem aan dat uw script.pyeen toegangspunt is voor uw src-module (misschien is dit bijvoorbeeld het hoofdprogramma). Als dat waar is, kun je het oplossen door script.pynaar hetzelfde niveau te verplaatsen als src:

Project
├───.git
├───venv
|───script.py       <--- script.py moves up here
└───src
    ├───__init__.py
    └───mymodules
        ├───__init__.py
        ├───module1.py
        └───module2.py

Op deze manier kan script.pyalles vrij importeren in src, maar niets in srckan script.py.

Als dat niet het geval is, en script.pyecht een onderdeel is van src, kun je -margument om script.pyuit te voeren als onderdeel van de srcmodule als volgt:

$ python -m src.scripts.script

Omdat je python hebt verteld welke module je gebruikt (src), zal het in het pad staan. Dus script.pyweet dat het een submodule is van src, en kan dan importeren vanuit src.

Wees echter voorzichtig in deze situatie – het is mogelijk om een circulaire import te maken als iets in srcsrc.scripts.scriptimporteert.


Als alternatief voor beide benaderingen kunt u het sys.pathrechtstreeks in script.pywijzigen:

import sys
sys.path.insert(0, '/path/to/Project') # location of src 

Hoewel dit werkt, heeft het meestal niet mijn voorkeur. Het vereist script.pyom precies te weten hoe je code is ingedeeld, en kan importverwarring veroorzaken als een ander python-programma ooit probeert script.pyte importeren.


Antwoord 2, autoriteit 4%

Als u met dit probleem wordt geconfronteerd bij het omgaan met Pytestof coverage. Het toevoegen van het bestand __init__.pylost de meeste gevallen op.


Antwoord 3, autoriteit 2%

Project
├───.git
├───venv
└───src
    ├───__init__.py
    ├───mymodules
    │   ├───__init__.py
    │   ├───module1.py
    │   └───module2.py
    └───scripts
        ├───__init__.py
        └───script.py

U kunt ook als volgt importeren in uw script.py

import os
import sys
sys.path.append(os.path.join(os.path.dirname(__file__),'../../'))
import src.mymodules.module1

Nu kunt u het script.py-bestand vanaf elke locatie uitvoeren.

e.g :
python script.py
python /path to folder/script.py

Antwoord 4

Een andere oplossing is het aanmaken van de bestandsnaam ‘xxx(any name).pth’ en het schrijven van je projectmap (moedermap van je src). Zet dit bestand in ‘/virtual_env/lib/pythonXX/site-packages/’. Op deze manier hoeft u sys.path niet in uw script te importeren.

Other episodes