27

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).

Community
  • 1
  • 1
XtrmJosh
  • 889
  • 2
  • 14
  • 33
  • Note that the indentation is correct in ST, for some reason I think this website just doesn't like parsing my text correctly :( – XtrmJosh Dec 28 '12 at 14:39
  • 1
    Don't use tabs but spaces for indentation. – Martijn Pieters Dec 28 '12 at 14:41
  • 2
    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](http://docs.python.org/2/tutorial/modules.html#packages). Is there a reason you don't want to use one? – Katriel Dec 28 '12 at 14:50
  • duplicate also of: http://stackoverflow.com/questions/8718885/import-module-from-string-variable – 0 _ Jun 23 '15 at 16:23

3 Answers3

66

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()
lbonn
  • 2,499
  • 22
  • 32
  • Marvelous, thanks a ton for this, spent well over an hour scouring for information on it, I managed to write out __import__(testName) earlier, but didn't realise I had to assign the response to a module or w.e, fortunately all my functions will be named Test throughout all files, so I can just call mod.Test() from now on. – XtrmJosh Dec 28 '12 at 14:50
  • @XtrmJosh have you seen the other answer? `__import__` is an implementation detail; you should use `importlib` (or `imp` if you don't care about Python 3.x compatibility). – Katriel Dec 28 '12 at 14:54
  • 1
    What kind of values are allowed for testName? Do I put `.py` at the end? Do I provide a relative path or an absolute path? – Aaron Franke Jul 17 '22 at 22:22
  • 1
    Aaron lead me to the solution to my problem. I added `.py` to `testName`. This does not work. Use your file name without extension! – Peter Oct 13 '22 at 08:53
24
  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__).

Bakuriu
  • 98,325
  • 22
  • 197
  • 231
  • 2
    This is for `import moduleName` where moduleName is string. How about `from moduleName import *` ? – Nam G VU May 30 '17 at 06:57
  • 2
    @NamGVU try to import the module as above and then: `globals().update(module.__dict__)` – Bakuriu May 30 '17 at 07:10
  • I just found another solution here which import only the user-defined variables https://stackoverflow.com/a/31306598/248616 – Nam G VU May 30 '17 at 07:50
  • 2
    Where can I find examples of how to do this? I want to run methods defined in Python scripts in subfolders. Do I provide a relative path? Absolute path? Do I put a `.py` suffix? – Aaron Franke Jul 17 '22 at 22:24
2

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
Swapnil
  • 407
  • 4
  • 7