How do I run a Bash script that calls a Python script from anywhere?
I have a Python script, say myscript.py
that uses relative module imports, i.e. from .. import module1
where my project layout looks like this:
project
+ outer_module
- __init__.py
- module1.py
+ inner_module
- __init__.py
- myscript.py
- myscript.sh
And I have a Bash script, say myscript.sh
, which is a wrapper for my python script as shown below:
#!/bin/bash
python -m outer_module.inner_module.myscript $@
This works for execution myscript.py
and redirects arguments to my script as desired, but only works when called ./outer_module/inner_module/myscript.sh
from the directory project
shown above.
How can I make this script work from anywhere? For example, how can I make this work for a type call bash /root/to/my/project/outer_module/inner_module/myscript.sh
?
Here are my attempts:
When you run myscript.sh
from another location, I get the following error: No module named outer_module.inner_module
. Then I tried a different approach to execute a Bash script from anywhere, replacing myscript.sh
with:
#!/bin/bash
scriptdir=`dirname "$BASH_SOURCE"`
python $scriptdir/myscript.py $@
When I execute myscript.sh
as shown above, I get this:
Traceback (most recent call last):
File "./inner_module/myscript.py", line 10, in <module>
from .. import module1
ValueError: Attempted relative import in non-package
This is due to the relative imports on the first line in myscript.py
, as mentioned earlier, which is from .. import module1
.
source to share
You need to specify the path to the external module's parent directory in an environment variable PYTHONPATH
, then you can use the same command you used in the first script from anywhere.
PYTHONPATH
where python looks for any modules you are trying to import:
#!/bin/bash
export PYTHONPATH=$PYTHONPATH:PATH/TO/MODULE/PARENTDIR
python -m outer_module.inner_module.myscript $@
source to share
As the error message says:
ValueError: Attempted relative import in non-package
The solution to this is to create a package and execute a script with that package in its path.
You already have a package because you have files __init__.py
in those directories; but you only have this package in your path when you call it from the project directory as you mentioned; because it .
is in your Python path by default.
To fix this, just add the project directory to your Python path and then call it with python -m outer_module.inner_module.myscript
:
#!/bin/bash
export PYTHONPATH=$PYTHONPATH:$(dirname "$BASH_SOURCE")/../..
python -m outer_module.inner_module.myscript $@
source to share