Modulunterklassen (Module Subclasses)
Theorie
Information
- Um Modulunterklassen zu verstehen, sollte man einen Überblick darüber besitzen, wie die Python-Anbindung in PLANTA funktioniert:
Wie wird aus dem nativen C-Code eine Python-Klasse?
- Die nativen Funktionen werden in einem speziellen Modul (
ppms.i
) angebunden.
- Mit dem Tool SWIG werden diese Funktionen kompiliert.
- Es ensteht eine
.dll
/ .so
ähnliche Datei namens _ppms.pyd
, die als Bibliothek die entsprechenden Funktionen bereitstellt.
- Es entsteht eine Python-Datei namens
ppms_.py
, die sämtliche Funktionen aus der _ppms.pyd
Bibliothek bereitstellt.
- Im Python-Verzeichnis befindet sich die Python-Datei
ppms.py
, die aus ppms_.py
importiert und den Code um weitere, in Python geschriebene, Funktionen erweitert.
- Benutzt man nun eine API-Funktion, die einem eine
Module
Instanz zurückliefert, wird diese Modul-Instanz nicht direkt zurück gegeben, stattdessen erhält man eine Modulunterklasse: Entweder die im 405er Datensatz angegebene Klasse, oder die Standard Base
Klasse.
Was macht die Modulunterklasse?
- Die Modulunterklasse dient dazu, ein Modul um neue Funktionen und Attribute zu erweitern.
- Wird versucht eine Funktion aufzurufen, die es in der Modulunterklasse nicht gibt, wird stattdessen in der "echten" Modul-Instanz danach gesucht.
- Durch diese Fassade können Module leicht um neue Funktionen erweitert werden.
Praxis
Information
- Jedes neue Modul hat standardmäßig die Modulunterklasse
ppms.module_subclasses.base_class.Base
.
- Alle Modulunterklassen sollten von dieser Klasse erben.
Hinweis
- So wie bei allen anderen ausgelagerten Python-Dateien muss der Client neugestartet werden, nachdem Änderungen vorgenommen wurden.
Modulunterklassen und Makros
PLANTA rät davon ab, Makros zu verwenden. Stattdessen sollen Modulunterklassen verwendet werden, die gegenüber Makros folgende Vorteile aufweisen:
- Editierbarkeit mit einer IDE (Pycharm, PyDev, Visual Studio, ...)
- Bessere Durchsuchbarkeit
- Einfache Austauschbarkeit (ermöglicht zentrale Anpassungen)
- Wiederverwendbarkeit von Funktionen
- Einfachere Anpassung von Funktionen in bestimmten Modulen
- Versionierung in einem Quellcodeverwaltungssystem möglich (Nachvollziehbarkeit von Anpassungen)
Informationen
- Hat ein Modul ein Makro sowie eine Modulunterklasse, verhält es sich wie folgt:
- Das Modulmakro wird nach dem Öffnen des Moduls ausgeführt. Code auf der obersten Ebene wird ausgeführt.
- Gibt es die gleiche Funktion (z.B.
on_load()
) in beiden, so wird nur die Funktion der Modulunterklasse aufgerufen.
- Gibt es eine Funktion nur auf einer Seite, so wird sie aufgerufen.
Methoden aufrufen
Vorgehensweise
- Um eine Methode der Modulunterklasse aufrufbar zu machen, beispielsweise über einen Button, geht man wie folgt vor:
- Man implementiert die Methode in der Modulunterklasse
- Die Methodensignatur muss wie folgt aussehen:
(self, applied_dfc, clicked_df)
- Man fügt ein neues Button-DI (004336) in einen Datenbereich ein mit:
Menüpunkte überschreiben
Vorgehensweise
- Um einen Menüpunkt zu überschreiben, geht man wie folgt vor:
- Man überschreibt die Methode
menu_override(self, menu_id)
in seiner Modulunterklasse.
- Man prüft mit einem
if
, ob der Menüpunkt, der überschrieben werden soll, ausgeführt wird.
- Man behandelt den Menüpunkt und benutzt einen der folgenden zwei Rückgabewerte:
-
self.MENU_OVERRIDE_SUCCESS
: Der Menüpunkt wurde erfolgreich behandelt.
-
self.MENU_OVERRIDE_FAILURE
: Der Menüpunkt wurde nicht erfolgreich behandelt.
- Zum Schluss sollte man noch die
super()
Funktion aufrufen, um den normalen Programmfluss für andere Menüpunkte zu gewährleisten.
Beispiel
from ppms import ppms
from ppms.module_subclasses.base_class import Base
from ppms.constants import MENU_FILTER, MENU_RESET, MENU_SAVE
class ModuleThatOverwritesSave(Base):
def menu_override(self, menu_id):
if menu_id == MENU_SAVE:
ppms.ui_message_box('No saving allowed!')
return self.MENU_OVERRIDE_SUCCESS
# Don't allow resetting as that brings up a save prompt
elif menu_id == MENU_RESET:
return self.MENU_OVERRIDE_SUCCESS
return super(ModuleThatOverwritesSave, self).menu_override(menu_id)