2012-04-16 2 views
4

Я создал приятное приложение для виртуализации python с плагином для проигрывателя twistd, как указано в Twisted Documentation: http://twistedmatrix.com/documents/current/core/howto/tap.html. У меня проблемы с упаковкой с помощью PyInstaller: мой плагин twistd не найден во время выполнения замороженного приложения.Упаковка плагина twistd с помощью pyinstaller

Чтобы отправить мой проект, я создал свой собственный стартовый сценарий верхнего уровня, используя модули twistd runner, например.

#!/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() 

Далее, я использую PyInstaller, чтобы заморозить это как развертывание единого каталога. Выполнение замороженного сценария выше не как не может найти мой twistd плагина (отредактированный для краткости):

~/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 

Обычно, Twistd проверяет системный путь Python, чтобы обнаружить мой плагин в витом/плагин/myapp_plugin.py. Если я распечатаю список плагинов twistd в моем сценарии запуска, список пуст в исполняемом файле, полученном в PyInstaller, например.

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

Я использую несколько спецификаций PyInstaller по умолчанию, никаких скрытых импортных или импортных перехватчиков.

Мне нравится функциональность twistd с протоколированием, pid-файлами и т. Д., Поэтому я бы хотел, чтобы вы отказались от твист-бегуна, чтобы обойти проблему с плагином. Есть ли способ обеспечить мой плагин twistd в замороженном исполняемом файле?

+0

Большой вопрос. Спасибо, что спросили об этом. Упаковка. Скрученные плагины - это больные спот-инструменты для упаковки, которые часто не учитывают его, - и я с нетерпением жду ответа от кого-то, кто знает больше о pyinstaller :). – Glyph

+0

Спасибо. В то же время мне удалось запустить PyInstaller успешно на скрипт-скрипте python, который не использует твист, но просто запускает скрученный реактор, например. реактор.listenTCP (9999, сайт); reactor.run() '. Таким образом, проблем с упаковкой с скрученными вообще, только с системой twistd plugin. –

+0

Путь в предупреждении '~/pyinstall/dist/mystartup? 16632' выглядит подозрительно. Я предполагаю, что это то, что создает pyinstaller - поэтому, возможно, pyinstaller отвечает за добавление его в правильные части конфигурации импорта Python (например, без ограничений, 'sys.path'). Я действительно удивляюсь, почему у этого пути есть '~'. Как вы, возможно, знаете, этот символ не имеет особого значения, если явно не интерпретироваться с помощью 'os.path.expanduser'. Действия пути, выполняемые 'twisted.plugins', все будут смущены им. Этот путь, с буквальным '~', появляется в конфигурации импорта где-нибудь? –

ответ

2

Я нашел обходное решение для обратного проектирования некоторых из скрученного кода. Здесь я жестко задаю импорт плагина. Это отлично работает с PyInstaller для меня.

#!/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() 
Смежные вопросы