TripWired
TripWired

Reputation: 378

How to dynamically load module based on command line argument?

I have a project that has a plugins folder and is run with python Project.py --plugin TestPlugin.test.

The directory structure looks like:

plugins/
    TestPlugin/
        test.py
Project.py
PluginLoader.py

I'm having trouble loading test.py as a module with the pluginloader.

In PluginLoader.py this is my function:

def loadPlugin(pluginName): #would be "TestPlugin.test" this is passed in from Project.py which gets the value from parseargs.
    plugin = pluginName.rsplit(".", 1) 


    if len(plugin) == 2:
        module = import_module( plugin[1], package='.'.join(["plugins", plugin[0]])
        print(getattr(module, "test"))
        return module

I keep getting this error:

python Project.py --plugin TestPlugin.test
Traceback (most recent call last):
  File "Project.py", line 107, in <module>
    plugin = PluginLoader.loadPlugin( comArgs.plugin )
  File "PluginLoader.py", line 15, in loadPlugin
    module = import_module( plugin[ 1 ], package = ".".join( ["plugins", plugin[ 0 ] ] ) )
  File "/Users/********/anaconda/lib/python3.5/importlib/__init__.py", line 126, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "<frozen importlib._bootstrap>", line 986, in _gcd_import
  File "<frozen importlib._bootstrap>", line 969, in _find_and_load
  File "<frozen importlib._bootstrap>", line 956, in _find_and_load_unlocked
ImportError: No module named 'test'

I'm still fairly new to python and I know I'm probably not setting up my modules correctly, but I'm not sure why.

Upvotes: 0

Views: 502

Answers (1)

zwer
zwer

Reputation: 25769

In order for your module to be recognized as such, your *.py file needs to be accessible either from the paths in sys.path, or it needs to be in a directory that has __init__.py file. Also, since you're not doing a relative import, you don't need to define a package (but you can totally use plugins for that if you declare your plugin name as 'relative' to it, i.e. by adding a dot in front of its declared name).

So, make your directory structure as:

plugins/
    TestPlugin/
        __init__.py
        test.py
    __init__.py
Project.py
PluginLoader.py

And have your PluginLoader.py have:

import importlib

def load_plugin(plugin):
    mod = importlib.import_module("." + plugin, "plugins")
    print(getattr(mod, "test"))
    return mod

And all should be well.

Upvotes: 1

Related Questions