add plugin registry

This commit is contained in:
2021-11-13 18:12:15 +01:00
parent d980cd99d5
commit c8e5374aa7
8 changed files with 215 additions and 0 deletions

0
raven/__init__.py Normal file
View File

3
raven/pluginbase.py Normal file
View File

@@ -0,0 +1,3 @@
class PluginBase():
def __init__(self):
pass

55
raven/pluginregistry.py Normal file
View File

@@ -0,0 +1,55 @@
from types import ModuleType
from typing import Dict
from inspect import isclass
from pkgutil import iter_modules
from pathlib import Path
from os.path import dirname
from importlib import import_module
from raven.pluginbase import PluginBase
class PluginRegistry():
plugins: Dict[str, PluginBase] = {}
modules: [ModuleType] = []
@staticmethod
def register_plugin(name: str, plugin: PluginBase):
PluginRegistry.plugins[name] = plugin
@staticmethod
def get_plugins_by_function(function_name: str) -> [PluginBase]:
result = []
for plugin in PluginRegistry.plugins.values():
fun = getattr(plugin, function_name, None)
if callable(fun):
result.append(plugin)
return result
@staticmethod
def load_module(module_name: str) -> ModuleType:
module_name = f"plugins.{module_name}"
# import the module and iterate through its attributes
module = import_module(module_name)
PluginRegistry.modules.append(module)
return module
@staticmethod
def load_plugin(plugin_name: str):
module_name = f"plugins.{plugin_name.lower()}"
module = import_module(module_name)
if plugin_name in dir(module):
plugin_class = getattr(module, plugin_name)
if isclass(plugin_class) and issubclass(plugin_class, PluginBase):
PluginRegistry.register_plugin(plugin_name, plugin_class)
print("%s -> %s :: %s in %s" % (plugin_name, plugin_class, module_name, module))
return plugin_class
@staticmethod
def get_modules() -> [ModuleType]:
return PluginRegistry.modules.copy()
@staticmethod
def get_plugins() -> [ModuleType]:
return PluginRegistry.modules.copy()

25
raven/plugins/__init__.py Normal file
View File

@@ -0,0 +1,25 @@
from inspect import isclass
from pkgutil import iter_modules
from pathlib import Path
from importlib import import_module
from raven.pluginbase import PluginBase
# iterate through the modules in the current package
from raven.pluginregistry import PluginRegistry
if False:
package_dir = Path(__file__).resolve().parent
for (_, module_name, _) in iter_modules([str(package_dir)]):
# import the module and iterate through its attributes
module = import_module(f"{__name__}.{module_name}")
print("module: %s" % module)
for attribute_name in dir(module):
if attribute_name == "PluginBase":
continue
attribute = getattr(module, attribute_name)
if isclass(attribute) and issubclass(attribute, PluginBase):
globals()[attribute_name] = attribute
PluginRegistry.register_plugin(attribute_name, attribute)
print("%s -> %s :: %s in %s" % (attribute_name, attribute, module_name, module))

View File

@@ -0,0 +1,11 @@
from raven.pluginbase import PluginBase
class FilterPlugin(PluginBase):
def __init__(self):
super(FilterPlugin, self).__init__()
print("init FilterPlugin")
def init():
print("initializing filter plugin")

View File

@@ -0,0 +1,7 @@
from raven.pluginbase import PluginBase
class LogFileViewerPlugin(PluginBase):
def __init__(self):
super(LogFileViewerPlugin, self).__init__()
print("init LogFileViewerPlugin")

80
raven/ravenlog.py Normal file
View File

@@ -0,0 +1,80 @@
import ctypes
import logging
import signal
import sys
from inspect import isclass
from importlib import import_module
from pathlib import Path
from pkgutil import iter_modules
from plugins import *
from PyQt6 import QtCore
from PyQt6.QtCore import QTimer
from PyQt6.QtGui import QIcon
from PyQt6.QtWidgets import QApplication
import constants
from raven.ravenwindow import RavenWindow
from ravenui import RavenUI
logging.basicConfig(level=logging.INFO)
log = logging.getLogger("main")
def stop_signal(signum, _stackframe):
""" Handle terminate signal """
try:
log.info("Terminate signal received. %s", signum)
QtCore.QCoreApplication.quit()
except Exception:
log.exception("Exception occurred while terminating")
sys.exit(1)
sys.exit(0)
def init_signal_handler():
# workaround to make signals work in QT apps.
# They do not work out of the box, because the main thread
# is running in C++ code once app.exec() is executed
# Forcing an empty lambda to be executed periodically gives
# control back to python and allows python to react to signals
timer = QTimer()
timer.timeout.connect(lambda: None)
timer.start(100)
signal.signal(signal.SIGINT, stop_signal)
signal.signal(signal.SIGTERM, stop_signal)
def init_translator(app: QApplication):
# translator = QTranslator()
# if translator.load(QLocale("de"), "messages_de.ts"):
# app.installTranslator(translator)
pass
def set_window_icon(app: QApplication):
app.setWindowIcon(QIcon("../" + constants.raven_icon))
# see https://stackoverflow.com/questions/1551605/how-to-set-applications-taskbar-icon-in-windows-7/1552105#1552105
if sys.platform == 'win32' or sys.platform == 'cygwin':
ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID('opentext.ravenlog')
if __name__ == "__main__":
filterplugin = PluginRegistry.load_plugin("FilterPlugin")
filterplugin()
logfileviewerplugin = PluginRegistry.load_plugin("LogFileViewerPlugin")
logfileviewerplugin()
app = QApplication(sys.argv)
set_window_icon(app)
init_translator(app)
init_signal_handler()
window = RavenWindow()
RavenUI.window = window
window.show()
app.exec()

34
raven/ravenwindow.py Normal file
View File

@@ -0,0 +1,34 @@
from PyQt6.QtWidgets import QMainWindow, QMenu, QStatusBar
from cutesettings import CuteSettings
from settingsstore import SettingsStore
class RavenWindow(QMainWindow):
def __init__(self, *args, **kwargs):
super(RavenWindow, self).__init__(*args, **kwargs)
self.settings = SettingsStore.load()
self.setWindowTitle(self.tr("RavenLog"))
self._restore_window()
self.setDockNestingEnabled(True)
self.setAcceptDrops(True)
# self.tabs = Tabs(self.settings)
# self._menu_recent_files = QMenu(self.tr("Open &Recent"), self)
# self.setCentralWidget(self.tabs)
# self.status_bar = QStatusBar(self)
# self.setStatusBar(self.status_bar)
# self.setMenuBar(self.create_menu_bar())
def _restore_window(self):
qsettings = CuteSettings()
geometry_restored = False
geometry = qsettings.value("mainWindow/geometry")
if geometry:
geometry_restored = self.restoreGeometry(geometry)
if not geometry_restored:
self.setGeometry(0, 0, 800, 600)