2014年7月1日火曜日

軽量pythonフレームワーク「bottle」の導入

開発するにあたり、やはりフレームワークは有った方が良いですよね。
openstackなんかはDjangoを使っているようですが、なにぶん初心者なので、、、挫折しないシンプルなものは無いかと探していたところ、ありました!bottle!

なんと驚愕の1ファイル、146kbyte!
でもこれで、立派なフレームワークです。

では恒例のhello worldまでを見ていきましょう。

bottleインストール

公式webはこちら
wgetでbottle.pyを持ってきてカレントディレクトリに置くのでも良いのですが、せっかくpipを入れた事ですし、pipで入れましょう。

(dev001)kitabat@clientX% pip install bottle
(dev001)kitabat@clientX% pip list
bottle (0.12.7)
pip (1.5.6)
setuptools (3.6)
はい、終わりです。これで from bottle import すればbottleが使えます。
pip listを打つとbottleが入っている事を確認出来ます。今回は 0.12.7 というバージョンが入りました。


hello, world!!


まず、virtualenvで作ったディレクトリのルートにはbin、libなどがあるので、workというディレクトリを作ってそこで作業を進めます。

(dev001)kitabat@clientX% pwd
/home/kitabat/dev001
(dev001)kitabat@clientX% mkdir work
(dev001)kitabat@clientX% cd work
(dev001)kitabat@clientX% vim hello.py 

では公式webにもある例文を見てみます。以下をhello.pyとして作成しましょう。

from bottle import route, run

@route('/hello')
def hello():
    return "Hello, World!!"

run(host='0.0.0.0', port=8080, debug=True)


1行目はbottleの利用宣言です。bottleという機能群から、routeとrunという機能を使いますよ、の意味です。
説明順が前後しますが、7行目がmain処理です。bottleは自身がwebサーバとして動作し、この例だと http://<サーバIP>:8080/ でwebアクセスを待ち受けます(0.0.0.0とする事でサーバの全NICでListenします)。
debug=Trueで、ターミナルにデバッグメッセージが出ます。
ここまではbottleを利用する場合は毎回ほぼ同じです。

アプリケーションの動作を決定するのは3〜5行目です。
/helloにアクセスがあれば(正確には、http://<サーバIP>:8080/hello にアクセスがあれば)、hello()以下が呼び出されます。
def xxx()はpythonの関数定義、@xxx()はデコレータと呼ばれる仕組みです。この辺りは後ほど書ければ書きます。

では実行してみましょう!
っとその前にこのサーバのIPを確認しておきます。192.168.56.103です(virtual boxなのがバレバレですね)。
(dev001)kitabat@clientX% python hello.py 
(dev001)kitabat@clientX% ip addr show | grep inet
    inet 127.0.0.1/8 scope host lo
    inet 192.168.56.103/24 brd 192.168.56.255 scope global eth0

おもむろにpython hello.pyとタイプします。
(dev001)kitabat@clientX% python hello.py 
Bottle v0.12.7 server starting up (using WSGIRefServer())...
Listening on http://0.0.0.0:8080/
Hit Ctrl-C to quit.


はい、ターミナル、何も返ってこなくなりましたね。これでOKです。
先ほど確認したip:8080/helloにブラウザでアクセスしてみましょう!

おお〜!皆さん、出ましたか?
ちなみにターミナルを見ると、アクセスログが表示されております。
(dev001)kitabat@clientX% python hello.py 
Bottle v0.12.7 server starting up (using WSGIRefServer())...
Listening on http://0.0.0.0:8080/
Hit Ctrl-C to quit.

192.168.56.1 - - [26/Jun/2014 17:56:56] "GET /hello HTTP/1.1" 200 12


もうちょっと使ってみる


例えば '/' (http://192.168.56.103:8080/)にアクセスすると、当然、定義が無いので怒られます。


以下のコードを追記すると、問題なくアクセス出来るようになります。

from bottle import route, run

@route('/')
@route('/hello')
def hello():
    return "Hello World!"

run(host='0.0.0.0', port=8080, debug=True, reloader=True)

3行目に @route('/') を加えています。こんな感じでデコレータは関数に対して幾つも記載可能です。それと、直接は関係無いのですがrun()に渡す引数として reloader=True を加えています。これはbottleが、コードの編集を認識し再読み込みしてくれるオプションです。付けない場合は、コードの反映にbottleの停止起動が必要になります。



はい、無事アクセス出来ました。

ちなみに以下のようにする事でURLのパスを取得出来ます。

from bottle import route, run

@route('/')
@route('/<hoge>')
def hello(hoge="root"):
    return "Hello World!<br> path is " + hoge

run(host='0.0.0.0', port=8080, debug=True, reloader=True)

4行目で、アクセスされたurlをhogeという変数で受け取り、それをhello()関数の引数として使っています。5行目で、hogeのデフォルト値を"root"にしていますが、これは '/' へのアクセス時に使われます。
6行目で、hoge変数も表示するよう設定しています。

/helloへアクセスした場合



行けますね。じゃあ次。

ルート('/')にアクセスした場合


問題無しです!デフォルト値の"root" が適用されている事が確認出来ます。


補足:注意点

reloader=Trueが悪いのか分からないのですが、コードを編集し、bottleがリロードされてから暫く、アクセス出来るはずのURLに、何故かアクセス出来なくなる事があります。その時は根気よくブラウザのリロードをすれば良いのですが、酷い場合は1分程、アクセス出来ません。



ひとたびアクセス出来れば、以後はスムーズなのですが。。。
この問題の困るところは、修正したコードに何か誤りが有ったから表示出来なくなったのだ、と勘違いする事です。
この思考に落ち入ると、せっかく書いたコードを過去に戻していき、しかし以前上手く行った筈のコードですらアクセス出来なくて、更に以前に戻し…、という非常に悲惨な循環にハマります。
pythonの構文でエラーが有るならば必ずターミナルに出力されますので、それが出ていないのにアクセス出来なかったら、この問題を疑って、ブラウザリロードを何度か、試みて下さい。

------

はい、という事で、如何でしたでしょうか。結構簡単に色々面白い事が出来そうですよね!
次回以降、アプリケーションを作る過程で、これはどうやるんだろう?に直面した事を、順にご紹介していきます。

0 件のコメント:

コメントを投稿