Implementing a basic plugin architecture shouldn't be a complicated task. The solution described here is working but you still have to import every plugin (inheriting from the base class).
This is my solution:
$ tree
.
├── main.py
└── plugins
├── __init__.py
├── plugin_a.py
├── plugin_b.py
$ cat plugins/__init__.py
import os
import traceback
from importlib import util
class Base:
"""Basic resource class. Concrete resources will inherit from this one
"""
plugins = []
# For every class that inherits from the current,
# the class name will be added to plugins
def __init_subclass__(cls, **kwargs):
super().__init_subclass__(**kwargs)
cls.plugins.append(cls)
# Small utility to automatically load modules
def load_module(path):
name = os.path.split(path)[-1]
spec = util.spec_from_file_location(name, path)
module = util.module_from_spec(spec)
spec.loader.exec_module(module)
return module
# Get current path
path = os.path.abspath(__file__)
dirpath = os.path.dirname(path)
for fname in os.listdir(dirpath):
# Load only "real modules"
if not fname.startswith('.') and \
not fname.startswith('__') and fname.endswith('.py'):
try:
load_module(os.path.join(dirpath, fname))
except Exception:
traceback.print_exc()
$ cat plugins/plugin_a.py
import plugins
class PluginA(plugins.Base):
def __init__(self):
pass
def start(self):
print("Plugin A")
$ cat main.py
from plugins import Base
if __name__ == '__main__':
for p in Base.plugins:
inst = p()
inst.start()
$ python main.py
Plugin B
Plugin A
Is there any way for a plugin to import a module or method in main project?
I'd like to expose some function in main application to plugin codes, but have no idea how to do it.
The main application may be compiled and distributed to user, then user can write their own plugin and call the function exposed by main application to add their specific feature.