21
votes

Possible Duplicate:
Dynamic module import in Python

I intend to make a suite of files at some point soon, and the best way to organize it is to have a list, that list will be at the very top of a file, and after it will come a ridiculous amount of code to handle what that list controls and how it operates. I'm looking to write said list only once, and said list is a list of folder and file names in this format:

[(folder/filename, bool, bool, int), (folder/filename, bool, bool, int)]

As you can see, folder/filename are the same (sort of). File name is folder name with .py on the end, but doing import XXX you don't need to do import XXX.py, so I don't see this causing an issue.

The problem I'm facing is importing using this method...

for (testName, auto, hardware, bit) in testList:
    print(testName)
    paths = "\\" + testName
    print paths
    addpath(paths)
    sys.modules[testName] = testName # One of a few options I've seen suggested on the net
    print("Path Added")
    test = testName + ".Helloworld()"
    eval(test)

So for each test I have, print the name, assemble a string which contains the path ("\\testName"), for this example, print the test path, then add the path to the list (sys.path.append(path)), then print to confirm it happened, then assemble a string which will be executed by eval for the tests main module and eventually eval it.

As you can see, I'm currently having to have a list of imports at the top. I can't simply do import testName (the contents of testName are the name of the module I wish to import), as it will try to find a module called testName, not a module called the contents of testName.

I've seen a few examples of where this has been done, but can't find any which work in my circumstances. If someone could literally throw a chunk of code which does it that would be wonderful.

I'd also request that I'm not hung, drawn, nor quartered for use of eval, it is used in a very controlled environment (the list through which it cycles is within the .py file, so no "end user" should mess with it).

3
Note that the indentation is correct in ST, for some reason I think this website just doesn't like parsing my text correctly :( - XtrmJosh
Don't use tabs but spaces for indentation. - Martijn Pieters♦
Python already has a way of managing large collections of .py files that you might want to import, which understands folders and subfolders, lets you handle relative imports, does namespacing properly, and so on. It's called a package. Is there a reason you don't want to use one? - Katriel

3 Answers

52
votes

Not sure if I understood everything correctly, but you can import a module dynamically using __import__:

mod = __import__(testName)
mod.HelloWorld()

Edit: I wasn't aware that the use of __import__ was discouraged by the python docs for user code: __import__ documentation (as noted by Bakuriu)

This should also work and would be considered better style:

import importlib

mod = importlib.import_module(testName)
mod.HelloWorld()
21
votes
  1. Never, ever, ever mess with sys.modules directly if you don't know exactly what you are doing.
  2. There are a lot of ways to do what you want:
    1. The build-in __import__ function
    2. Using imp.load_module
    3. Using importlib.import_module

I'd avoid using __import__ directly, and go for importlib.import_module(which is also suggested at the end of the documentation of __import__).

2
votes

Add the path where module resides to sys.path. Import the module using __import__ function which accepts a string variable as module name.

import sys
sys.path.insert(0, mypath)  # mypath = path of module to be imported
imported_module = __import__("string_module_name") # __import__ accepts string 
imported_module.myfunction()   # All symbols in mymodule are now available normally