2

I have the following directory structure

+ code
|
--+ plugins
  |
  -- __init__.py
  -- test_plugin.py (has a class TestPlugin)
  -- another_test_plugin.py (has a class AnotherTestPlugin)
--+ load.py
--+ __init__.py

In load.py, I want to be able to initialize only those classes that the user specifies. For example, lets say I do something like

$ python load.py -c test_plugin # Should only import test_plugin.py and initialize an object of the TestPlugin class

I am having trouble trying to use the "imp" module to do it. It keeps on saying "No such file or directory". My understanding is that it is somehow not understanding the path properly. Can someone help me out with this?

Nikhil Singh
  • 625
  • 2
  • 8
  • 14
  • you say you're having trouble trying to use the 'imp' module, but what code did you try so far? what are you having trouble on? what part of the tutorials/documentation don't you understand? stackoverflow is not a place for other people to write code for you! – zmo May 08 '13 at 10:08
  • did you have a look at http://stackoverflow.com/questions/10675054/how-to-import-the-module-in-python ? – zmo May 08 '13 at 10:10
  • I am trying the following code `import imp` `import.load_source('TestPlugin', 'plugins/test_plugin.py')` – Nikhil Singh May 08 '13 at 10:34
  • I have mistype `import.load_source`. It should be `imp.load_source` – Nikhil Singh May 08 '13 at 10:42
  • 1
    ... and how are we supposed to know what's wrong when you: 1) Didn't show the code you are using and 2) Didn't show the *full traceback* you are getting? – Bakuriu May 08 '13 at 10:46
  • Sorry about missing out on the details. I was trying to figure out the issue and realized that the plugins directory was inside another directory 'lib'. So, I corrected the path and things are working fine now. – Nikhil Singh May 08 '13 at 11:00
  • I think you should be using `importlib` instead – wim May 08 '13 at 11:09
  • @NikhilSingh did you check the answers below? – Saullo G. P. Castro May 24 '14 at 06:10

3 Answers3

0

ok, your problem is a path related problem. You expect that the script is being run in the same directory as where load.py is, where it is not the case.

what you have to do is something like:

import imp, os, plugins

path = os.path.dirname(plugins.__file__)
imp.load_source('TestPlugin', os.path.join(path, 'test_plugin.py')

where plugins is the module containing all your plugins (i.e. just the empty __init__.py), that will help you get the full path to your plugin modules' files.

wim
  • 338,267
  • 99
  • 616
  • 750
zmo
  • 24,463
  • 4
  • 54
  • 90
0

Another solution, if you want a "plugins" discovery tool:

import imp, os
import glob

def load_plugins(path):
  """
  Assuming `path` is the only directory in which you store your plugins,
  and assuming each name follows the syntax:
  plugin_file.py -> PluginFile
  Please note that we don't import files starting with an underscore.

  """
  plugins = {}
  plugin_files = glob.glob(path + os.sep + r'[!_]*.py')
  for plugin_path in plugin_files:
    module_name, ext = os.path.splitext(plugin_path)
    module_name = os.path.basename(module_name)
    class_name = module_name.title().replace('_', '')
    loaded_module = imp.load_source(class_name, plugin_path) # we import the plugin
    plugins[module_name] = getattr(loaded_module, class_name)
  return plugins

plugins = load_plugins(your_path_here)
plugin_name = sys.argv[3]
plugin = plugins.get(plugin_name)
if not plugin:
    # manage a not existing plugin
else:
    plugin_instance = plugin() # creates an instance of your plugin

This way, you can also specify different names by changing your keys, e.g., 'test_plugins' => 'tp'. You don't have to initialize your plugins, but you can still run this function whenever you want to load your plugins at runtime.

Markon
  • 4,480
  • 1
  • 27
  • 39
  • What if the user wrote his own plug-in and would like to load it? The main program cannot hardcode its name, hence a dynamic discovery and *dynamic import* of the plug-in is necessary. – Bakuriu May 08 '13 at 11:44
  • Yeah, it's not so hard to do that. – Markon May 08 '13 at 12:49
-7
exec('import ' + sys.argv[2])
obj = test_plugin.TestPlugin()

Here sys.argv[2] is 'test_plugin' string from command line arguments.

EDIT: Another way to avoid using exec:

import importlib
mod = importlib.import_module(sys.argv[2])
thavan
  • 2,409
  • 24
  • 32