13

I am trying to import modules dynamically in Python. Right now, I have a directory called 'modules' with two files inside (mod1.py and mod2.py). They are simple test functions to return time (ie. mod1.what_time('now') returns the current time).

From my main application, I can import as follows:

sys.path.append('/Users/dxg/import_test/modules')
import mod1

Then, I can execute:

mod1.what_time('now') 

This works correctly.

I am not always going to know what modules are available in the directory. I wanted to import as follows:

tree = []
tree = os.listdir('modules')

sys.path.append('/Users/dxg/import_test/modules')

for i in tree:
  import i

However, I get the error:

ImportError: No module named i

What am I missing?

Dan G
  • 366
  • 1
  • 3
  • 18
  • 1
    related http://stackoverflow.com/questions/40823418 – Uriel Feb 22 '17 at 20:22
  • The above referenced question helps to understand why it does not work; but not if there is a solution to make this work. – Dan G Feb 22 '17 at 20:45
  • Take a look at the [`__import__()`](https://docs.python.org/2/library/functions.html#__import__) function. – martineau Feb 22 '17 at 20:51
  • This [answer](https://docs.python.org/2/library/functions.html#__import__) of mine shows using `__import__()` with `listdir()`. It's doing more than you want, but that should be easy to fix. – martineau Feb 22 '17 at 20:56
  • Q: If you don't know what modules are available, how will your code know to use them? – martineau Feb 22 '17 at 21:05
  • @martineau; each module is a test case in this application. Each module (test case) has a standard layout with a main function called execute_test(). So based on the file name being the module name, we can trigger the test case to execute. Example : module file name is create_user.py; once imported, we could trigger with create_user.execute_test(). – Dan G Feb 22 '17 at 21:23

2 Answers2

14

The import instruction does not work with variable contents (as strings) (see extended explanation here), but with file names. If you want to import dynamically, you can use the importlib.import_module method:

import importlib
tree = os.listdir('modules')

...

for i in tree:
    importlib.import_module(i)

Note:

  • You can not import from a directory where the modules are not included under Lib or the current directory like that (adding the directory to the path won't help, see previous link for why). The simplest solution would be to make this directory (modules) a package (just drop an empty __init__.py file there), and call importlib.import_module('..' + i, 'modules.subpkg') or use the __import__ method.

  • You might also review this question. It discusses a similar situation.

Community
  • 1
  • 1
Uriel
  • 15,579
  • 6
  • 25
  • 46
-2

You can achieve something like what you are proposing, but it will involve some un-pythonic code. I do not recommend doing this:

dynamic_imports = dict()
for filename in tree:
    name = filename.replace('.py', '')
    dynamic_imports[name] = __import__(name)
wim
  • 338,267
  • 99
  • 616
  • 750
Tom Lynch
  • 893
  • 6
  • 13