views:

2129

answers:

6

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))
+1  A: 

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

dfa
actually, __import__ is a builtin and should work
Rick Copeland
just noticied the implementation of __import__ using the imp module; thanks :)
dfa
+5  A: 

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
+3  A: 

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'])
jcoon
Actually, the __import__ part is throwing an error..
Ian
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
Doing this worksstructures = __import__('structures')But the fromlist part doesn't return the module, it returns the parent "structure" instead. :(
Ian
How are you calling it? Maybe are you trying to do this?: from structures import index
jcoon
I updated the parent. Check it out.
Ian
I updated my answer, and I made some assumptions based o comments you left on other answers.
jcoon
A: 

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
I'm guessing he wants to import multiple modules dynamically. Ian? Any response to this?
jcoon
And by "dynammic" I'm assuming Ian means that he doesn't know what he is importing until runtime.
jcoon
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
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
@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
+2  A: 

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
A: 
>>> 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!