4

I'm trying to dynamically load modules I've created.

Right now this works properly:

import structures.index

But if I try the same thing by importing it dynamically, it fails.

struct = __import__("structures.index")

Error supplied is:

Error ('No module named structures.index',)

Any ideas why?


Edit: When using full scope (it sort of works?):

struct = __import__("neoform.structures.index")

This doesn't throw any errors, however, it isn't loading the index module, it's loading the "neoform" module instead.

The result of "struct" is:

<module 'neoform' from '/neoform/__init__.py'>

Also, as a side question, how can I then instantiate a class within a dynamically loaded module? (assuming all the modules contain a common class name).

Edit: Solution: (thanks coonj & Rick) This ended up being what worked. Not sure why (yet), but the fromlist had to be something "anything apparently, since it worked when I put the letter "a" as a value (strange, given that the file only had 1 class in it).

def get_struct_module(self, name):
    try:
        return = __import__("neoform.structures." + name, fromlist='*')
    except ImportError, e:
        self.out.add("Could not load struct: neoform.structure." + name + "\n\n" + "Error " + str(e.args))
Ian
  • 24,116
  • 22
  • 58
  • 96
  • 1
    An error message would be useful – Moe Apr 20 '09 at 18:40
  • `__import__('structures.index')` should return you a reference to `structures` just like `import structures.index` does. What is the error you are getting? – Rick Copeland Apr 20 '09 at 18:40
  • Error ('No module named structures.index',) – Ian Apr 20 '09 at 19:01
  • And you're certain that you have some file structures/index.py (and that "import structures.index" does not fail with the same error?) – Rick Copeland Apr 20 '09 at 19:11
  • yep, this is what's confusing me. "import structures.index" works. (just tested it again 10 seconds ago. I replaced the map(...) code with it.. loaded just fine. :( – Ian Apr 20 '09 at 19:13
  • Using map() for the side effect is a bad idea anyway. –  Apr 20 '09 at 19:19
  • I switched to __import__('structures.index') and i get the same error. – Ian Apr 20 '09 at 19:22
  • What do you get if you type map(__import__, ["structures"]) – David Berger Apr 20 '09 at 19:23
  • heh: Error ('No module named structures',) – Ian Apr 20 '09 at 19:32
  • Does the structures/ directory contain an __init__.py file and an index.py file? Or do you have some other file layout? – Rick Copeland Apr 20 '09 at 19:46
  • yep, the full path is "neoform.structures.index", but i'm doing the import from within neoform/__init__.py (structures has an __init__.py as well). I think the problem might be because __import__() acts a bit different than "import xxx", but i've had no extra luck doing __import("neoform.structures.index") or anything similar. – Ian Apr 20 '09 at 19:57
  • FWIW, here is a quick one-liner I've devised to dynamically import a resource from a module: imp = lambda path: reduce(lambda module, next: getattr(module, next), path.split('.')[1:], __import__(path[0:path.index('.')])) – Jay Taylor Mar 01 '13 at 19:15

7 Answers7

12

I'm not sure what "it fails" means, so I'll just mention that __import__('structures.index') should, in fact, work, but it doesn't assign the module name in the current scope. To do that (and then use a class in the dynamically imported module), you'll have to use:

structures = __import__('structures.index')
structures.index.SomeClass(...)

The complete details on __import__ are available here.

Edit: (based on question edit)

To import neoform.structures.index, and return the index module, you would do the following:

structures = __import__('neoform.structures.index', 
                        fromlist=['does not in fact matter what goes here!'])

So if you have a list of package names packages, you can import their index modules and instantiate some MyClass class for each using the following code:

modules = [ __import__('neoform.%s.index' % pkg, fromlist=['a']) 
            for pkg in packages ]
objects = [ m.MyClass() for m in modules ]
Rick Copeland
  • 11,672
  • 5
  • 39
  • 38
4

To import sub-modules, you need to specify them in the fromlist arg of __import__()
Fo example, the equivalent of:

import structures.index

is:

structures = __import__('structures', fromlist=['index'])

To do this in a map is a little more tricky...

import mod1.index
import mod2.index
import mod3.index

For those imports, you would want to define a new function to get the index sub-module from each module:

def getIndexMods(mod_names):
  mod_list = map(lambda x: __import__(x, fromlist='index'))
  index_mods = [mod.index for mod in mod_list]
  return index_mods

