Directory structure:
root/
script.py
package/
__init__.py
module1.py
module2.py
In script.py
I need to import a method from module1.py
and run it.
#contents of script.py
from package.module1 import func1
func1()
The method in module1.py
requires a method from module2.py
.
#contents of module1.py
from package.module2 import func2
def func1():
func2()
if __name__ == "__main__":
func1()
The above code works if I run script.py
directly. There are some situations, however, where I need to run module1.py
directly via crontab
and this is where the problem lies.
When the cronjob runs, I get an error saying func2
can't be found. I can run module1.py
if I modify the import to the following:
#contents of module1.py
from module2 import func2
def func1():
func2()
if __name__ == "__main__":
func1()
I can make both situations work if I add an else
statement in module1.py
but it looks so hacky:
#contents of module1.py
def func1():
func2()
if __name__ == "__main__":
from module2 import func2
func1()
else:
from package.module2 import func2
func1()
How can I do this more pythonically? Maybe I need to utilize __init__.py
somehow? It's just an empty file at the moment.
When running a file with python file.py
python does not look at the directory containing file
for __init__.py
. This means you cannot use import package.module
nor from .module import x
imports.
The way to fix this is to tell python that file.py
is part of a package. This is done by using the -m
switch:
python -m package.module1
So you don't have to fix your code, you have to fix your crontab
command!
This said: I personally never like to run modules. I'd rather write a run_module1.py
script outside the package that simply contains:
from package import module1
module1.func1()
Then run run_module1.py
instead of running module1.py
directly.
I don't think there is any good reason to want to run module1.py
as you are doing and expecting it to work without hacky imports as you tried. AFAIK there is no non-hackish solution to that.