Colubrid 0.10

PythonといえばWSGIWSGIといえばPython
というわけで、シンプルなWSGIパブリッシャーColubridでWSGIの体験です。
コードも短くてシンプルなのでサクッと読めてしまいます(WSGIミドルウェアが提供してくれる引数が得体が知れないのでそこら辺若干の読みづらさはあるかもですが)。

PyPIページ
開発元

あと、WSGIについては、ちょっと長いですが

http://wiki.pylonshq.com/display/pylonsja/PEP333-ja

を見ればどういったものかわかると思います。


PyPIのcolubridのページにHelloWorldのサンプルがあるんですが、そのソースだけではどう動かしてよいのやら?な感じで、また、開発元のドキュメントにあるサンプルソースもちょっと古いのか?うまく動かないっぽいです。

で、動くHelloWorldはこんな感じに。

from colubrid import BaseApplication, HttpResponse
from colubrid import execute

class HelloWorld(BaseApplication):
    def process_request(self):
        return HttpResponse('Hello World!')

app = HelloWorld

if __name__ == '__main__':
    execute()

このソースを実行すると、8080番ポートでhttpdが起動しますんで、ブラウザにアクセスすれば無事『Hello World!』が表示されるわけです。

このソース自体のメインの処理はexecute()関数ですが、これの本体は

colubrid.server.execute

でして、colubrid/__init__.pyで

from colubrid.server import execute

としてあるので、server.pyのexecute関数が実行されているわけですね。

server.pyのexecute()関数ではWebサーバモジュールを読み込んで実行しているんですが、

  • pasteのhttpserver
  • BaseWSGIServer
  • wsgiref

を上から探して、importできたものをWebサーバとして使ってくれます。

execute()関数に与える引数は

  • app WSGIでいうところのcallableなアプリケーション。デフォルトはNone
  • debug デフォルトでTrue
  • hostname 見てのとおりホスト名。デフォルトで'localhost'
  • port ポート番号。デフォルトで8080
  • reload リロードフラグ、デフォルトでFalse
  • evalex デフォルトでFalse

となってまして、基本的にapp以外デフォルト値が決まってるんでさっきのHelloWorldではexecute()関数に何も渡しませんでしたが動作したわけです。
一番下の二つは本筋から離れるので気にしない方向で。ていうかそこまで追っかけてみてません。。

appについては

app = frm.f_globals['app']

という具合でexecute()の呼び元から拾ってきてくれます。
つまりはHelloWorldクラスがappとして利用されるわけです。*1

ここで冒頭で紹介したPEP333に戻るわけですが、アプリケーションオブジェクトの定義について

アプリケーションオブジェクトは 2つの固定引数を受け付けなければならない。例証のために、それらを environ と start_response と名付けるが、これらの名前を持つ必要はない。サーバまたはゲートウェイは、固定引数 (キーワード引数ではなく) を使用してアプリケーションオブジェクトを呼び出さ なければならない。 (例えば、上に示されるように、result = application(environ, start_response) のようにして呼び出す)

とあります。

HelloWorldクラスの親クラスであるBaseApplicationクラスは、colubridのapplicationモジュールで定義されていて、そのコンストラクタは

def __init__(self, environ, start_response, request_class=Request):

なってます。変数名がPEPと同じ表現なので一目でわかりますね。

また、アプリケーションオブジェクトについて追加で

アプリケーションオブジェクトは、サーバによって呼ばれると、文字列を yield する iterable を返さなければならない。

とあります。

BaseApplicationクラスは

def __iter__(self):

メソッドが宣言されているため、この条件も満たす、というわけです。


単純な例でしたが、とどのつまり
WSGIに乗っかるフレームワーク(もしくはアプリケーション)側は最低限これだけ満たせば良いってことが実際のソースレベルでわかったつもりになれるかなと思います(´・ω・`)

*1:Pythonではクラスもオブジェクトとして扱えます