【Python】 Bottleのソースコードを読んでみる　その１

# bottle.pyを読む

Pythonのwebフレームワーク、Bottleのコードリーディングをしてみました。
Bottleのソースコードはbottle.pyに集約されているので、このファイルを読むことになります。

GitHubはこちら。
https://github.com/bottlepy/bottle

以下で引用するコードは、bottle.pyから必要な部分のみを引用したものになります。
また、ところどころ勝手にコメントを付け加えています。

最初から細かい部分まで追うと大変なので、まずは全体の流れを掴みたいと思います。

# 最初の入り口： run()

起動から順番にソースを追っていきたいと思います。
Bottleの起動は、例えばドキュメントによると以下のようにする。

```python
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)
```

`run()`からみていきましょう。
念の為もう一度言いますが、ソースコードは（大部分を）端折って引用しています。

```bottle.py
def run(app=None,
        server='wsgiref',
        host='127.0.0.1',
        port=8080,
        interval=1,
        reloader=False,
        quiet=False,
        plugins=None,
        debug=None,
        config=None, **kargs):

    app = app or default_app()

    if server in server_names:
            server = server_names.get(server)
        if isinstance(server, basestring):
            server = load(server)
        if isinstance(server, type):
            server = server(host=host, port=port, **kargs)
        if not isinstance(server, ServerAdapter):
            raise ValueError("Unknown or unsupported server: %r" % server)

    if reloader:
            lockfile = os.environ.get('BOTTLE_LOCKFILE')
            bgcheck = FileCheckerThread(lockfile, interval)
            with bgcheck:
                server.run(app)
            if bgcheck.status == 'reload':
                sys.exit(3)
        else:
            server.run(app)

```

要するに

```python
app = app or default_app()  # デフォルトだと app=None
server = server_names.get(server)  # デフォルトだと server='wsgiref'
server.run(app)
```

ってことですね。
まずは一行目の`default_app()`の定義をみてみます。

# AppStackクラスってなんだ？

定義箇所は

```python
apps = app = default_app = AppStack()
```

で、

```bottle.py

class AppStack(list):
    """ A stack-like list. Calling it returns the head of the stack. """

    def __call__(self):
        """ Return the current default application. """
        return self.default

    def push(self, value=None):
        """ Add a new :class:`Bottle` instance to the stack """
        if not isinstance(value, Bottle):
            value = Bottle()
        self.append(value)
        return value
    new_app = push

    @property
    def default(self):
        try:
            return self[-1]
        except IndexError:
            return self.push()
```

ほほう。AppStackはlistを継承していると。
`AppStack()`を使う側（`server`）からして大事なのは`__call__`メソッドでしょう。

callメソッドの復習がてらまとめると、

```python
app = AppStack()
app()
```

と呼び出すと、（デフォルト引数なら）`Bottle`インスタンスが返ってくるらしい。
と同時に、そいつをlistとして蓄積していく仕組みなんですね。

`Bottle`クラスのソースをまとめたいところですが、名前通りこいつがBottleの中核らしく、長い。
そもそも`AppStack`インスタンスは

```python

server.run(app)
```
でserverのrunメソッドに引数として渡されており、その先で`app()`とcallされるはずなので、先に`server`について調べてみよう。

# Serverクラス

少し振り返ると、

```python

app = app or default_app()  # デフォルトだと app=None
server = server_names.get(server)  # デフォルトだと server='wsgiref'
server.run(app)
```

の部分で定義される`server`が何者なのか調べようという話。

```bottle.py

server_names = {
    'cgi': CGIServer,
    'flup': FlupFCGIServer,
    'wsgiref': WSGIRefServer,  # デフォルトだとこいつが使われる
    'waitress': WaitressServer,
    # 以下略
}
```

と辞書になっており、各valueは`ServerAdapter`クラスを継承している。こいつは「形だけの親」的な存在なので、いきなり`WSGIRefServer`クラスにいく。

```bottle.py
class WSGIRefServer(ServerAdapter):
    def run(self, app):  # pragma: no cover
        from wsgiref.simple_server import make_server
        from wsgiref.simple_server import WSGIRequestHandler, WSGIServer
        import socket

        server_cls = self.options.get('server_class', WSGIServer)
        self.srv = make_server(self.host, self.port, app, server_cls,
                               handler_cls)
        self.port = self.srv.server_port  # update port actual port (0 means random)
        try:
            self.srv.serve_forever()
        except KeyboardInterrupt:
            self.srv.server_close()  # Prevent ResourceWarning: unclosed socket
            raise
```

`server.run()`に渡された`app = AppStack()`は`make_server`関数に渡される。
`make_server`関数自体はpythonの標準ライブラリ`wsgiref`のもの。

https://docs.python.org/ja/3/library/wsgiref.html　

> Web Server Gateway Interface (WSGI) は、Web サーバソフトウェアと Python で記述された Web アプリケーションとの標準インターフェースです。標準インターフェースを持つことで、WSGI をサポートするアプリケーションを幾つもの異なる Web サーバで使うことが容易になります。



ってことで、`wsgiref`のドキュメントにあるサンプルをみてみる。

```python

from wsgiref.util import setup_testing_defaults
from wsgiref.simple_server import make_server

def simple_app(environ, start_response):
    setup_testing_defaults(environ)

    status = '200 OK'
    headers = [('Content-type', 'text/plain')]

    start_response(status, headers)

    ret = ["%s: %s\n" % (key, value)
           for key, value in environ.iteritems()]
    return ret

httpd = make_server('', 8000, simple_app)
print "Serving on port 8000..."
httpd.serve_forever()
```

・`make_server`関数に第三引数として、自分で定義した関数（サンプルだと`simple_app`関数）を渡してね！
・するとリクエストが飛んできたときに、その関数に処理させることができるよ！
・ただし２つの引数`(environ, start_response)`を用意してね！

ってことですね。

そんでもって、これまでのソースを振り返ってみると、その関数（サンプルにおける`simple_app`）とは`Bottle()`のことでしたね。

関数じゃなくてインスタンスじゃん！
でも大丈夫！
`__call__`インスタンスを用意しておけば、関数と同じように呼ばれることができるから！

くどいようですが整理すると、サンプルで

```python

simple_app(environ, start_response)
```
と実行される行為は、

```python
Bottle()(environ, start_response)
```

が実行されることに等しいってことよね。<br>

<b>つまり</b>

<b>当たり前のようだけど、Bottleインスタンスが実質的な処理を担う</b>

ってことがわかった。

実際

```bottle.py

class Bottle(object):

    def __call__(self, environ, start_response):
```

が定義されている。

ここまで長かった。

`Bottle`クラスは[次回](https://qiita.com/nyancook/items/1181597a10f8c4481a56)にします。


# ここまでのまとめ

`wsgiref`ライブラリの`make_server`関数の引数として`Bottle()`が渡され、こいつが実質的な処理を担う。