Steck rein
Plugins sind in der Regel Module oder Packages die in einem (oder mehreren) Unterverzeichnissen hinterlegt sind.
Das Hauptscript muss diese laden und bestimmte Funktionen in diesen aufrufen, damit diese dann Daten verarbeiten können.
Eventuell möchte man das die Plugins selbst bestimmte Funktionen registrieren für bestimmte Ereignisse im Hauptprogramm (Hooks).
Eine einfache Variante wie man all das realisieren kann könnte so aussehen:
1
2
3
4
5
6
7
8
9
10
import importlib
import glob
import lib.register
for module in glob.glob("lib/plugins/*.py"):
module = module.replace("/", ".")[:-3]
importlib.import_module(module)
for module in lib.register._processors:
print(f"Would call {module}")
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
"""
Central module where all plugins could register theire callback functions
"""
_processors = set()
def register_processor(processor_function: callable):
"""
Method to register a processor function
Processor function take a tuple of line number and line content (string) and check
if the line is relevant for them.
If so they could take actions.
"""
_processors.add(processor_function)
1
2
3
4
5
6
7
8
9
10
11
12
13
import lib.register as register
from typing import Tuple
def process_line(line_tuple: Tuple[int, str]):
"""
Processes a line
"""
print(line_tuple)
register.register_processor(process_line)
Der Ablauf sieht in etwa so aus:
Gehen wir das einzeln durch.
In der Grafik die ersten 3 Blöcke im grünen Bereich:
1
2
3
4
5
6
7
import importlib
import glob
import lib.register
for module in glob.glob("lib/plugins/*.py"):
module = module.replace("/", ".")[:-3]
importlib.import_module(module)
-
Zeile 5: erstellt eine Liste aller Dateien die auf *.py enden in lib/plugins → entspricht in etwa ls -ls lib/plugins auf der Shell
-
Ergebnis ist eine Liste ala ["lib/plugins/firstplugin.py", "lib/plugins/firstplugin.py"]
-
-
Zeile 6: ersetzt "/" (Trenner im Dateisystempfad) durch "." (Trenner in Modulnamen) und schneidet ".py" weg ("[:-3]")
-
Zeile 7: importiert das Modul anschließend
-
das hat nur den Sinn das der Code des Moduls durch den Import automatisch ausgeführt wird (siehe nächster Abschnitt)
-
In der Grafik der blaue Bereich ist im Modul des jeweiligen Plugins:
Das ist also in den Modulen die wir im letzten Abschnitt importiert haben.
1
2
3
4
5
6
7
8
9
10
11
12
13
import lib.register as register
from typing import Tuple
def process_line(line_tuple: Tuple[int, str]):
"""
Processes a line
"""
print(line_tuple)
register.register_processor(process_line)
Beim Import des Moduls wird der Code des Moduls ausgeführt (also alles was außerhalb von Klassen und Funktionen steht). Das passiert bei jedem import in Python automatisch.
Hier Zeile 13, welche die Funktion "register_processor" mit der Funktion "process_line" als Parameter aufruft.
"process_line" ist weiter oben im gleichen Modul des Plugins definiert. Die Funktion "process_line" wird hier nicht aufgerufen (fehlende "()"), sondern ein Verweis auf sie übergeben.
Weiter geht es im orangenen Bereich der Grafik, dort ist "register_processor" definiert, was im vorherigen Abschnitt aufgerufen wurde:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
"""
Central module where all plugins could register theire callback functions
"""
_processors = set()
def register_processor(processor_function: callable):
"""
Method to register a processor function
Processor function take a tuple of line number and line content (string) and check
if the line is relevant for them.
If so they could take actions.
"""
_processors.add(processor_function)
-
register_processor wurde vom Plugin-Modul aufgerufen
-
Zeile 15: speichert die Referenz auf die übergene Funktion in einem set
-
Die 2 letzten Boxen im grünen Bereich werden ausgeführt wenn ein Event auftritt oder Daten vorliegen die durch Plugins verarbeitet werden sollen:
1
2
3
4
5
6
7
8
9
10
import importlib
import glob
import lib.register
for module in glob.glob("lib/plugins/*.py"):
module = module.replace("/", ".")[:-3]
importlib.import_module(module)
for module in lib.register._processors:
print(f"Would call {module}")
-
Zeile 3: bindet "lib.register" - den blauen Teil der Grafik ein
-
Zeile 9: greift auf die Liste der registrierten Funktionen in in lib.register._processors zu und durchläuft sie
-
Zeile 10: würde dann (hier nur angedeutet) die Funktionen in den Plugins aufrufen und entsprechend zu verarbeitende Daten als Parameter übergeben
Code
Der hier genutzte Code kann hier https://codeberg.org/shellkraut/plugin_implementation_example gefunden werden.
Bzw. per:
git clone https://codeberg.org/shellkraut/plugin_implementation_example.git
gecloned werden.
Folgender Aufruf führt das Script aus:
python main.py