Thursday, May 25, 2017

Python ImportError No module named X



There are sometimes when you want to run a python script from a package directly, and you may encounter “ImportError: No module named X” error. This blog shares why and how to solve it.
Example:

vagrant@stock:/stock/test_python$ tree  .
.
├── p0.py
└── pack1
    ├── __init__.py
    ├── p1.py
    ├── p2.py

vagrant@stock:/stock/test_python$ cat p0.py

print("this is p0")
import pack1.p1

vagrant@stock:/stock/test_python$ cat ./pack1/p1.py

print("this is p1")

import pack1.p2

vagrant@stock:/stock/test_python$ cat ./pack1/p2.py
print("this is p2")

Running p0.py is ok:
vagrant@stock:/stock/test_python$ python ./p0.py
this is p0
this is p1
this is p2

But if you want to run p1.py directly, you will run into the import error:
vagrant@stock:/stock/test_python$ python ./pack1/p1.py
this is p1
Traceback (most recent call last):
  File "./pack1/p1.py", line 7, in <module>
    import pack1.p2
ImportError: No module named 'pack1'


To find out why, we can print python runtime’s path, adding the highlighted into ./pack1/p1.py:
vagrant@stock:/stock/test_python$ cat ./pack1/p1.py

import sys
print('\n'.join(sys.path))

print("this is p1")

And rerun it:
vagrant@stock:/stock/test_python$ python ./pack1/p1.py

/stock/test_python/pack1
/home/vagrant/anaconda3/lib/python3.5
this is p1
Traceback (most recent call last):
  File "./pack1/p1.py", line 7, in <module>
    import pack1.p2
ImportError: No module named 'pack1'

You can see Python add the directory where the script being run is under to the runtime paths, there is no /stock/test_python/pack1/pack1/p1.py, and the error is thrown out. 

To solve this problem, export the current directory:
vagrant@stock:/stock/test_python$ export PYTHONPATH='.'
vagrant@stock:/stock/test_python$ python ./pack1/p1.py

/stock/test_python/pack1
/stock/test_python
/home/vagrant/anaconda3/lib/python3.5
this is p1
this is p2