0

I have a Python project (an application) with the following project structure (adapted from https://realpython.com/python-application-layouts/#installable-single-package):

Helloworld/
├── helloworld/
│   ├── __init__.py
│   ├── __main__.py
│   └── helloworld.py
│
└── .gitignore

__init__.py is empty.

__main__.py:

import helloworld.helloworld

if __name__ == '__main__':
    helloworld.helloworld.run()

helloworld.py:

def run():
    print("Hello World!")

Executing python -m helloworld works as expected and prints "Hello World!". Executing python helloworld/__main__.py gives a ModuleNotFoundError:

File "C:\Users\<username>\repos\HelloWorld\helloworld\__main__.py", line 4, in <module>
    import helloworld.helloworld
ModuleNotFoundError: No module named 'helloworld.helloworld'; 'helloworld' is not a package

I have figured out that there are two issues causing the error:

  1. The direct call of the __main__.py script implies that the Python interpreter looks for modules inside HelloWorld/helloworld/, and not (as in the -m option case) inside HelloWorld/. As a solution to this problem I found that I can add the HelloWorld/ directory to sys.path. __main__.py then becomes:
import sys
sys.path.append('../helloworld')

import helloworld.helloworld

if __name__ == '__main__':
    helloworld.helloworld.run()

This still does not work and throws the exact same ModuleNotFoundError, which is due to the second issue:

  1. The interpreter still doesn't recognize the package correctly, because it has the same name as the module.

If I rename the module helloworld.py to e.g. app.py and update the __main__.py as follows, the code also works when executing python helloworld/__main__.py:

__main__.py:

import sys
sys.path.append('../helloworld')

import helloworld.app

if __name__ == '__main__':
    helloworld.app.run()

I have two questions:

  1. Is my project structure, in the first place, appropriate? I believe this is a common structure, but could not find an answer to this specific problem.
  2. Are there better or alternative solutions to the problem that allow me to name the module in the same way as the package (which appears to be quite common)?

I have looked into a lot of solutions regarding relative imports (e.g. Relative imports for the billionth time) but couldn't make it work.

dende
  • 23
  • 4

0 Answers0