Ich habe eine in Python geschriebene Anwendung, die von einem ziemlich technischen Publikum (Wissenschaftlern) verwendet wird.
Ich suche nach einer guten Möglichkeit, die Anwendung für die Benutzer erweiterbar zu machen, dh nach einer Skript- / Plugin-Architektur.
Ich suche etwas extrem Leichtes . Die meisten Skripte oder Plugins werden nicht von einem Drittanbieter entwickelt und verteilt und installiert, sondern von einem Benutzer in wenigen Minuten erstellt, um eine sich wiederholende Aufgabe zu automatisieren und Unterstützung für ein Dateiformat hinzuzufügen. usw. Plugins sollten also den absoluten Mindest-Boilerplate-Code haben und keine andere 'Installation' erfordern als das Kopieren in einen Ordner (so etwas wie setuptools-Einstiegspunkte oder die Zope-Plugin-Architektur scheinen zu viel zu sein.)
Gibt es bereits solche Systeme oder Projekte, die ein ähnliches Schema implementieren, bei dem ich nach Ideen / Inspirationen suchen sollte?
imp
Modul wird zugunstenimportlib
von Python 3.4imp.load_module
.module_example.py
::loader.py
::Es ist sicherlich "minimal", es hat absolut keine Fehlerprüfung, wahrscheinlich unzählige Sicherheitsprobleme, es ist nicht sehr flexibel - aber es sollte Ihnen zeigen, wie einfach ein Plugin-System in Python sein kann.
Sie wollen wahrscheinlich in die aussehen imp Modul auch, obwohl Sie nur mit viel tun können
__import__
,os.listdir
und einige String - Manipulation.quelle
def call_plugin(name, *args)
zudef call_plugin(name, *args, **kwargs)
, und dannplugin.plugin_main(*args)
zuplugin.plugin_main(*args, **kwargs)
imp
wird zugunsten vonimportlib
Werfen Sie einen Blick auf diese Übersicht über vorhandene Plugin-Frameworks / Bibliotheken , sie ist ein guter Ausgangspunkt. Ich mag Yapsy sehr , aber es hängt von Ihrem Anwendungsfall ab.
quelle
Obwohl diese Frage wirklich interessant ist, denke ich, dass sie ohne weitere Details ziemlich schwer zu beantworten ist. Was für eine Anwendung ist das? Hat es eine GUI? Ist es ein Kommandozeilen-Tool? Eine Reihe von Skripten? Ein Programm mit einem eindeutigen Einstiegspunkt usw.
Angesichts der wenigen Informationen, die ich habe, werde ich sehr allgemein antworten.
Was bedeutet, dass Sie Plugins hinzufügen müssen?
Bei einer reinen Code- / Entwurfspraxis müssen Sie klar bestimmen, welches Verhalten / welche spezifischen Aktionen Ihre Benutzer erweitern sollen. Identifizieren Sie den gemeinsamen Einstiegspunkt / eine Reihe von Funktionen, die immer überschrieben werden, und bestimmen Sie Gruppen innerhalb dieser Aktionen. Sobald dies erledigt ist, sollte es einfach sein, Ihre Anwendung zu erweitern.
Beispiel mit Hooks , inspiriert von MediaWiki (PHP, aber spielt Sprache wirklich eine Rolle?):
Ein weiteres Beispiel, inspiriert von Quecksilber. Hier fügen Erweiterungen der ausführbaren Datei der hg- Befehlszeile nur Befehle hinzu, wodurch das Verhalten erweitert wird.
Für beide Ansätze könnten Sie gemeinsam müssen initialize und Finalisierung für Ihre Erweiterung. Sie können entweder eine gemeinsame Schnittstelle verwenden, die alle Ihre Erweiterungen implementieren müssen (passt besser zum zweiten Ansatz; mercurial verwendet ein Reposetup (ui, repo), das für alle Erweiterungen aufgerufen wird), oder einen Hook-Ansatz mit a verwenden hooks.setup hook.
Aber wenn Sie nützlichere Antworten wünschen, müssen Sie Ihre Frage eingrenzen;)
quelle
Das einfache Plugin-Framework von Marty Allchin ist die Basis, die ich für meine eigenen Bedürfnisse verwende. Ich empfehle wirklich, einen Blick darauf zu werfen. Ich denke, es ist wirklich ein guter Anfang, wenn Sie etwas einfaches und leicht hackbares wollen. Sie können es auch als Django-Snippets finden .
quelle
Ich bin ein pensionierter Biologe, der sich mit digitalen Mikrofotografien befasste und ein Bildverarbeitungs- und Analysepaket (technisch gesehen keine Bibliothek) schreiben musste, um auf einem SGi-Computer ausgeführt zu werden. Ich habe den Code in C geschrieben und Tcl für die Skriptsprache verwendet. Die GUI, so wie sie war, wurde mit Tk erstellt. Die in Tcl angezeigten Befehle hatten die Form "extensionName commandName arg0 arg1 ... param0 param1 ...", dh einfache durch Leerzeichen getrennte Wörter und Zahlen. Als Tcl den Teilstring "extensionName" sah, wurde die Steuerung an das C-Paket übergeben. Dadurch wurde der Befehl über einen Lexer / Parser (in lex / yacc ausgeführt) ausgeführt und anschließend nach Bedarf C-Routinen aufgerufen.
Die Befehle zum Bedienen des Pakets konnten einzeln über ein Fenster in der GUI ausgeführt werden. Stapeljobs wurden jedoch durch Bearbeiten von Textdateien ausgeführt, die gültige Tcl-Skripte waren. Sie würden die Vorlage auswählen, die die gewünschte Operation auf Dateiebene ausgeführt hat, und dann eine Kopie bearbeiten, die das tatsächliche Verzeichnis und die Dateinamen sowie die Paketbefehle enthält. Es funktionierte wie ein Zauber. Bis um ...
1) Die Welt wandte sich PCs zu und 2) die Skripte wurden länger als etwa 500 Zeilen, als die zweifelhaften organisatorischen Fähigkeiten von Tcl zu einer echten Unannehmlichkeit wurden. Zeit verging ...
Ich habe mich zurückgezogen, Python wurde erfunden und es sah aus wie der perfekte Nachfolger von Tcl. Jetzt habe ich den Port nie ausgeführt, weil ich mich nie den Herausforderungen gestellt habe, (ziemlich große) C-Programme auf einem PC zu kompilieren, Python mit einem C-Paket zu erweitern und GUIs in Python / Gt? / Tk? /? ?. Die alte Idee, bearbeitbare Vorlagenskripte zu haben, scheint jedoch immer noch praktikabel zu sein. Es sollte auch keine allzu große Belastung sein, Paketbefehle in einer nativen Python-Form einzugeben, z.
packageName.command (arg0, arg1, ..., param0, param1, ...)
Ein paar zusätzliche Punkte, Parens und Kommas, aber das sind keine Showstopper.
Ich erinnere mich, dass jemand Versionen von Lex und Yacc in Python erstellt hat (versuchen Sie: http://www.dabeaz.com/ply/ ). Wenn diese also noch benötigt werden, sind sie da.
Der Punkt dieses Streifens ist, dass es mir so vorgekommen ist, als ob Python selbst das gewünschte "leichte" Frontend ist, das von Wissenschaftlern verwendet werden kann. Ich bin neugierig zu wissen, warum du denkst, dass es nicht so ist, und das meine ich ernst.
später hinzugefügt: Die Anwendung gedit geht davon aus, dass Plugins hinzugefügt werden, und auf ihrer Website finden Sie die klarste Erklärung für ein einfaches Plugin-Verfahren, das ich in wenigen Minuten gefunden habe. Versuchen:
https://wiki.gnome.org/Apps/Gedit/PythonPluginHowToOld
Ich würde Ihre Frage immer noch gerne besser verstehen. Ich bin mir nicht sicher, ob Sie 1) möchten, dass Wissenschaftler Ihre (Python-) Anwendung ganz einfach auf verschiedene Arten verwenden können, oder 2) möchten, dass die Wissenschaftler Ihrer Anwendung neue Funktionen hinzufügen. Wahl Nr. 1 ist die Situation, mit der wir mit den Bildern konfrontiert waren, und die dazu führte, dass wir generische Skripte verwendeten, die wir an die Bedürfnisse des Augenblicks anpassten. Ist es Wahl 2, die Sie zur Idee von Plugins führt, oder ist es ein Aspekt Ihrer Anwendung, der die Ausgabe von Befehlen an Plugins unmöglich macht?
quelle
Als ich nach Python Decorators suchte, fand ich ein einfaches, aber nützliches Code-Snippet. Es passt vielleicht nicht zu Ihren Bedürfnissen, ist aber sehr inspirierend.
Scipy Advanced Python # Plugin Registrierungssystem
Verwendung:
quelle
WordProcessor.plugin
nichts zurückgegeben (None
), sodass beimCleanMdashesExtension
späteren Importieren der Klasse nur importiert wirdNone
. Wenn die Plugin-Klassen für sich genommen nützlich sind, erstellen Sie die.plugin
Klassenmethodereturn plugin
.Ich habe die nette Diskussion über verschiedene Plugin-Architekturen von Dr. Andre Roberge auf der Pycon 2009 genossen. Er gibt einen guten Überblick über verschiedene Arten der Implementierung von Plugins, beginnend mit etwas wirklich Einfachem.
Es ist als Podcast erhältlich (zweiter Teil nach einer Erklärung zum Affen-Patching), begleitet von einer Reihe von sechs Blogeinträgen .
Ich empfehle, es kurz anzuhören, bevor Sie eine Entscheidung treffen.
quelle
Ich kam hier auf der Suche nach einer minimalen Plugin-Architektur an und fand viele Dinge, die mir alle übertrieben erschienen. Also habe ich Super Simple Python Plugins implementiert . Um es zu verwenden, erstellen Sie ein oder mehrere Verzeichnisse und legen
__init__.py
in jedem eine spezielle Datei ab. Durch das Importieren dieser Verzeichnisse werden alle anderen Python-Dateien als Submodule geladen und ihre Namen in die__all__
Liste aufgenommen. Dann liegt es an Ihnen, diese Module zu validieren / zu initialisieren / zu registrieren. Es gibt ein Beispiel in der README-Datei.quelle
Tatsächlich arbeitet setuptools mit einem "Plugins-Verzeichnis", wie das folgende Beispiel aus der Projektdokumentation zeigt: http://peak.telecommunity.com/DevCenter/PkgResources#locating-plugins
Anwendungsbeispiel:
Auf lange Sicht ist setuptools eine viel sicherere Wahl, da Plugins ohne Konflikte oder fehlende Anforderungen geladen werden können.
Ein weiterer Vorteil ist, dass die Plugins selbst mit demselben Mechanismus erweitert werden können, ohne dass sich die ursprünglichen Anwendungen darum kümmern müssen.
quelle
Als ein weiterer Ansatz für das Plugin-System können Sie das Extend Me-Projekt überprüfen .
Definieren wir zum Beispiel eine einfache Klasse und ihre Erweiterung
Und versuchen Sie es zu benutzen:
Und zeigen Sie, was sich hinter den Kulissen verbirgt:
Die Bibliothek " expand_me" manipuliert den Klassenerstellungsprozess über Metaklassen. Im obigen Beispiel erhalten
MyCoolClass
wir beim Erstellen einer neuen Instanz eine neue Klasse, die eine Unterklasse von beiden istMyCoolClassExtension
undMyCoolClass
dank der mehrfachen Vererbung von Python die Funktionalität beiderZur besseren Kontrolle über die Klassenerstellung sind in dieser Bibliothek nur wenige Metaklassen definiert:
ExtensibleType
- ermöglicht eine einfache Erweiterbarkeit durch UnterklassenExtensibleByHashType
- Ähnlich wie ExtensibleType, jedoch mit der Fähigkeit, spezielle Klassenversionen zu erstellen, wodurch die globale Erweiterung der Basisklasse und die Erweiterung spezialisierter Klassenversionen ermöglicht werdenDiese Bibliothek wird in verwendet Bibliothek OpenERP Proxy Project verwendet und scheint gut genug zu funktionieren!
Ein echtes Anwendungsbeispiel finden Sie in der OpenERP-Proxy-Erweiterung 'field_datetime' :
Record
hier ist extesible Objekt.RecordDateTime
ist Erweiterung.Um die Erweiterung zu aktivieren, importieren Sie einfach das Modul, das die Erweiterungsklasse enthält, und (im obigen Fall) alle
Record
Objekte, die danach erstellt wurden, haben die Erweiterungsklasse in Basisklassen und verfügen somit über alle Funktionen.Der Hauptvorteil dieser Bibliothek besteht darin, dass Code, der erweiterbare Objekte betreibt, nicht über Erweiterungen Bescheid wissen muss und Erweiterungen alles in erweiterbaren Objekten ändern können.
quelle
my_cool_obj = MyCoolClassExtension1()
anstelle vonmy_cool_obj = MyCoolClass()
__new__
Methode überschrieben , sodass sie automatisch alle Unterklassen findet und eine neue Klasse erstellt, dh eine Unterklasse von allen, und eine neue Instanz dieser erstellten Klasse zurückgibt. Daher muss die ursprüngliche Anwendung nicht über alle Erweiterungen Bescheid wissen. Dieser Ansatz ist beim Erstellen einer Bibliothek hilfreich, damit der Endbenutzer das Verhalten leicht ändern oder erweitern kann. Im obigen Beispiel kann MyCoolClass in der Bibliothek definiert und von dieser verwendet werden, und MyCoolClassExtension kann vom Endbenutzer definiert werden.setuptools hat einen EntryPoint :
AFAIK Dieses Paket ist immer verfügbar, wenn Sie pip oder virtualenv verwenden.
quelle
Um die Antwort von @ edomaur zu erweitern, kann ich vorschlagen, einen Blick auf simple_plugins (schamloser Plug) zu werfen , ein einfaches Plugin-Framework, das von der Arbeit von Marty Alchin inspiriert wurde .
Ein kurzes Anwendungsbeispiel basierend auf der README-Datei des Projekts:
quelle
Ich habe Zeit damit verbracht, diesen Thread zu lesen, während ich ab und zu nach einem Plugin-Framework in Python gesucht habe. Ich habe einige verwendet, aber es gab Mängel bei ihnen. Folgendes habe ich mir für Ihre Prüfung im Jahr 2017 ausgedacht, ein schnittstellenfreies, lose gekoppeltes Plugin-Management-System: Laden Sie mich später . Hier finden Sie Tutorials zur Verwendung.
quelle
Sie können pluginlib verwenden .
Plugins sind einfach zu erstellen und können von anderen Paketen, Dateipfaden oder Einstiegspunkten geladen werden.
Erstellen Sie eine übergeordnete Plugin-Klasse und definieren Sie alle erforderlichen Methoden:
Erstellen Sie ein Plugin, indem Sie eine übergeordnete Klasse erben:
Laden Sie die Plugins:
quelle
foo
haben Sie möglicherweise ein Modul namens,foo.parents
in dem Sie die übergeordneten Klassen definieren. Dann würden deine Plugins importierenfoo.parents
. Das funktioniert in den meisten Anwendungsfällen gut. Da 'foo' selbst auch importiert wird, um die Möglichkeit von zirkulären Importen zu vermeiden, lassen viele Projekte das Stammverzeichnis des Moduls leer und verwenden eine__main__.py
Datei oder Einstiegspunkte, um die Anwendung zu starten.Ich habe viel Zeit damit verbracht, ein kleines Plugin-System für Python zu finden, das meinen Anforderungen entspricht. Aber dann dachte ich nur, wenn es bereits eine Vererbung gibt, die natürlich und flexibel ist, warum nicht?
Das einzige Problem bei der Verwendung der Vererbung für Plugins besteht darin, dass Sie nicht wissen, welche Plugin-Klassen am spezifischsten sind (die niedrigsten im Vererbungsbaum).
Dies könnte jedoch mit einer Metaklasse gelöst werden, die die Vererbung der Basisklasse verfolgt, und möglicherweise eine Klasse erstellen, die von den meisten spezifischen Plugins erbt ('Root erweitert' in der folgenden Abbildung).
Also kam ich mit einer Lösung, indem ich eine solche Metaklasse codierte:
Wenn Sie also eine Root-Basis haben, die mit einer Metaklasse erstellt wurde, und einen Baum von Plugins haben, die davon erben, können Sie automatisch eine Klasse erhalten, die von den spezifischsten Plugins erbt, indem Sie einfach Unterklassen erstellen:
Die Codebasis ist ziemlich klein (~ 30 Zeilen reiner Code) und so flexibel, wie es die Vererbung zulässt.
Wenn Sie interessiert sind, melden Sie sich unter https://github.com/thodnev/pluginlib
quelle
Sie können sich auch Groundwork ansehen .
Die Idee ist, Anwendungen um wiederverwendbare Komponenten zu erstellen, die als Muster und Plugins bezeichnet werden. Plugins sind Klassen, die von abgeleitet sind
GwBasePattern
. Hier ist ein einfaches Beispiel:Es gibt auch erweiterte Muster, um z. B. Befehlszeilenschnittstellen, Signalisierung oder gemeinsam genutzte Objekte zu handhaben.
Groundwork findet seine Plugins entweder durch programmgesteuertes Binden an eine App wie oben gezeigt oder automatisch über
setuptools
. Python-Pakete, die Plugins enthalten, müssen diese über einen speziellen Einstiegspunkt deklarierengroundwork.plugin
.Hier sind die Dokumente .
Haftungsausschluss : Ich bin einer der Autoren von Groundwork.
quelle
In unserem aktuellen Gesundheitsprodukt haben wir eine Plugin-Architektur mit Schnittstellenklasse implementiert. Unser Tech-Stack ist Django über Python für API und Nuxtjs über Nodejs für Frontend.
Wir haben eine Plugin-Manager-App für unser Produkt geschrieben, die im Grunde genommen ein Pip- und ein npm-Paket ist, das Django und Nuxtjs entspricht.
Für die Entwicklung neuer Plugins (pip und npm) haben wir den Plugin-Manager als Abhängigkeit festgelegt.
Im Pip-Paket: Mit Hilfe von setup.py können Sie den Einstiegspunkt des Plugins hinzufügen, um etwas mit dem Plugin-Manager (Registrierung, Initiierungen usw.) zu tun. Https://setuptools.readthedocs.io/en/latest/setuptools .html # automatische Skript-Erstellung
Im npm-Paket: Ähnlich wie bei pip gibt es Hooks in npm-Skripten, um die Installation durchzuführen. https://docs.npmjs.com/misc/scripts
Unser Anwendungsfall:
Das Plugin-Entwicklungsteam ist jetzt vom Kernteam für die Entwicklung getrennt. Der Umfang der Plugin-Entwicklung besteht in der Integration in Apps von Drittanbietern, die in einer der Produktkategorien definiert sind. Die Plugin-Schnittstellen sind kategorisiert nach: - Fax, Telefon, E-Mail ... usw. Der Plugin-Manager kann auf neue Kategorien erweitert werden.
In Ihrem Fall: Vielleicht können Sie ein Plugin schreiben lassen und dasselbe für Dinge wiederverwenden.
Wenn Plugin-Entwickler Kernobjekte wiederverwenden müssen, kann dieses Objekt durch eine Abstraktionsebene im Plugin-Manager verwendet werden, damit alle Plugins diese Methoden erben können.
Wenn Sie nur mitteilen, wie wir unser Produkt implementiert haben, erhalten Sie eine kleine Vorstellung davon.
quelle