Упаковка плагина twistd с помощью pyinstaller
Я создал красивое приложение Python Twisted с плагином для Twistd Runner, как указано в Twisted Documentation: http://twistedmatrix.com/documents/current/core/howto/tap.html. У меня проблемы с упаковкой с помощью PyInstaller: мой плагин twistd не найден во время выполнения замороженного приложения.
Чтобы отправить свой проект, я создал свой собственный стартовый скрипт верхнего уровня с использованием модулей запуска twistd, например
#!/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, чтобы обнаружить мой плагин в файле twisted/plugins/myapp_plugin.py. Если я распечатаю список плагинов twistd в моем скрипте запуска, этот список будет пуст в исполняемом файле, полученном из PyInstaller, например
from twisted.plugin import IPlugin, getPlugins
plugins = list(getPlugins(IPlugin))
print "Twistd plugins=%s" % plugins
Я использую несколько спецификаций PyInstaller по умолчанию, скрытых импортов или хуков импорта не указано.
Мне нравится функциональность twistd с ведением журналов, pid-файлами и т. Д., Поэтому я хотел бы избежать необходимости полностью отказаться от запуска twistd, чтобы обойти проблему с плагином. Есть ли способ убедиться, что мой плагин twistd находится в замороженном исполняемом файле?
1 ответ
Я нашел обходной путь путем обратного инжиниринга некоторых искаженных кодов. Здесь я жестко закодировал импорт плагина. Это прекрасно работает с 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()