🚀

bottleソースコードリーディング その1

2023/01/18に公開

webフレームワークのソースコードリーディングの記録です。
Djangoは量が多いのでまずは軽量フレームワークのbottleのソースコードを読んでみました。
https://bottlepy.org/docs/dev/

サンプルコード

from bottle import route, run, template

@route('/hello/<name>')
def index(name):
    return template('<b>Hello {{name}}</b>!', name=name)

run(host='localhost', port=8080)

ルーティングの登録

まず、デコレータrouteが実行され、indexメソッドが登録される
importされているrouteは以下
https://github.com/bottlepy/bottle/blob/master/bottle.py#L3187
make_default_app_wrapperでは、Bottleクラスから引数のメソッドを取得しているので
(L3182のapp()でBottleオブジェクト取得している)
https://github.com/bottlepy/bottle/blob/master/bottle.py#L3177-L3184
Bottleクラス内で定義されているrouteが実行される
https://github.com/bottlepy/bottle/blob/master/bottle.py#L870-L918
L918のelseのdecoratorが実行され、add_routeにて、ルートのパターンと関数が登録される
https://github.com/bottlepy/bottle/blob/master/bottle.py#L863-L868
L867のaddの処理で登録
https://github.com/bottlepy/bottle/blob/master/bottle.py#L355-L426
add内の最終行で_compileが実行され、そこでself.dyna_regexesにルーティングのルールとindexメソッドのデータが追加される(ここの細かい内容についてはまだ未確認)
https://github.com/bottlepy/bottle/blob/master/bottle.py#L428-L438
ここまででルーティングのルールが登録される。

サーバー起動

ルーティング登録後、runでサーバーが起動される

from bottle import route, run, template

@route('/hello/<name>')
def index(name):
    return template('<b>Hello {{name}}</b>!', name=name)

run(host='localhost', port=8080)

サーバーはデフォルト引数からポートやBottleオブジェクトを引数として渡してwsgirefサーバーが起動する(L3725のserver.run(app))
https://github.com/bottlepy/bottle/blob/master/bottle.py#L3625-L3735
※ここは細かく見ないがcpythonのwsgirefサーバーが起動する
https://github.com/python/cpython/tree/main/Lib/wsgiref

リクエストの処理

※ここでは、localhost:8080/hello/yamadaにアクセスしたとします
Bottleの__call__()がリクエスト時に呼び出される
https://github.com/bottlepy/bottle/blob/master/bottle.py#L1118-L1120
https://github.com/bottlepy/bottle/blob/master/bottle.py#L1088-L1091
_handleメソッド内にてmatchが実行され、リクエストの情報からレスポンスを生成するために必要なデータを取り出す
https://github.com/bottlepy/bottle/blob/master/bottle.py#L965-L979
このmatchでは、登録した情報(indexメソッドなど)が入ったRouteオブジェクトとリクエストに含まれる引数のデータがかえってくる(この場合、{'name': 'yamada'})
https://github.com/bottlepy/bottle/blob/master/bottle.py#L454-L469
L983にて取得したリクエストのデータを引数にRouteオブジェクトのcallメソッドが実行される
callメソッドではRouteオブジェクト内のcallbackが返されるので、ここではindexメソッドが返ってきて、リクエストのデータ({'name': 'yamada'})を引数に、indexメソッドが実行される
https://github.com/bottlepy/bottle/blob/master/bottle.py#L546-L558
生成されたhtml用の文字列がiterableな型でwsgiサーバーへと返される
https://github.com/bottlepy/bottle/blob/master/bottle.py#L1088-L1101

Discussion