Question

Il existe plusieurs utilitaires - toutes avec des procédures différentes, les limites et les systèmes d'exploitation cible - pour obtenir un package Python et toutes ses dépendances et les transformer en un seul programme binaire qui est facile pour expédier aux clients:

Ma situation va encore plus loin: les développeurs tiers seront désireux de plug-ins d'écriture, extensions ou add-ons pour mon application. Il est, bien sûr, une question ardue comment les utilisateurs sur des plateformes telles que Windows serait plus facile d'installer des plugins ou addons dans une telle manière que mon application peut facilement découvrir qu'ils ont été installés. Mais au-delà de cette question de base est une autre: comment un développeur tiers bundle leur extension avec ce que les bibliothèques de l'extension elle-même a besoin (ce qui pourrait être des modules binaires, comme lxml) de telle sorte que les dépendances du plugin sont disponibles pour l'importation à la temps que le plug-in est disponible.

Comment cela peut-il être abordé? Est-ce que ma demande besoin de son propre plug-in zone sur le disque et son propre plug-in Registre pour faire ce traitable? Ou y at-il des mécanismes généraux, que je pouvais éviter de me écrire, qui permettrait une application qui est distribué comme un seul exécutable à regarder autour et trouver des plugins qui sont également installés sous forme de fichiers individuels?

Était-ce utile?

La solution

Vous devriez être en mesure d'avoir un répertoire plugins que votre application analyse lors de l'exécution (ou version ultérieure) pour importer le code en question. Voici un exemple qui devrait fonctionner avec .py ou un code .pyc régulier que même fonctionne avec des plugins stockés dans des fichiers zip (afin que les utilisateurs pourraient simplement déposer someplugin.zip dans le répertoire « plugins » et ont magiquement travail):

import re, os, sys
class Plugin(object):
    """
    The base class from which all plugins are derived.  It is used by the
    plugin loading functions to find all the installed plugins.
    """
    def __init__(self, foo):
        self.foo = foo
    # Any useful base plugin methods would go in here.

def get_plugins(plugin_dir):
    """Adds plugins to sys.path and returns them as a list"""

    registered_plugins = []

    #check to see if a plugins directory exists and add any found plugins
    # (even if they're zipped)
    if os.path.exists(plugin_dir):
        plugins = os.listdir(plugin_dir)
        pattern = ".py$"
        for plugin in plugins:
            plugin_path = os.path.join(plugin_dir, plugin)
            if os.path.splitext(plugin)[1] == ".zip":
                sys.path.append(plugin_path)
                (plugin, ext) = os.path.splitext(plugin) # Get rid of the .zip extension
                registered_plugins.append(plugin)
            elif plugin != "__init__.py":
                if re.search(pattern, plugin):
                    (shortname, ext) = os.path.splitext(plugin)
                    registered_plugins.append(shortname)
            if os.path.isdir(plugin_path):
                plugins = os.listdir(plugin_path)
                for plugin in plugins:
                    if plugin != "__init__.py":
                        if re.search(pattern, plugin):
                            (shortname, ext) = os.path.splitext(plugin)
                            sys.path.append(plugin_path)
                            registered_plugins.append(shortname)
    return registered_plugins

def init_plugin_system(cfg):
    """
    Initializes the plugin system by appending all plugins into sys.path and
    then using load_plugins() to import them.

        cfg - A dictionary with two keys:
        plugin_path - path to the plugin directory (e.g. 'plugins')
        plugins - List of plugin names to import (e.g. ['foo', 'bar'])
    """
    if not cfg['plugin_path'] in sys.path:
        sys.path.insert(0, cfg['plugin_path'])
    load_plugins(cfg['plugins'])

def load_plugins(plugins):
    """
    Imports all plugins given a list.
    Note:  Assumes they're all in sys.path.
    """
    for plugin in plugins:
        __import__(plugin, None, None, [''])
        if plugin not in Plugin.__subclasses__():
            # This takes care of importing zipped plugins:
            __import__(plugin, None, None, [plugin])

Alors laisse dire que j'ai un plugin nommé « foo.py » dans un répertoire appelé « plugins » (qui se trouve dans la base dir de mon application) qui ajoutera une nouvelle fonctionnalité à ma demande. Le contenu peut ressembler à ceci:

from plugin_stuff import Plugin

class Foo(Plugin):
    """An example plugin."""
    self.menu_entry = {'Tools': {'Foo': self.bar}}
    def bar(self):
        return "foo plugin!"

Je pourrais initialiser mes plugins quand je lance mon application comme ceci:

plugin_dir = "%s/plugins" % os.getcwd()
plugin_list = get_plugins(plugin_dir)
init_plugin_system({'plugin_path': plugin_dir, 'plugins': plugin_list})
plugins = find_plugins()
plugin_menu_entries = []
for plugin in plugins:
    print "Enabling plugin: %s" % plugin.__name__
    plugin_menu_entries.append(plugin.menu_entry))
add_menu_entries(plugin_menu_entries) # This is an imaginary function

Cela devrait fonctionner aussi longtemps que le plug-in est soit un fichier ou .py .pyc (en supposant qu'il est compilé pour octet la plate-forme en question). Il peut être un fichier autonome ou à l'intérieur d'un répertoire avec un init py ou à l'intérieur d'un fichier zip avec les mêmes règles.

Comment puis-je sais que cela fonctionne? Il est ainsi que je mis en œuvre plugins dans PyCI . PyCI est une application Web, mais il n'y a aucune raison pour que cette méthode ne fonctionnerait pas pour GUI « un ol régulier. Pour l'exemple ci-dessus, j'ai choisi d'utiliser une fonction add_menu_entries imaginaire () en conjonction avec une variable d'objet Plugin qui pourrait être utilisé pour ajouter des méthodes d'un plug-in pour les menus de votre interface graphique.

Espérons que cette réponse vous aidera à construire votre propre système de plug-in. Si vous voulez voir précisément comment il est mis en œuvre, je vous recommande de télécharger le code source PyCI et regardez plugin_utils.py et le plug-in exemple dans le répertoire plugins_enabled.

Autres conseils

Voici un autre exemple d'une application Python qui utilise des plugins: OpenSTV . Ici, les plug-ins ne peuvent être que des modules Python.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top