5

Twisted Documentation で指定されているように、twistd ランナー用のプラグインを使用して素敵な python Twisted アプリを作成しました: 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 仕様ファイルを使用しており、非表示のインポートやインポート フックは指定されていません。

ロギング、pid ファイルなどを使用した twistd の機能が気に入っているので、プラグインの問題を回避するために twistd ランナーを完全に放棄する必要がないようにしたいと考えています。私の twistd プラグインが凍結された実行可能ファイルで確実に見つかるようにする方法はありますか?

4

1 に答える 1

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()
于 2012-04-17T15:59:58.670 に答える