tags:

views:

657

answers:

6

Given a string with a module name, how do you import everything in the module as if you had called:

from module import *

i.e. given string S="module", how does one get the equivalent of the following:

__import__(S, fromlist="*")

This doesn't seem to perform as expected (as it doesn't import anything).

Thanks!

A: 

You don't, that's a very silly idea and entirely unpythonic.

Jerub
You don't answer like this, it's a very silly answer and entirely unhelpful.
jae
Of course I do. I try to use StackOverflow like I use other avenues of programmer education, to educate programmers.Not to facilitate them writing poor programs. That would be evil.
Jerub
Sorry dude, but this *is* a silly and unhelpful answer. You're making the bold assertion that `import *` is something that is *never* useful… Which is demonstrably not true: `grep -R 'import \*' Python-trunk/Lib/`.
David Wolever
Ignore test_*.py files, Tkinter, Carbon, mac, sunos and distutils you're left with 70-odd actual imports. Most of those are doing import * from an accompanying c module that they wrap.
Jerub
So are you implying that tests, Tkinter, Carbon, mac, sunos, disutils and c modules are "entirely unpythonic"? Or are you saying "those are special cases — not something average programmers like Brian need to deal with"?
David Wolever
+11  A: 

Please reconsider. The only thing worse than import * is magic import *.

If you really want to:

m = __import__ (S)
try:
    attrlist = m.__all__
except AttributeError:
    attrlist = dir (m)
for attr in attrlist:
    globals()[attr] = getattr (m, attr)
John Millikin
maybe better: for attr in m.__all__?
Sergei Stolyarov
@Sergei: there's no guarantee that modules will define __all__
John Millikin
@John Millikin: But if a module defines __all__ you should observe it
Florian Bösch
Fixed to obey __all__ hints
John Millikin
To be pedantic, if there is no __all__, only names not starting with a _ are imported.
Thomas Wouters
You're right: it is heinous and evil... and atypical. The reason I ask isn't to include any regular Python module, but to include one of a set of short config modules that change, specific to the computer being used (which don't have __all__ defined, incidentally). I'm refactoring around this. :)
Brian M. Hunt
@BMH: Have you considered a settings aggregator like the one used in Django? Define an object that stores a list of modules to search, and then override __getattr__ to perform a search of them using getattr().
John Millikin
Yes, there's absolutely no reason why each setting should live in a global namespace, that is `options.some_option` is obviously better than `some_option`. You can also use **dict.update()** on module's distionaries in your specific case.
ilya n.
A: 

The underlying problem is that I am developing some Django, but on more than one host (with colleagues), all with different settings. I was hoping to do something like this in the project/settings.py file:

from platform import node

settings_files = { 'BMH.lan': 'settings_bmh.py", ... } 

__import__( settings_files[ node() ] )

It seemed a simple solution (thus elegant), but I would agree that it has a smell to it and the simplicity goes out the loop when you have to use logic like what John Millikin posted (thanks). Here's essentially the solution I went with:

from platform import node

from settings_global import *

n = node()

if n == 'BMH.lan':
  from settings_bmh import *
# add your own, here...
else:
  raise Exception("No host settings for '%s'. See settings.py." % node())

Which works fine for our purposes.

Brian M. Hunt
A: 

I didn't find a good way to do it so I took a simpler but ugly way from http://www.djangosnippets.org/snippets/600/

try:
    import socket
    hostname = socket.gethostname().replace('.','_')
    exec "from host_settings.%s import *" % hostname
except ImportError, e:
    raise e
I can see where this code is coming from, but that call to exec sends shivers down my back. I don't really know if it's a big deal in this case, but I've learned to trust my instincts about things like this.
Jason Baker
This is illegal inside the function, and looks terrible indeed.
ilya n.
A: 

It appears that you can also use dict.update() on module's dictionaries in your case:

config = [__import__(name) for name in names_list]

options = {}
for conf in config:
    options.update(conf.__dict__)

Update: I think there's a short "functional" version of it:

options = reduce(dict.update, map(__import__, names_list))
ilya n.
+1  A: 

Here's my solution for dynamic naming of local settings files for Django. Note the addition below of a check to not include attributes containing '__' from the imported file. The __name__ global was being overwritten with the module name of the local settings file, which caused setup_environ(), used in manage.py, to have problems.

try:
    import socket
    HOSTNAME = socket.gethostname().replace('.','_')
    # See http://docs.python.org/library/functions.html#__import__
    m = __import__(name="settings_%s" % HOSTNAME, globals=globals(), locals=locals(), fromlist="*")
    try:
        attrlist = m.__all__
    except AttributeError:
        attrlist = dir(m)        
    for attr in [a for a in attrlist if '__' not in a]:
        globals()[attr] = getattr(m, attr)

except ImportError, e:
    sys.stderr.write('Unable to read settings_%s.py\n' % HOSTNAME)
    sys.exit(1)
David Marble