-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathplugin_collection.py
93 lines (73 loc) · 3.66 KB
/
plugin_collection.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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
import inspect
import json
import os
import pkgutil
# This code and the style of set-up should be attributed to GitHub user gdiepen
# at https://github.com/gdiepen/python_plugin_example
# To make a plugin "discoverable" to this script. Have the plugin class inherit the Plugin class (just below)
class Plugin(object):
"""Base class that each plugin must inherit from. within this class
you must define the methods that all of your plugins must implement
"""
def __init__(self):
self.description = 'UNKNOWN'
def perform_operation(self, argument):
"""The method that we expect all plugins to implement. This is the
method that our framework will call
"""
raise NotImplementedError
class PluginCollection(object):
"""Upon creation, this class will read the plugins package for modules
that contain a class definition that is inheriting from the Plugin class
"""
def __init__(self, plugin_package):
"""Constructor that initiates the reading of all available plugins
when an instance of the PluginCollection object is created
"""
self.plugin_package = plugin_package
self.reload_plugins()
def reload_plugins(self):
"""Reset the list of all plugins and initiate the walk over the main
provided plugin package to load all available plugins
"""
self.plugins = []
self.seen_paths = []
# print()
# print('Looking for plugins under package {}'.format(self.plugin_package))
self.walk_package(self.plugin_package)
def apply_all_plugins_on_value(self, args):
"""Apply all of the plugins on the argument supplied to this function
"""
# print()
# print('Applying all plugins on value {}:'.format(args))
for plugin in self.plugins:
# print(' plugin desc: {} args: {}'.format(plugin.description, json.dumps(args)))
plugin.perform_operation(**args)
def walk_package(self, package):
"""Recursively walk the supplied package to retrieve all plugins
"""
imported_package = __import__(package, fromlist=['blah'])
for _, pluginname, ispkg in pkgutil.iter_modules(imported_package.__path__, imported_package.__name__ + '.'):
if not ispkg:
plugin_module = __import__(pluginname, fromlist=['blah'])
clsmembers = inspect.getmembers(plugin_module, inspect.isclass)
for (_, c) in clsmembers:
# Only add classes that are a sub class of Plugin, but NOT Plugin itself
if issubclass(c, Plugin) & (c is not Plugin):
# print(' Found plugin class: {}.{}'.format(c.__module__, c.__name__))
self.plugins.append(c())
# Now that we have looked at all the modules in the current package, start looking
# recursively for additional modules in sub packages
all_current_paths = []
if isinstance(imported_package.__path__, str):
all_current_paths.append(imported_package.__path__)
else:
all_current_paths.extend([x for x in imported_package.__path__])
for pkg_path in all_current_paths:
if pkg_path not in self.seen_paths:
self.seen_paths.append(pkg_path)
# Get all sub directory of the current package path directory
child_pkgs = [p for p in os.listdir(pkg_path) if os.path.isdir(os.path.join(pkg_path, p))]
# For each sub directory, apply the walk_package method recursively
for child_pkg in child_pkgs:
self.walk_package(package + '.' + child_pkg)