I have a Python script, say myscript.py, that uses relative module imports, ie from .. import module1, where my project layout is as follows:
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, shown below:
#!/bin/bash
python -m outer_module.inner_module.myscript $@
This works to execute myscript.py and forwards the arguments to my script as desired, but it only works when I call ./outer_module/inner_module/myscript.sh from within the project directory shown above.
How can I make this script work from anywhere? For example, how can I make this work for a call like bash /root/to/my/project/outer_module/inner_module/myscript.sh?
Here are my attempts:
When executing myscript.sh from anywhere else, I get the error: No module named outer_module.inner_module. Then I tried another approach to execute the bash script from anywhere, by replacing myscript.sh with:
#!/bin/bash
scriptdir=`dirname "$BASH_SOURCE"`
python $scriptdir/myscript.py $@
When I execute myscript.sh as shown above, I get the following:
Traceback (most recent call last):
File "./inner_module/myscript.py", line 10, in <module>
from .. import module1
ValueError: Attempted relative import in non-package
Which is due to the relative import on the first line in myscript.py, as mentioned earlier, which is from .. import module1.
(cd $scriptdir && python ./devicelist.py $@)outer_moduleis in, not inouter_moduleitself; otherwiseouter_moduleisn't a package (hence the exception). (It's hard to be too precise since you seem to have switched names for everything halfway through the question, but if you're insideinner_module, it's the same problem.)PYTHONPATH=<the directory that outer_module is in>before running the script.-m, better to have your launcher also use-m; there's no reason to try to debug the differences between running it as a-mmodule vs. running it as a script if you don't actually want any of those differences.setuptoolsto create a trivial installer? Then you could do an in-place build that would build a wrapper for you to use in your source tree, or a normal install that would put the project into site-packages and build a wrapper for you in your bin or scripts directory, and either way, it takes care of all the mess for you.