Reputation: 115
I would like to dynamically load .py-Files (plugins) into my program.
After doing some research, I found usually two ways of doing this:
1)
import importlib.util
spec = importlib.util.spec_from_file_location("module.name", "/path/to/file.py")
foo = importlib.util.module_from_spec(spec)
spec.loader.exec_module(foo)
from importlib import import_module
module = import_module("plugins." + modulename)
for name, klass in inspect.getmembers(module, inspect.isclass):
if klass.__module__ == "plugins." + modulename:
instance = klass()
if isinstance(instance, IPluginTemplate):
print("Plugin Call:", instance.do_something(x))
What are the main differences regarding both solutions? Is there a prefered way of doing this?
Upvotes: 3
Views: 2978
Reputation: 1671
In the second example you are running through all members of a module, it is more a brute force approach.
The first example(second also), you can not find what you want. Test for a None if not found or an error during the instantiation.
You can also use import_module direct from importlib. This way you can use getattr to return what you want from the module and return None if an AttributeError is thrown.
You can use this method to return modules, variables, anything that is defined into a module.
import importlib
def get_from_module(module, attr_name):
module = importlib.import_module(module)
try:
return getattr(module, attr_name)
except AttributeError:
return None
klass = get_from_module("plugins." + modulename, classname)
if klass is not None:
instance = klass()
This method is available on my project, cartola, that has some lightweight util methods that I use in multiple projects. It is available at pypi, feel free to import get_from_module or get_from_string from the config module.
See:
Note: References here must be a valid module present in your PYTHONPATH, as you're handling plugins. I'm assuming this is the case.
Upvotes: 1