197 votes

Construire une architecture de plugin minime en Python

J'ai une demande, écrite en Python, qui est utilisé par un assez technique public (les scientifiques).

Je suis à la recherche d'un bon moyen pour rendre l'application extensible par les utilisateurs, c'est à dire un script/plugin architecture.

Je suis à la recherche de quelque chose de très léger. La plupart des scripts ou des plugins, ne sont pas va être développé et distribué par un tiers et installé, mais sont quelque chose de fouettée par un utilisateur dans quelques minutes pour automatiser la répétition d'une tâche, d'ajouter le support du format de fichier, etc. Donc, les plugins doivent avoir le minimum absolu du code réutilisable, et ne nécessitent pas de "installation" autres que la copie d'un dossier (donc quelque chose comme setuptools points d'entrée, ou les Zope architecture de plugin semble de trop.)

Existe-il des systèmes comme celui-ci, ou les projets qui mettent en œuvre un système similaire que je devrais regarder pour des idées et d'inspiration?

154voto

TJG Points 801

Le mien est, fondamentalement, un répertoire "plugins" dont l'application principale peut interroger et ensuite utiliser imp.load_module pour ramasser des fichiers, recherchez un bien connu de point d'entrée, éventuellement avec le module de niveau config, et à partir de là. J'ai utiliser le fichier de surveillance de choses pour une certaine quantité de dynamisme dans lequel les plugins sont actifs, mais c'est une bonne chose à avoir.

Bien sûr, toute exigence qui vient de dire "je n'ai pas besoin de grand, quelque chose de compliqué] X; je veux juste quelque chose de léger," court le risque de re-mise en œuvre de X on a découvert exigence à la fois. Mais cela ne veut pas dire que vous ne pouvez pas avoir du plaisir à le faire de toute façon :)

59voto

dbr Points 66401

module_example.py:

def plugin_main(*args, **kwargs):
    print args, kwargs

loader.py:

def load_plugin(name):
    mod = __import__("module_%s" % name)
    return mod

def call_plugin(name, *args, **kwargs):
    plugin = load_plugin(name)
    plugin.plugin_main(*args, **kwargs)

call_plugin("example", 1234)

C'est certainement le "minimal", il n'a absolument aucun contrôle d'erreur, probablement d'innombrables problèmes de sécurité, il n'est pas très souple, mais il devrait comment simple un système de plugin en Python peut être..

Vous voudrez probablement regarder dans le pgi module, bien que vous pouvez faire beaucoup avec juste __import__, os.listdir , et certains de manipulation de chaîne.

31voto

PhilS Points 901

Jetez un oeil sur à cette vue d’ensemble sur les cadres existants de plugin / bibliothèques, c’est un bon point de départ. J’aime bien yapsy, mais cela dépend de votre cas d’utilisation.

25voto

NicDumZ Points 5566

Même si la question est vraiment intéressant, je pense que c'est assez dur de répondre, sans plus de détails. Ce genre de demande est-ce? Il possède une interface graphique? Est-il un outil en ligne de commande? Un ensemble de scripts? Un programme avec un point d'entrée unique, etc...

Étant donné le peu d'information que j'ai, je vais répondre dans un très générique.

De quels moyens disposez-vous pour ajouter des plugins?

  • Vous devrez probablement ajouter un fichier de configuration qui contiendra la liste des chemins des répertoires/charger.
  • Une autre façon serait de dire "tous les fichiers du plugin/ répertoire sera chargé", mais il a l'inconvénient d'exiger à vos utilisateurs de déplacer des fichiers.
  • Une dernière solution intermédiaire consisterait à exiger que tous les plugins dans le même plugin/ dossier, puis active/désactiver l'aide de chemins relatifs dans un fichier de config.

Sur un code pur/pratique de la conception, vous aurez à déterminer clairement ce que le comportement/les actions spécifiques que vous souhaitez que vos utilisateurs de s'étendre. Identifier le point d'entrée commun/un ensemble de fonctionnalités qui va toujours être remplacées, et de déterminer des groupes à l'intérieur de ces actions. Une fois que ceci est fait, il devrait être facile à étendre votre application,

Exemple à l'aide de crochets, inspiré de MediaWiki (PHP, mais n'langue qui compte vraiment?):

import hooks

# In your core code, on key points, you allow user to run actions:
def compute(...):
    try:
        hooks.runHook(hooks.registered.beforeCompute)
    except hooks.hookException:
        print('Error while executing plugin')

    # [compute main code] ...

    try:
        hooks.runHook(hooks.registered.afterCompute)
    except hooks.hookException:
        print('Error while executing plugin')

# The idea is to insert possibilities for users to extend the behavior 
# where it matters.
# If you need to, pass context parameters to runHook. Remember that
# runHook can be defined as a runHook(*args, **kwargs) function, not
# requiring you to define a common interface for *all* hooks. Quite flexible :)

# --------------------

# And in the plugin code:
# [...] plugin magic
def doStuff():
    # ....
# and register the functionalities in hooks

