views:

36

answers:

1

Hi, I am trying to understand an other magic thing about django: it can convert strings to modules. In settings.py, INSTALLED_APPS is declared like that:

INSTALLED_APPS = (
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
)

All it contains is strings. But django will convert those strings to modules and import them later.

I want to do be able to do the same thing. but i don't know how. I have a dictionnary of rederer dispatcher in settings.py:

RESOUCE_RENDERER = {
    'video': 'video_player',
    'audio': 'audio_player', 
}

I want to use it later like this: RESOURCE_RENDERER'video' I cannot assign directly the function name(eg video_player) because it lives in a module that needs settings.py

Any idea?

+4  A: 

Take a look in django.conf.__init__.py, but basically it uses importlib like so:

try:
    mod = importlib.import_module(self.SETTINGS_MODULE)
except ImportError, e:
    raise ImportError("Could not import settings '%s' 
               (Is it on sys.path? Does it have syntax errors?):
                %s" % (self.SETTINGS_MODULE, e))

# Settings that should be converted into tuples if they're mistakenly entered
# as strings.
tuple_settings = ("INSTALLED_APPS", "TEMPLATE_DIRS")

Edit: At the request of the OP I've expanded the example and contributed some more below.

Now, suppose you had a list of functions in this module, defined in for example FUNCTIONS TO CALL, a list of functions. Then, you could call each like this:

ARGUMENTS = '()'

for FUNCTION in FUNCTIONS_TO_CALL:
    function_string = FUNCTION + ARGUMENTS
    exec(function_string)

This assumes each function has the same set of defined arguments. You could use an if statement to detect the function name listed by the user and supply custom arguments depending on what this is. You could also evaluate from reading the python file what the arguments should be.

You could also check the module object to (I assume this is possible, I don't know) see if that function exists before calling exec() or eval(). I don't know, again, if one can evaluate from the function object what arguments it takes. I suspect so, but this is a separate (possibly already answered?) question.

Ninefingers
@Ninefingers, this would help, but i am looking to import functions, not just modules. Do you know how i can achieve that?
maroxe
i guess __import__ is what i am looking for
maroxe
Yes and no. The import statement is a wraparound for the importlib functions, as such, when you fun import_module you *have* imported a variable module *as if* you'd asked for "import somevariable". I don't think you can `import` variable names but you can via this library. Now, once you've imported a module you have access to everything in it - I expanded the example above to include the code accessing `INSTALLED_APPS` from the settings file, as you discussed in the q.
Ninefingers
@Ninefingers i meaned import wrapped with two underscores(the parser maked it bold instead). I wan't to be able to call a function from a string, just a string. And i don't understand your new example(i guess you've forgotten some lines)
maroxe
I should add this is called Reflection in .net/java.
Ninefingers
@maroxe Either or, they are equivalent. http://docs.python.org/dev/py3k/library/importlib.html#importlib.__import__. Take a look at: http://code.djangoproject.com/browser/django/trunk/django/conf/__init__.py#L71. This is the full code that I'm looking at. What's happening is they're using INSTALLED_APPS in that compilation unit, but it is defined in the loaded module. In the same vein, if you load a module `foo` with a function `bar` in it into your module (wherever that is) you can just use bar straight away - you have imported the function.
Ninefingers
Or to put it another way, the INSTALLED_APPS they refer to in that line of code is the one you defined in your settings.py - so if you define a function in settings.py you would be able to access it in this file, after running the importlib.import_module statement and assuming it succeeds.
Ninefingers
@Ninefingers, i cannot access function bar straight way, because i don't know the name of the function before the execution of the program. i have just a string 'bar', and i want to call the function whose name is in the string.
maroxe
Aaah. Hold on. Will edit answer.
Ninefingers