I get the sense this question has been asked many times before, but somehow none of the answers to seemingly related questions get me to fully understand what's going on.
The situation: I create a package and inside that package I have another package and I want to be able to run all of them directly, for testing purposes i.e.:
\main.py
\package_1\__init__.py
\package_1\module_1.py
\package_1\package_2\__init__.py
\package_1\package_2\module_2.py
Where main.py:
from package_1.module_1 import func_1
func_1()
And module_1.py:
from package_1.package_2.module_2 import func_2
def func_1():
func_2()
if __name__ == "__main__":
func_1()
And module_2.py:
def func_2:
print ("This works")
if __name__ == "__main__":
func_2()
The __init__.py are empty. This allows me to run main.py from the root and it works. I can also run module_2.py from its own folder. But I can't run module_1.py since it complains there is no package_1. That makes some sense, although technically it is itself in package_1. But if I remove that prefix, it breaks main, which also makes some sense.
How to fix this? I tried replacing the import in module_1.py by:
import .package_2.module_2
But that gets me an error I don't fully understand:
ModuleNotFoundError: No module named '__main__.package_2'; '__main__' is not a package
What is the right approach to get all of the packages and modules working as intended? Is it something that should be solved in __init__.py? Or should I simply avoid nesting packages like this and install them all (after providing a setup.py)?
Edit:
@Blckknght suggested running:
python -m package_1.module_1
python -m package_1.package_2.module_1
From the root directory. That works, in that all the code is run as expected. I also updated the import in module_1.py to:
from .package_2.module_2 import func_2
And finally, @jonilyn2730 provided the suggestion to make the main body callable from other scripts by putting it inside a main() function. For example, module_1.py would be:
from package_1.package_2.module_2 import func_2
def func_1():
func_2()
def main():
func_1()
if __name__ == "__main__":
main()
In this trivial example, it makes little difference, but it allows this in other scripts:
from package_1.module_1 import main
main()
So the script no longer has to be called directly and multiple runs can be combined in a single script.