# doStuff will be called at the end of each core.compute() call
hooks.registered.afterCompute.append(doStuff)

Un autre exemple, inspiré de mercurial. Ici, les extensions seulement ajouter des commandes à l' hg en ligne de commande exécutable, d'étendre le comportement.

def doStuff(ui, repo, *args, **kwargs):
    # when called, a extension function always receives:
    # * an ui object (user interface, prints, warnings, etc)
    # * a repository object (main object from which most operations are doable)
    # * command-line arguments that were not used by the core program

    doMoreMagicStuff()
    obj = maybeCreateSomeObjects()

# each extension defines a commands dictionary in the main extension file
commands = { 'newcommand': doStuff }

Pour les deux approches, vous pourriez avoir besoin commun d'initialiser et de finaliser pour votre extension. Vous pouvez soit utiliser une interface commune que tous vos extension aura à mettre en œuvre (il s'intègre mieux avec la deuxième approche; mercurial utilise un reposetup(ui, repo), qui est appelée pour toutes les extension), ou l'utilisation d'un crochet-type d'approche, avec crochets.le programme d'installation du crochet.

Mais encore une fois, si vous voulez plus de réponses utiles, vous devrez préciser votre question ;)

11voto

behindthefall Points 694

Je suis à la retraite biologiste qui a traité avec le numérique micrograqphs et s'est trouvé avoir à écrire un traitement de l'image et de l'analyse du package (pas techniquement d'une bibliothèque) pour s'exécuter sur une machine SGi. J'ai écrit le code en C et utilisé Tcl pour le langage de script. L'interface graphique, tel qu'il a été, a été fait à l'aide de Savoirs traditionnels. Les commandes qui sont apparus dans Tcl étaient de la forme "extensionName commandName arg0 arg1 ... param0 param1 ...", c'est simple, séparés par des espaces, des mots et des nombres. Lorsque Tcl a vu le "extensionName" sous-chaîne, le contrôle est passé à la C package. Qui à son tour l'exécution de la commande par l'intermédiaire d'un analyseur lexical/parser (qui se fait dans lex/yacc) et puis il a appelé des routines C que nécessaire.

Les commandes pour faire fonctionner le package peut être exécuté, un par un, par l'intermédiaire d'une fenêtre de l'interface graphique, mais des jobs batch ont été réalisées par l'édition de fichiers texte qui ont été valide scripts Tcl: il vous suffit de choisir le modèle qui a fait le genre de fichier d'opération au niveau de ce que tu veux faire et ensuite modifier une copie de contenir le répertoire réel, et les noms de fichier plus le paquet de commandes. Il a travaillé comme un charme. Jusqu'à ce que ...

1) Le monde se tourna vers Pc et 2) les scripts obtenu plus de 500 lignes, lors de la Tcl est douteux capacités organisationnelles commencé à devenir un véritable inconvénient. Le temps passait ...

Je suis à la retraite, Python ai inventé, et il semblait que le parfait successeur de Tcl. Maintenant, je n'ai jamais fait le port, parce que je n'ai jamais fait face aux défis de la compilation (assez grand) des programmes en C sur un PC, l'extension de Python avec un C paquet, et de faire des Interfaces graphiques en Python/Gt?/Les savoirs traditionnels?/??. Cependant, la vieille idée d'avoir modifiable modèle de scripts semble encore utilisable. Aussi, il ne devrait pas être un fardeau trop lourd pour entrer paquet de commandes dans un natif Python forme, par exemple:

packageName.de commande( arg0, arg1, ..., param0, param1, ...)

Un supplément de quelques points, les parenthèses et les virgules, mais ce ne sont pas les points de blocage.

Je me souviens que quelqu'un a fait des versions de lex et yacc en Python (à essayer: http://www.dabeaz.com/ply/), de sorte que si ceux-ci sont encore nécessaires, ils sont autour.

Le but de cette randonnée est qu'il m'a semblé que Python lui-même EST "léger" front-end utilisable par les scientifiques. Je suis curieux de savoir pourquoi vous pensez qu'il n'est pas, et je le dis sérieusement.


ajouté plus tard: L'application gedit prévoit des plugins ajoutés et leur site a propos de la plus claire explication d'un plugin simple procédure que j'ai trouvé en quelques minutes, regardant autour de lui. Essayez:

https://wiki.gnome.org/Apps/Gedit/PythonPluginHowToOld

Je voudrais encore à comprendre votre question mieux. Je ne sais pas si 1) vous voulez scientifiques pour être en mesure d'utiliser votre (Python) demande tout simplement de diverses façons ou 2) veut permettre aux scientifiques d'ajouter de nouvelles fonctionnalités à votre application. Choix #1 est la situation à laquelle nous sommes confrontés avec les images et qui nous a conduit à utiliser des scripts génériques qui nous modifiées afin de répondre à la nécessité du moment. C'est le Choix #2 qui vous mène à l'idée de plugins, ou est-il un aspect de votre application qui permet de lancer les commandes à elle impossible?

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X