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:
- 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:
- 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:
- 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.
- 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.