Essentially, when you execute script.py
directly, it doesn't know that it's part of a submodule of src
, nor does it know where a module named src
might be. This is the case in either python 2 or 3.
As you know, Python finds modules based on the contents of sys.path
. In order to import any module, it must either be located in a directory that's listed in sys.path
, or, in the same directory as the script that you're running.
When you say python src/scripts/script.py
, sys.path
includes the Project/src/scripts/
(because that's where script.py
is located), but not Project
. Because Project
isn't in the path, the modules in that directory (src
) aren't able to be imported.
To fix this:
I'm assuming that your script.py
is an entry point for your src
module (for example, maybe it's the main program). If that's true, then you could fix it by moving script.py
up to the same level as src
:
Project
├───.git
├───venv
|───script.py <--- script.py moves up here
└───src
├───__init__.py
└───mymodules
├───__init__.py
├───module1.py
└───module2.py
This way, script.py
can freely import anything in src
, but nothing in src
can import script.py
.
If that's not the case, and script.py
really is a part of src
, you can use python's -m
argument to execute script.py
as part of the src
module like so:
$ python -m src.scripts.script
Because you've told python which module you're running (src
), it will be in the path. So, script.py
will be aware that it's a submodule of src
, and then will be able to import from src
.
Be careful in this situation though - there's potential to create a circular import if something in src
imports src.scripts.script
.
As an alternative to both of these approaches, you can modify the sys.path
directly in script.py
:
import sys
sys.path.insert(0, '/path/to/Project') # location of src
While this works, it's not usually my preference. It requires script.py
to know exactly how your code is laid out, and may cause import confusion if another python program ever tries to import script.py
.