From Evernote: |
pastescript離れを考える |
Pyramidも使ってるPasteScriptだけど、Pasteという結構大きめなライブラリに依存している。
そして、Pasteライブラリって大部分は既に使われていないんだよね。
ということで、WSGIに限らず細かなタスクをまとめるものとして、paverをもうちょっと使うことを考えた。
fabricでもいいかもしんない。
paverのタスクは、カレントディレクトリにあるpavement.py に定義します。
task デコレータで登録。
と、これが前回調べたときのおさらい。
今回はpaverからWSGIアプリケーションを実行させてみる。
WSGIアプリケーション実行
PasteScriptは内部でPasteDeployを使ってWSGIアプリをロードしている。
このとき、PasteDeployは指定された設定ファイルの内容を、app_factoryに渡す。
ということなので、WSGIアプリケーションをpkg_resourcesを使ってegg経由で呼び出す方法と、dotted_nameで呼び出す方法と二種類考える。
まずは、いきなり WSGIアプリケーションを取得する方法。
とりあえず、wsgiref.simple_server.demoapp を例にします。
文字列で渡されたパッケージ名からインポートするには、 __import__ 関数を使います。
また、インポート済のパッケージは、 sys.modules から取得できます。
オブジェクトは、getattr で取り出せばよいです。
from paver.easy import *
options(
run_server={
'port': '8080',
},
)
@task
@cmdopts([
('appname=', 'a', 'wsgi application'),
('port=', 'p', 'port of httpd'),
])
def run_server(options, info):
""" run wsgi application """
dotted_name = options.appname
port = int(options.port)
mod, obj = dotted_name.split(":")
__import__(mod)
app = getattr(sys.modules[mod], obj)
from wsgiref.simple_server import make_server
httpd = make_server('', port, app)
info('run wsgi application %s on port %d' % (dotted_name, port))
httpd.serve_forever()
というところ。
しかし、これでは設定を切り替えたりできないので、 paste.app_factory エントリポイントを pkg_resources から取得して設定を渡したいところ。
appnameが、"egg:" で始まる場合は、pkg_resourcesで取得するようにします。
またコンフィグレーションファイルの内容をapp_factoryに渡してwsgiアプリを作成するようにします。
コンフィグレーションファイルのパーサーとして、configobjを利用することにします。
from paver.easy import *
import pkg_resources
import configobj
options(
run_server={
'port': '8080',
},
)
@task
@cmdopts([
('appname=', 'a', 'wsgi application'),
('port=', 'p', 'port of httpd'),
('config=', 'c', 'configuration file'),
])
def run_server(options, info):
""" run wsgi application """
dotted_name = options.appname
port = int(options.port)
if dotted_name.startswith('egg:'):
egg_name = dotted_name[len('egg:'):]
distname, entryname = egg_name.split(':', 1)
app_factory = pkg_resources.load_entry_point(distname, 'paste.app_factory', entryname)
config = configobj.ConfigObj(options.config)
app = app_factory(config.get('global', {}), **config[egg_name].dict())
else:
mod, obj = dotted_name.split(":")
__import__(mod)
app = getattr(sys.modules[mod], obj)
from wsgiref.simple_server import make_server
httpd = make_server('', port, app)
info('run wsgi application %s on port %d' % (dotted_name, port))
httpd.serve_forever()
PasteScript, PasteDeployの組み合わせだと、さらにWSGIミドルウェアの構成を変えられますが、そこまではさすがに手間なのでやらないことにします。