PythonのWAFやORMやテンプレートエンジンにはどういうのがあるのか調べてみました。
俺の要望
- GAEでも使えるものがいい。
- 複雑なRoutesはうんざり。シンプルなのがいい。
- ActiveRecordはうんざり。DataMapperがいい。
- hamlみたいにインデントを綺麗に出してくれるテンプレがいい。
- layoutみたいにパーツでなく枠を共有できるテンプレがいい。
調べた感じ
- GAE SDKにdjangoが入ってるらしい。
- Routingは正規表現が多い。
- SQLAlchemyというORMがDataMapperパターンらしい。
- インデントをそろえてくれるテンプレがみつからない。
- 枠の共有はテンプレの継承で行うみたい。(?)
- web.pyというのがシンプルっぽい。
「PythonでWAF,ORM,テンプレつったらxxxだろうjk・・・」
「xxx知らない情弱は負け組」
というのがあれば教えて頂けるとうれしいです。
python2.5からwsgirefというモジュールが標準で入ってるそうです。WSGIのリファレンス実装って意味かな?Rubyで言えばRackとWEBrickが標準で入ってるって感じでしょうか。
% vi wsgi.py
def application(environ, start_response):
start_response('200 OK', [('Content-type', 'text/plain')])
return 'Hello, WSGI!'
from wsgiref import simple_server
if __name__ == '__main__':
server = simple_server.make_server('', 8080, application)
server.serve_forever()
% python wsgi.py

