DRYな備忘録

Don't Repeat Yourself.

Djangoが嫌いなのでPyramidっていうのをやってみる【Python3.3】【MacOSX10.9】

Python

 そもそもなぜPython選ぶかっていうと、Pythonの画像処理ライブラリ(その名もずばりPython Imaging Library (PIL))の使い勝手がなかなか好きなので、画像処理したい時に選びます。実際、以前艦これ関係でOCRサーバを作ったときにPILに画像の前処理なんかをしてもらいました。これ otiai10/ocr-kcwidget · GitHub

Flask

 で、今回も画像処理が必要っぽい案件だったので、Pythonを選んだわけだけど。

 サーバどうしようかな、Flaskだとビューとかテンプレートの機能が乏しいので、APIサーバには向いてるけど面のあるサーバだとちょっと物足りない気もした。Djangoは重厚感が嫌いです。

Pyramid

なるほどやってみよう、というわけ

インストール

pyenvは入ってる前提で

% cd
% mkdir proj/pyramids
% cd proj/pyramids
% python --version
Python 2.7.5
% pyenv local 3.3.3
% python --version
Python 3.3.3
% pip install pyramid

プロジェクトの作成、起動

% ~/.pyenv/versions/3.3.3/bin/pcreate -s alchemy myTutorial
# いつも思うんだけど、pipで入れたコマンドにパス通らないんだよなぁ...
% cd myTutorial
% python setup.py develop
% ~/.pyenv/versions/3.3.3/bin/initialize_myTutorial_db development.ini
# はーん、テーブルとか作ったっぽい。Railsのmigrationみたいなやつ?

起動してみる

% ~/.pyenv/versions/3.3.3/bin/pserve development.ini --reload
Starting subprocess with file monitor
Starting server in PID 24477.
serving on http://0.0.0.0:6543

f:id:otiai10:20140406060931p:plain

あらやだ、かんたん。

ディレクトリ構成とか

% tree -L 1
.
├── CHANGES.txt
├── MANIFEST.in
├── README.txt
├── development.ini
├── myTutorial.egg-info
├── myTutorial.sqlite
├── mytutorial
├── production.ini
├── setup.cfg
└── setup.py

2 directories, 8 files

アプリケーションなコードはmytutorialの中にあるっぽい

% tree -L 1 mytutorial
mytutorial
├── __init__.py
├── __pycache__
├── models.py
├── scripts
├── static
├── templates
├── tests.py
└── views.py

4 directories, 4 files

ん、ルーターとかコントローラーは無いのか?

ルーティング

mytutorial/__init__.py

from pyramid.config import Configurator
from sqlalchemy import engine_from_config

from .models import (
    DBSession,
    Base,
    )


def main(global_config, **settings):
    """ This function returns a Pyramid WSGI application.
    """
    engine = engine_from_config(settings, 'sqlalchemy.')
    DBSession.configure(bind=engine)
    Base.metadata.bind = engine
    config = Configurator(settings=settings)
    config.add_static_view('static', 'static', cache_max_age=3600)
    config.add_route('home', '/')
    config.scan()
    return config.make_wsgi_app()

views?

ビューらしきファイルを見てみる

mytutorial/views.py

from pyramid.response import Response
from pyramid.view import view_config

from sqlalchemy.exc import DBAPIError

from .models import (
    DBSession,
    MyModel,
    )


@view_config(route_name='home', renderer='templates/mytemplate.pt')
def my_view(request):
    try:
        one = DBSession.query(MyModel).filter(MyModel.name == 'one').first()
    except DBAPIError:
        return Response(conn_err_msg, content_type='text/plain', status_int=500)
    return {'one': one, 'project': 'myTutorial'}

conn_err_msg = """\
Pyramid is having a problem using your SQL database.  The problem
might be caused by one of the following things:

1.  You may need to run the "initialize_myTutorial_db" script
    to initialize your database tables.  Check your virtual
    environment's "bin" directory for this script and try to run it.

2.  Your database server may not be running.  Check that the
    database server referred to by the "sqlalchemy.url" setting in
    your "development.ini" file is running.

After you fix the problem, please restart the Pyramid application to
try it again.
"""

おー、結構色々書いてある。もはやいわゆるコントローラーっぽい。

ちょっと調べてみると、、、

You Say Pyramid is MVC, But Where’s The Controller?

Pyramid が MVC だと言うけれど、コントローラーはどこ?

Pyramid の作者は、 MVC パターンが実際にはウェブにあまりぴった りとフィットしないと信じています。 Pyramid アプリケーションでは、 サイト構造を表すリソースツリーと、リソースツリーとユーザ定義の 「ドメインモデル」に保存されたデータを表示する傾向にあるビューがあります。 しかしながら、 フレームワークによって 提供される機能は、必ずしも 実際に「コントローラ」あるいは「モデル」の概念にマッピングされません。 したがって、それに頭字語を与えなければならないとしたら、私は Pyramid が実際には「MVCフレームワークというよりむしろ「RV」 フレームワークであると言うべきだろうと思います。しかし、「MVC」は、 他のウェブフレームワークとの比較の目的のための一般的な分類名としては 十分に近いです。

Pyramid イントロダクション — The Pyramid Web Application Development Framework v1.4.3 (翻訳)

f:id:otiai10:20140406062053j:plain

エンドポイントの追加

やってみる

diff --git a/mytutorial/__init__.py b/mytutorial/__init__.py
index aac7c5e..f8e6dbc 100644
--- a/mytutorial/__init__.py
+++ b/mytutorial/__init__.py
@@ -16,5 +16,7 @@ def main(global_config, **settings):
     config = Configurator(settings=settings)
     config.add_static_view('static', 'static', cache_max_age=3600)
     config.add_route('home', '/')
+    config.add_route('foo', '/foo')
+    config.add_route('bar', '/bar')
     config.scan()
     return config.make_wsgi_app()
diff --git a/mytutorial/views.py b/mytutorial/views.py
index 314f524..9909f22 100644
--- a/mytutorial/views.py
+++ b/mytutorial/views.py
@@ -8,6 +8,8 @@ from .models import (
     MyModel,
     )
 
+import json

 @view_config(route_name='home', renderer='templates/mytemplate.pt')
 def my_view(request):
@@ -17,6 +19,14 @@ def my_view(request):
         return Response(conn_err_msg, content_type='text/plain', status_int=500)
     return {'one': one, 'project': 'myTutorial'}
 
+@view_config(route_name='foo')
+def foo_view(request):
+    return Response("This is `foo` view", content_type='text/plain', status_int=200)
+
+@view_config(route_name='bar')
+def bar_view(request):
+    return Response(json.dumps({"message":"This is `bar` message"}), content_type='application/json', status_int=200)
+
 conn_err_msg = """\
 Pyramid is having a problem using your SQL database.  The problem
 might be caused by one of the following things:

で再起動する

f:id:otiai10:20140406063250p:plain

f:id:otiai10:20140406063259p:plain

content_typeもちゃんと出し分けれてるし、良い感じっぽい

DRYな備忘録