14

Possible Duplicate:
Dynamic module import in Python

Probably a simple question! I need to iterate through a list of classes (as strings) passed from a settings file. The classes are listed like below:

TWO_FACTOR_BACKENDS = (
    'id.backends.AllowToBeDisabled', # Disable this to enforce Two Factor Authentication
    'id.backends.TOTPBackend',
    'id.backends.HOTPBackend',
    #'id.backends.YubikeyBackend',
    #'id.backends.OneTimePadBackend',
    #'id.backends.EmailBackend',
)

I now need to call the authenticate() function on each of these classes (unless commented out, of course). I'm happily iterating through the list, I just need to know how to convert the strings to a Class object in my foreach loop so that I can call the authenticate method on it. Is there an easy way to do this?

2
  • Do you want authenticate() called on the classes, or on objects of those classes? Commented May 27, 2012 at 10:54
  • Sorry, authenticate() is called on the classes, not the objects of the classes. Should have made that more clear sorry! Commented May 27, 2012 at 12:48

1 Answer 1

46

You want to use the importlib module to handle loading of modules like this, then simply use getattr() to get the classes.

For example, say I have a module, somemodule.py which contains the class Test:

import importlib

cls = "somemodule.Test"
module_name, class_name = cls.split(".")

somemodule = importlib.import_module(module_name)

print(getattr(somemodule, class_name))

Gives me:

<class 'somemodule.Test'>

It's trivial to add in things like packages:

cls = "test.somemodule.Test"
module_name, class_name = cls.rsplit(".", 1)

somemodule = importlib.import_module(module_name)

And it will not import a module/package if it's already been imported, so you can happily do this without keeping track of loading modules:

import importlib

TWO_FACTOR_BACKENDS = (
    'id.backends.AllowToBeDisabled', # Disable this to enforce Two Factor Authentication
    'id.backends.TOTPBackend',
    'id.backends.HOTPBackend',
    #'id.backends.YubikeyBackend',
    #'id.backends.OneTimePadBackend',
    #'id.backends.EmailBackend',
)

backends = [getattr(importlib.import_module(mod), cls) for (mod, cls) in (backend.rsplit(".", 1) for backend in TWO_FACTOR_BACKENDS)]

 

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.