This question is related to Can't import module with importlib.import_module, which I don't think got to the root of the issue at all.
I'm trying to understand the reason for differences with importlib
used in the interactive interpreter vs. a non-interactive script, because I'm getting different results with each.
I have a folder containing myscript.py
, and I want it to import a module called module
from a subfolder, my_subdir
of the initial working directory. I want to do this by moving into that directory and working there. I know there are other solutions to accessing a module in a subdirectory, but this is the use case that I'd like to talk about.
The following is the contents of myscript.py
, which simply moves into the subdirectory and tries to import the module from there, and then call some hello-world function from the module:
#!/home/chris/anaconda2/bin/python
import sys
import platform
import os
import importlib
print("Python version "+ platform.python_version())
print(sys.path)
os.chdir('my_subdir')
my_module = importlib.import_module('module')
my_module.my_function()
When I run this from the command line, Python can't find the module. It seems that the import system doesn't know about the change of directory from os.chdir()
:
(base) chris@linux-om3m:~/workspace> python myscript.py
Python version 2.7.15
['/home/chris/workspace', '/home/chris/anaconda2/lib/python27.zip', '/home/chris/anaconda2/lib/python2.7', '/home/chris/anaconda2/lib/python2.7/plat-linux2', '/home/chris/anaconda2/lib/python2.7/lib-tk', '/home/chris/anaconda2/lib/python2.7/lib-old', '/home/chris/anaconda2/lib/python2.7/lib-dynload', '/home/chris/anaconda2/lib/python2.7/site-packages', '/home/chris/anaconda2/lib/python2.7/site-packages']
Traceback (most recent call last):
File "myscript.py", line 11, in <module>
my_module = importlib.import_module('module')
File "/home/chris/anaconda2/lib/python2.7/importlib/__init__.py", line 37, in import_module
__import__(name)
ImportError: No module named module
However, when I type the same script into the interactive interpreter, it works fine:
(base) chris@linux-om3m:~/workspace> python
Python 2.7.15 | packaged by conda-forge | (default, Jul 2 2019, 00:39:44)
[GCC 7.3.0] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> import platform
>>> import os
>>> import importlib
>>> print("Python version "+ platform.python_version())
Python version 2.7.15
>>> print(sys.path)
['', '/home/chris/anaconda2/lib/python27.zip', '/home/chris/anaconda2/lib/python2.7', '/home/chris/anaconda2/lib/python2.7/plat-linux2', '/home/chris/anaconda2/lib/python2.7/lib-tk', '/home/chris/anaconda2/lib/python2.7/lib-old', '/home/chris/anaconda2/lib/python2.7/lib-dynload', '/home/chris/anaconda2/lib/python2.7/site-packages', '/home/chris/anaconda2/lib/python2.7/site-packages']
>>> os.chdir('my_subdir')
>>> my_module = importlib.import_module('module')
>>> my_module.my_function()
Here I am!
>>>
I can fix this issue by manually updating sys.path
with a sys.path.append(os.getcwd())
after I do the os.chdir
- but I do not understand why this is only necessary in non-interactive mode.
The only thing I do notice (and is printed here in the pasted output) is that under the interactive interpreter, sys.path
has an empty-string entry, whereas in non-interactive mode it contains the working dir where I invoked python.
I know I could fix this problem using relative imports, and for now I'm fixing the problem using a sys.path.append(os.getcwd())
, but I'd like to understand why there is a difference between running interactively vs. non-interactively.
I'm getting the same results with Python 2.7 and Python 3.6.