pythonpython-3.xmodulenotfounderror

Python: Module not found: Why did venv solve it?


I have the following project structure:

- project
  - src
    - module_a
      - foo.py
      - __init__.py
    - runner.py
    - constants.py
    - __init__.py

constants.py:

SOME_CONST = 5

foo.py:

from src.constants import SOME_CONST
class Foo:
    def some_func(self):
        ....

runner.py:

from src.module_a.foo import FOO

def main():
    Foo.some_func()

if __name__ == "__main__":
    main()

I am trying to run python runner.py from the src folder, but it gave me a ModuleNotFound about src when foo.py was trying to import from src.constants import SOME_CONST.

I understand that the issue was the Python interpreter didn't recognise the src folder as a module, even though it has an __init__.py file. After creating a venv virtual environment, the issue was resolved.

I have the following questions:

  1. Why didn't the Python interpreter recognise the src folder as a module before creating a virtual environment?
  2. Why did creating a virtual environment solve the issue?
  3. How can I set up the project so that it will run without setting a virtual environment?

Solution

  • You should not treat src as a package, but rather a directory that will be added to sys.path when you execute runner.py. Thus, constants and module_a are top-level modules, not submodules of a src package.

    constants.py:

    SOME_CONST = 5
    

    foo.py:

    from constants import SOME_CONST
    class Foo:
        def some_func(self):
            ....
    

    runner.py:

    from module_a.foo import FOO
    
    def main():
        Foo.some_func()
    
    if __name__ == "__main__":
        main()
    

    When you install to a virtual environment, module_a and constants should be installed under venv/lib, while runner.py should be installed under venv/bin, breaking your former assumption that runner.py and the modules all lived in the same directory.