5 votes

Emballage d'un plugin twistd avec pyinstaller

J'ai créé une belle application Twisted en python avec un plugin pour le runner twistd, comme spécifié dans la documentation Twisted : http://twistedmatrix.com/documents/current/core/howto/tap.html . J'ai des problèmes pour l'empaqueter avec PyInstaller : mon plugin twistd n'est pas trouvé lors de l'exécution de l'application gelée.

Pour expédier mon projet, j'ai créé mon propre script de démarrage de haut niveau script en utilisant les modules d'exécution twistd, par exemple

#!/usr/bin/env python
from twisted.scripts.twistd import run
from sys import argv
argv[1:] = [
  '--pidfile', '/var/run/myapp.pid',
  '--logfile', '/var/run/myapp.log',
  'myapp_plugin'
]
run()

Ensuite, j'utilise PyInstaller pour figer le déploiement dans un seul répertoire. L'exécution du script gelé ci-dessus échoue car il ne trouve pas mon plugin twistd (édité par souci de concision) :

~/pyinstall/dist/bin/mystartup?16632/twisted/python/modules.py:758:
UserWarning: ~/pyinstall/dist/mystartup?16632 (for module twisted.plugins)
not in path importer cache (PEP 302 violation - check your local configuration).

~/pyinstall/dist/bin/mystartup: Unknown command: myapp_plugin

Normalement, Twistd inspecte le chemin du système Python pour découvrir mon plugin dans twisted/plugins/myapp_plugin.py. Si j'imprime la liste des plugins twistd dans mon script de démarrage, la liste est vide dans l'exécutable résultant de PyInstaller, par ex.

from twisted.plugin import IPlugin, getPlugins
plugins = list(getPlugins(IPlugin))
print "Twistd plugins=%s" % plugins

J'utilise un fichier de spécification PyInstaller un peu par défaut, sans importations cachées ou crochets d'importation spécifiés.

J'aime la fonctionnalité de twistd avec la journalisation, les fichiers pid, etc, donc j'aimerais éviter d'avoir à abandonner complètement le runner twistd pour contourner le problème du plugin. Existe-t-il un moyen de s'assurer que mon plugin twistd se trouve dans l'exécutable gelé ?

2voto

Martijn Rutten Points 393

J'ai trouvé une solution de contournement en faisant de la rétro-ingénierie sur une partie du code tordu. Ici, j'ai codé en dur l'importation du plugin. Cela fonctionne bien avec PyInstaller pour moi.

#!/usr/bin/env python
import sys

from twisted.application import app
from twisted.scripts.twistd import runApp, ServerOptions

import myapp_plugin as myplugin

plug = myplugin.serviceMaker

class MyServerOptions(ServerOptions):
    """
    See twisted.application.app.ServerOptions.subCommands().
    Override to specify a single plugin subcommand and load the plugin
    explictly.
    """
    def subCommands(self):
        self.loadedPlugins = {plug.tapname:plug}
        yield (plug.tapname,
               None,
               # Avoid resolving the options attribute right away, in case
               # it's a property with a non-trivial getter (eg, one which
               # imports modules).
               lambda plug=plug: plug.options(),
               plug.description)

    subCommands = property(subCommands)

def run():
    """
    Replace twisted.application.app.run()
    To use our ServerOptions.
    """
    app.run(runApp, MyServerOptions)

sys.argv[1:] = [
    '--pidfile', '/var/run/myapp.pid',
    '--logfile', '/var/run/myapp.log',
    plug.tapname] + sys.argv[1:]

run()

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