__import__ confusion

Steven Taschuk staschuk at telusplanet.net
Wed Feb 26 01:13:13 EST 2003


Quoth Leazen:
> 	I'm trying to load modules dinamically. All modules which define a
> class (Plugin) should be imported and an object of the class within them
> created, do you think using __import__ is the way to go or that I should
> keep looking?
> 	Thanks again, first time doing this kind of thing.

Hm.  Never done this sort of thing, but here's my first
impressions, for what they're worth:

I assume you've got a plugins directory somewhere that your app
knows about, and you want to spin through all the *.py files in
that directory, loading each, and instantiating each module's
Plugin class, if it defines one.  Is this correct?

If so, I'm not sure __import__ is best.  For one thing, I think
it'll go wandering off on sys.path looking for the specified
module; but you already know where the file is.  The facilities
provided by the imp module might serve better.

Here's a quicky illustration.  (I hope those more familiar than I
with this subject will offer comments.)

Two trivial plugin files:

    # plugin1.py

    class Plugin(object):
        def __init__(self):
            print 'plugin1 instantiated'
            self.name = "I'm plugin1!"

    # plugin2.py

    class Plugin(object):
        def __init__(self):
            print 'plugin2 instantiated'
            self.name = "I'm plugin2!"

And a script which loads them:

    # loader.py
    import imp
    import os

    PLUGIN_DIR = '.'

    def getplugins():
        plugins = []
        for file in os.listdir(PLUGIN_DIR):
            if file.endswith('.py'):
                modulename = file[:-3]
                try:
                    file, filename, description = imp.find_module(
                        modulename, [PLUGIN_DIR])
                    pluginmodule = imp.load_module(modulename,
                        file, filename, description)
                    if hasattr(pluginmodule, 'Plugin'):
                        print 'Instantiating plugin from %s' % pluginmodule
                        try:
                            plugins.append(pluginmodule.Plugin())
                        except Exception, e:
                            print 'Urk! %s' % e
                    else:
                        print 'No plugin in %s' % pluginmodule
                finally:
                    if file:
                        file.close()
        return plugins

    if __name__ == '__main__':
        plugins = getplugins()
        for plugin in plugins:
            print plugin.name

Result:
    $ python loader.py
    Instantiating plugin from <module 'plugin1' from './plugin1.pyc'>
    plugin1 instantiated
    Instantiating plugin from <module 'plugin2' from './plugin2.pyc'>
    plugin2 instantiated
    No plugin in <module 'loader' from './loader.pyc'>
    I'm plugin1!
    I'm plugin2!

Seems to work, anyway.

Some caveats:
    - The loader should look for *.pyc and *.pyo files too.  Maybe even
      *.so files.
    - The documentation says that imp.load_module() will do a reload if
      the module has already been loaded; this might not be desirable.
      I'm not sure how to prevent it, short of spinning through
      sys.modules.
    - The error handling is clumsy and probably wrong.
    - There's no support for package structures in the plugin directory.

-- 
Steven Taschuk                          staschuk at telusplanet.net
"Its force is immeasurable.  Even Computer cannot determine it."
                            -- _Space: 1999_ episode "Black Sun"





More information about the Python-list mailing list