ほう。
インストール。GAEがpython2.5だそうなので2.5を入れてみた。
% sudo port install python25
(...)
To fully complete your installation and make python 2.5 the default, please run
sudo port install python_select
sudo python_select python25
python_selectを入れて実行せよと出た。debianのupdate-alternativeみたいなもんだろう。
% sudo port install python_select
% sudo python_select -s
python26-apple
% sudo python_select python25
% sudo python_select -s
python25
macのデフォルトは2.6なんですね。これが普通なのかわからないけど2.5にしておきました。
% vi hello.py
print "Hello, Python!"
% python hello.py
Hello, Python!
うん。
随時更新。
Macのシンボリックリンク
zshで先頭を大文字で打たないと保管されないのが面倒なので。
% ln -s ~/Sites ~/site
% ln -s ~/Documents ~/doc
こっちの方が良い(via milkcocoa)
% vi ~/.zshrc
zstyle ':completion:*' matcher-list 'm:{a-z}={A-Z}'
viで:e ~/siteには効果なし
GAEjがどんなもんかイマイチつかめなかったんですが、やってみて、「最初からそういってくれよ!」と思ったので、過去の自分へのFAQ。
Q. どうやって動くの?
A. Java SE 6とServlet標準(実際はJetty)で動く。Java SE 6自体が過去のバージョンのclassもサポートしてるので大抵動く。あくまでServletが動くだけで勝手なプロセスを動かせるわけじゃないよ。(プロセスやスレッドの生成はできない)
Q. どうやってスケールするの?
A. 高負荷が続くと勝手にサーバインスタンスが増えてデプロイされるらしい。データはBigTable(分散KVS)に保存する。ファイルの書き込みは出来ない。
Q. どうやってアップするの?
A. そのためのクラスがあって、CUIからはラッパーシェルスクリプト、antタスク、GUIからはEclipse Pluginがある。どこのサーバーにアップするかとかそういうのを気にする必要は無い。
Q. 何をアップすればいいの?
A. app-engine.xmlという固有の設定ファイルを含めたWAR標準に則ったディレクトリをアップすればいい。(WARのアーカイブはまだサポートされてないらしい)
Q. 独自ドメイン使えるの?
A. 使える。
Q. じゃあすごい良さそうじゃん
A. だから散々そうだっつってんだろボケ!
GAE(がえ)
% tree hellogaej
hellogaej
|-- build.xml
|-- html
|-- src
| |-- META-INF
| |-- WEB-INF
| `-- hellogaej
| `-- HelloGAEJServlet.java
`-- war
`-- WEB-INF
|-- appengine-web.xml
|-- classes
|-- lib
`-- web.xml
% vi hellogaej/src/hellogaej/HelloGAEJServlet.java
package hellogaej;
import java.io.IOException;
import javax.servlet.http.*;
public class HelloGAEJServlet extends HttpServlet {
public void doGet(HttpServletRequest req, HttpServletResponse resp)
throws IOException {
resp.setContentType("text/plain");
resp.getWriter().println("Hello, GAEj!");
}
}
% vi hellogaej/war/WEB-INF/web.xml
<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version="2.5">
<display-name>Hello Google App Engine for Java</display-name>
<servlet>
<servlet-name>hellogaej</servlet-name>
<servlet-class>hellogaej.HelloGAEJServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>hellogaej</servlet-name>
<url-pattern>/hellogaej</url-pattern>
</servlet-mapping>
</web-app>
GAEj固有の設定ファイル。アプリ名やバージョンを書くそうです。
% vi hellogaej/war/WEB-INF/appengine-web.xml
<appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
<application>hellogaej</application>
<version>1</version>
</appengine-web-app>
App Engine SDKに含まれているdev_appserver.shを使って開発サーバーを起動できる。${appengine.sdk}/config/user/ant-macros.xmlに便利なantタスクがあるのでそれを利用するとなお便利。
% vi hellogaej/build.xml
<project name="hellogaej" default="war">
<property name="appengine.sdk" location="/usr/local/appengine-java-sdk-1.2.6"/> <fail message="Please define the appengine.sdk property to point to your SDK directory">
<condition>
<not> <and>
<isset property="appengine.sdk"/>
<available file="${appengine.sdk}/config/user/ant-macros.xml"/>
</and> </not>
</condition>
</fail>
<import file="${appengine.sdk}/config/user/ant-macros.xml"/>
<property name="debug.port" value="5005"/>
<property name="http.port" value="8080"/>
<property name="log.file" value="app.log"/>
<property name="log.days" value="2"/>
<property name="war.dir" location="war"/>
<target name="war" depends="enhance"
description="Assemble the application directory">
<mkdir dir="${war.dir}/WEB-INF"/>
<copy todir="${war.dir}">
<fileset dir="html">
<exclude name="**/.svn/**"/>
<exclude name="**/*~"/>
</fileset>
</copy>
<copy todir="${war.dir}/WEB-INF">
<fileset dir="src/WEB-INF">
<include name="*.xml"/>
</fileset>
</copy>
<enhance_war war="${war.dir}"/>
</target>
<target name="enhance" depends="compile"
description="Enhance the classes after compilation">
<enhance_war war="${war.dir}"/>
</target>
<target name="compile"
description="Compile the application servlet code">
<mkdir dir="${war.dir}/WEB-INF/classes"/>
<mkdir dir="${war.dir}/WEB-INF/lib"/>
<javac srcdir="src" destdir="${war.dir}/WEB-INF/classes">
<classpath>
<fileset dir="${appengine.sdk}/lib/user">
<include name="*.jar"/>
</fileset>
<fileset dir="${appengine.sdk}/lib/shared">
<include name="*.jar"/>
</fileset>
</classpath>
</javac>
</target>
<target name="clean"
description="Force a clean slate to rebuild">
<delete dir="${war.dir}"/>
</target>
<target name="runserver" depends="war"
description="Run the dev_appserver">
<dev_appserver war="${war.dir}" port="${http.port}"/>
</target>
<target name="dev_appserver" depends="runserver"/>
<target name="debug" depends="war"
description="Launches dev_appserver with remote debugging enabled">
<echo message="Launching dev_appserver on Web port ${http.port}, Java remote debug port ${debug.port}"/>
<dev_appserver war="${war.dir}" port="${http.port}">
<options>
<arg value="--jvm_flag=-Xdebug"/>
<arg value="--jvm_flag=-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=${debug.port}"/>
</options>
</dev_appserver>
</target>
<target name="update" depends="war"
description="Uploads the application, including indexes">
<appcfg action="update" war="${war.dir}"/>
</target>
<target name="update_indexes" depends="war"
description="Uploads only the application's indexes">
<appcfg action="update_indexes" war="${war.dir}"/>
</target>
<target name="rollback" depends="war"
description="Rolls back any in-progress application update">
<appcfg action="rollback" war="${war.dir}"/>
</target>
<target name="request_logs"
description="Downloads the application's logs">
<appcfg action="request_logs" war="${war.dir}">
<options>
<arg value="--num_days=${log.days}"/>
</options>
<args>
<arg value="${log.file}"/>
</args>
</appcfg>
</target>
</project>
% ant dev_appserver

面倒臭くて死にそうでしたが、どの言語もJREとServlet上で動くので知っとかないとと思って。