Errors while dynamic imports using importlib in python3

Umang Gupta picture Umang Gupta · May 11, 2018 · Viewed 9.3k times · Source

I have been trying to use importlib with python3 (3.6).

Directory structure

main.py

#Note: I will only modify line 4 that uses importlib
import importlib
if __name__ == '__main__':
    print("In main.py")
    hello = importlib.import_module('hello', package='./')
    print("Loaded hello.py")
    hello.hello()

hello.py

def hello():
    print('Hello world')

folder/hello.py

def hello():
    print('Hello world in folder')

Observations

If I do

hello = importlib.import_module('hello', package='./') or

hello = importlib.import_module('hello')

It imports hello.py from the root folder and prints hello world.

If I do

hello = importlib.import_module('folder.hello')

It imports folder/hello.py from the root folder and prints hello world in folder.

But if I do

hello = importlib.import_module('hello', package='folder') or

hello = importlib.import_module('hello', package='./folder')

It gives error

Traceback (most recent call last):
  File "main.py", line 4, in <module>
    hello = importlib.import_module('hello', package='./folder')
  File "/usr/lib/python3.6/importlib/__init__.py", line 126, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "<frozen importlib._bootstrap>", line 994, in _gcd_import
  File "<frozen importlib._bootstrap>", line 971, in _find_and_load
  File "<frozen importlib._bootstrap>", line 953, in _find_and_load_unlocked
ModuleNotFoundError: No module named 'hello'

Problem

I am not sure what is going on here. I am pretty sure there is something wrong with my understanding of python modules and packages. Can someone explain why this is the expected behavior?

Answer

Mahesh picture Mahesh · May 12, 2018

If the first argument, the module to be imported is an absolute module reference ( has no leading .), the seond argument is completely ignored.

To import a module a relative to another module b, you have to use

a = importlib.import_module('.a', package='b')

In your case, this should work

hello = importlib.import_module('.hello', package='folder')

As a rule of thumb, import package should work if you want to use package as second argument.

from package import module

then becomes

importlib.import_module(module, package)