"""
This module defines the PluginCollection class, which is responsible for discovering and loading
plugin modules that inherit from a base Plugin class. The PluginCollection class recursively walks
through a specified package to find and instantiate plugin classes.
Plugins are expected to perform specific operations within a larger application framework, ensuring
a consistent interface for interaction.
"""
import inspect
import os
import pkgutil
from base_plugin import Plugin
[docs]
class PluginCollection(object):
"""
Manages the collection of plugins by discovering and loading them from a specified package.
Attributes:
plugins (list): A list of instantiated plugin objects.
name_application (list): A list of plugin class names.
seen_paths (list): A list of paths that have already been scanned for plugins.
path_folder (list): A list of module paths where plugins were found.
plugin_package (str): The name of the package to search for plugins.
"""
def __init__(self, plugin_package):
"""
Upon creation, this class will read the plugins package for modules that contains
a class definition that is inheriting from the Plugin class.
Args:
plugin_package (): The folder name of plugins directory. i.e here is "plugins"
"""
self.plugins = None
self.name_application = None
self.seen_paths = None
self.path_folder = None
self.plugin_package = plugin_package
self.reload_plugins()
[docs]
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.
Returns:
None
"""
self.plugins = []
self.name_application = []
self.seen_paths = []
self.path_folder = []
self.walk_package(self.plugin_package)
[docs]
def application(self, argument, index):
"""
Apply all of the plugin on the argument supplied to this function.
Args:
argument (): this is the widget send from main apps(QMainWindow)
index (): The index number from the list plugins available
Returns:
None
"""
if index != -1:
plugin = self.plugins[index]
plugin.perform_operation(argument)
else:
print("No Application available!!")
[docs]
def walk_package(self, package):
"""
Recursively walk the supplied package to retrieve all plugins.
Args:
package (): The name folder e define. i.e "plugins"
Returns:
Create list plugins that find from plugin directory.
"""
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 it self
if issubclass(c, Plugin) & (c is not Plugin):
# print(f'Found Plugin class: {c.__module__}')
self.path_folder.append(c.__module__)
self.name_application.append(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_curent_paths = []
if isinstance(imported_package.__path__, str):
all_curent_paths.append(imported_package.__path__)
else:
all_curent_paths.extend([x for x in imported_package.__path__])
for pkg_path in all_curent_paths:
if pkg_path not in self.seen_paths:
self.seen_paths.append(pkg_path)
# get sub directory of curent 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)