1ファイルのアプリでview_configを使う。
誰も特をしないpyramidの話。
pyramidのconfiguration
pyramidにはすごく雑にいうと以下の2つのconfigurationの方法がある。
- declarative configuration
- imperative configuration
すごく雑に言えば、declarative configurationはデコレーターを使った設定(内部でvenusianが使われる)。imperative configurationはConfiguratorオブジェクトのdirectiveを直接使って設定する方。viewの設定に限って言えば、前者が view_config
の利用。後者が add_view
の利用。
通常1ファイルではadd_viewを使う
ドキュメントにもある通り通常は、1ファイルのアプリを作るときにはadd_viewを使うことが多い。
from wsgiref.simple_server import make_server from pyramid.config import Configurator from pyramid.response import Response def hello_world(request): return Response('Hello %(name)s!' % request.matchdict) if __name__ == '__main__': config = Configurator() config.add_route('hello', '/hello/{name}') config.add_view(hello_world, route_name='hello') app = config.make_wsgi_app() server = make_server('0.0.0.0', 8080, app) server.serve_forever()
1ファイルでも view_config
を使いたい
view_configを使いたい。やっぱりpathの設定とview関数が遠い状態は面倒くさい。どうにかできないかと試行錯誤した結果出来るようになった。以下の様にすると1ファイルでview_configが使える
from wsgiref.simple_server import make_server from pyramid.view import view_config from pyramid.config import Configurator from pyramid.response import Response @view_config(route_name="hello") def hello_world(request): return Response('Hello %(name)s!' % request.matchdict) if __name__ == '__main__': config = Configurator() config.add_route('hello', '/hello/{name}') config.scan(__name__) app = config.make_wsgi_app() server = make_server('0.0.0.0', 8080, app) server.serve_forever()
詳しく説明すると、それこそpyramidの内部のことまでふれなければいけないので省略するけれど。declarative configurationはconfig.scan()の部分により、Configuratorのactionの実行に代わる。venusianというライブラリが使われていて、moduleの開始地点から登録されたclosure(たしか。ココは記憶で書いている)を実行する。そしてこの登録時の名前空間には呼び出されたタイミングでのモジュール名が使われる。
ここでpythonの話になる。例えば上のファイルの名前が app.py
だった時に、 python app.py
として実行された場合には、つまりエントリーポイントのモジュールの名前は"__main__"
として実行される。モジュール名自体は __name__
に格納されている。そんなわけで、__name__
をconfig.scanに渡している。
おまけ
ちょっと試して終了みたいなアプリの時に、一度だけrequestを受け取れば十分みたいなときがある。そのような場合にはserve_foreverを使うよりhandle_requestを使ったほうが楽。
server = make_server('0.0.0.0', 8080, app) server.handle_request()
すると、1回だけrequestを捌いたら終了してくれる
おまけ2
こういう1ファイルの時にrouteとpathの指定が面倒と言うことがあるその場合には以下の様なdirectiveないしはdecoratorを作ってあげると良いかもしれない。
import venusian from pyramid.config import PHASE1_CONFIG def add_simple_view(config, view, path, *args, **kwargs): def callback(): route_name = view.__qualname__ config.add_route(route_name, path) config.add_view(view, route_name=route_name, *args, **kwargs) discriminator = ('add_simple_view', path) config.action(discriminator, callback, order=PHASE1_CONFIG) # venusian対応 class simple_view(object): def __init__(self, path, *args, **kwargs): self.path = path self.args = args self.kwargs = kwargs def register(self, scanner, name, wrapped): scanner.config.add_simple_view(wrapped, self.path, *self.args, **self.kwargs) def __call__(self, wrapped): venusian.attach(wrapped, self.register) return wrapped def includeme(config): config.add_directive("add_simple_view", add_simple_view)
これを使うといよいよflaskっぽくなる。
from wsgiref.simple_server import make_server from pyramid.config import Configurator from pyramid.response import Response from my import simple_view @simple_view("/hello/{name}") def hello_world(request): return Response('Hello %(name)s!' % request.matchdict) if __name__ == '__main__': config = Configurator() config.include("my") # ここで上のadd_simple_viewなどが使えるようになる config.scan(__name__) app = config.make_wsgi_app() server = make_server('0.0.0.0', 8080, app) server.serve_forever()
参考