Now, you can do this to get references to all index modules:

index_mods = getIndexMods(['mod1', 'mod2', 'mod3'])

Also, if you want to grab sub-modules that are not named 'index' then you could do this:

mod1, mod2, mod3 = map(lambda x,y: __import__(x, fromlist=y), 
  ['mod1', 'mod2', 'mod3'], ['index1', 'index2', 'index3'])
Jason Coon
  • 17,601
  • 10
  • 42
  • 50
  • You actually don't need to use `fromlist` to import sub-modules; try "__import__('os.path')". Works just fine (though it returns os, not os.path.) fromlist emulates "from os import path" which is a different beast. – Rick Copeland Apr 20 '09 at 19:54
  • Doing this works structures = __import__('structures') But the fromlist part doesn't return the module, it returns the parent "structure" instead. :( – Ian Apr 20 '09 at 20:06
  • How are you calling it? Maybe are you trying to do this?: from structures import index – Jason Coon Apr 20 '09 at 20:20
  • I updated my answer, and I made some assumptions based o comments you left on other answers. – Jason Coon Apr 20 '09 at 21:20
3

Use full scope ("neoform.structures.index") with this helper method.

def import_module(name):
    mod = __import__(name)
    components = name.split('.')
    for comp in components[1:]:
        mod = getattr(mod, comp)
    return mod

module = import_module("neoform.structures.index")
# do stuff with module
FogleBird
  • 74,300
  • 25
  • 125
  • 131
2
>>> import imp
>>> fm = imp.find_module('index', ['./structures']) # for submodule
>>> mymod = imp.load_module('structures.index', *fm)
>>> mymod
<module 'structures.index' from './structures/index.pyc'>
>>> x = mymod.insideIndex()
Initialising index class...

Voila!

rorycl
  • 1,344
  • 11
  • 19
1

Java programmer here, but I think you need the imp module

dfa
  • 114,442
  • 31
  • 189
  • 228
0

Really late post here. But I was searching for this question on google. I did some trial and error. Not sure if this snippet will help but here it is. Using it for Flask site.

modules = ['frontend', 'admin']
for module in modules:
    mod = __init__('controllers.%s' % module, fromlist=[module])
    app.register_blueprint(mod.blueprint_mod)


# or
from importlib import import_module
modules = ['frontend', 'admin']
for module in modules:
    mod = import_module('controllers.%s' % module)
    app.regitster_blueprint(mod.blueprint_mod)
jdsantiagojr
  • 476
  • 7
  • 10
0

Why on earth would you replace

import structures.index

with

map(__import__, ["structures.index"])

The first one (a) works, (b) is dynamic and (c) is directly supported. What possible use case is there for replacing easy-to-change, plain-text source with something more complex?

In short: don't do this. It doesn't have any value.


Edit

The "I'm getting the import from a database" is a noble effort, but still not sensible. What code block depends on those imports? That whole code block -- imports and all -- is what you want to execute. That whole code block -- imports, statements and everything -- should be a plain old python module file.

Import that block of code from the file system. Use the database to identify which file, the author of the file -- anything you want to use the database for. But simply import and execute the module the simplest possible way.

S.Lott
  • 384,516
  • 81
  • 508
  • 779
  • 1
    I'm guessing he wants to import multiple modules dynamically. Ian? Any response to this? – Jason Coon Apr 20 '09 at 19:31
  • And by "dynammic" I'm assuming Ian means that he doesn't know what he is importing until runtime. – Jason Coon Apr 20 '09 at 19:34
  • 1
    I'm doing it this way because the string is going to be a variable called from a database.. i simply use a string to simplify the example. – Ian Apr 20 '09 at 19:36
  • 1
    That would be annoying. The reason I'm storing it in a database is because I'm making a mod_wsgi site. Each modfule is a separate page on the site. I've already done this sort of thing with PHP, and I've had more than 300 structures on certain sites, each having it's own hierarchy, permissions, and other attributes. Storing it in the db is the best way I've found. – Ian Apr 20 '09 at 19:45
  • 1
    @Ian: Python is not PHP. The techniques that work for PHP do not always translate to Python. I think what you are doing won't work out very well for Python. Look at TurboGears or web.py for examples of how do to this in Python. – S.Lott Apr 21 '09 at 15:19