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:
1
2
3
4
5
6
7
|
$ tree
.
├── main.py
└── plugins
├── __init__.py
├── plugin_a.py
├── plugin_b.py
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
|
$ 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()
|
1
2
3
4
5
6
7
8
9
10
11
|
$ cat plugins/plugin_a.py
import plugins
class PluginA(plugins.Base):
def __init__(self):
pass
def start(self):
print("Plugin A")
|
And now the main.py
:
1
2
3
4
5
6
7
|
$ cat main.py
from plugins import Base
if __name__ == '__main__':
for p in Base.plugins:
inst = p()
inst.start()
|