Google App Engine上で
web.pyとか
CherryPyとか動かないという報告がいくらかあったのでまとめてみます。
Google App Engineでは、以下で述べられているように「WSGIに対応したCGI(と呼ばれるもの)であれば、フレームワークとして扱えるよ」と言っています。
Using the webapp Framework - Google App Engine - Google Code
The CGI standard is simple, but it would be cumbersome to write all of the code that uses it by hand. Web application frameworks handle these details for you, so you can focus your development efforts on your application's features. Google App Engine supports any framework written in pure Python that speaks CGI (and any WSGI-compliant framework using a CGI adaptor), including Django, CherryPy, Pylons, and web.py. You can bundle a framework of your choosing with your application code by copying its code into your application directory.
http://code.google.com/appengine/docs/gettingstarted/usingwebapp.html
今日はこの動かないと言われている部分を解決して頂ける(かもしれない)ポイントをご紹介。
web.py
まず
web.pyですが、オフィシャルがtarballで配布している物(web.py-0.23.tar.gz)では動きません。最新は
http://webpy.org/bzr/webpy.dev/で配布されており、bzrを使って取得する必要があります(必要であれば
http://bazaar-vcs.org/Downloadからbzrを取得して下さい)。
bzr get http://webpy.org/bzr/webpy.dev/
これまでの1スクリプトからソケットサーバまで起動するweb.pyのコーディング習慣ではそのままでは動きません。
flupを使ってWSGIモジュールを動かす必要があります。以下の様にWSGIハンドラとしてアプリケーションを作成しwsgiref.handlersに起動させます。mod_pythonの場合と同じですかね。
ソースコードの中を覗いた所、Google App Engineに対応するコードが入っています。以前までは一般的なCGIとして「print "Hello World!"」してしまえばそのまま出力されていましたが方式が変った様で、GET等はreturnで文字列として返す様になっています。
動くコードとしては以下の様になります。
import web
urls = (
'/hello/(.*)', 'hello'
)
class hello:
def GET(self, name):
web.header("Content-Type", "text/html; charset=utf-8")
return "Hello World!"
if __name__ == "__main__":
web.application(urls, globals()).cgirun()
但し、「web.pyが内部でimportしているopenid.consumerが無いよ!」と怒られるので
python-openidをいっそ入れてしまうか、以下のパッチを当てる必要があります。
--- web/__init__.py.orig Wed Apr 23 19:12:33 2008
+++ web/__init__.py Wed Apr 23 19:12:35 2008
@@ -26,7 +26,7 @@
from httpserver import *
from debugerror import *
from application import *
-import webopenid as openid
+#import webopenid as openid
try:
import cheetah
まだ開発版の様ですから、今後に期待したいです。
CherryPy
次に
CherryPyですが少し小細工が必要です。Google App EngineではPure Pythonで無いものは動かないのですがCherryPyに含まれるWSGIServer(実際にはSSL機能)がsocket._fileobjectを使ってしまっていてモジュールのインポートに失敗します。以下の様にしてSSL_fileobjectを殺してやる必要があります。
--- cherrypy/wsgiserver/__init__.py.orig Sun Jan 13 17:56:50 2008
+++ cherrypy/wsgiserver/__init__.py Wed Apr 23 16:47:34 2008
@@ -57,11 +57,12 @@
from urllib import unquote
from urlparse import urlparse
-try:
- from OpenSSL import SSL
- from OpenSSL import crypto
-except ImportError:
- SSL = None
+#try:
+# from OpenSSL import SSL
+# from OpenSSL import crypto
+#except ImportError:
+# SSL = None
+SSL = None
import errno
socket_errors_to_ignore = []
@@ -676,19 +677,19 @@
raise socket.timeout("timed out")
return ssl_method_wrapper
-class SSL_fileobject(socket._fileobject):
- """Faux file object attached to a socket object."""
-
- ssl_timeout = 3
- ssl_retry = .01
-
- close = _ssl_wrap_method(socket._fileobject.close)
- flush = _ssl_wrap_method(socket._fileobject.flush)
- write = _ssl_wrap_method(socket._fileobject.write)
- writelines = _ssl_wrap_method(socket._fileobject.writelines)
- read = _ssl_wrap_method(socket._fileobject.read, is_reader=True)
- readline = _ssl_wrap_method(socket._fileobject.readline, is_reader=True)
- readlines = _ssl_wrap_method(socket._fileobject.readlines, is_reader=True)
+#class SSL_fileobject(socket._fileobject):
+# """Faux file object attached to a socket object."""
+#
+# ssl_timeout = 3
+# ssl_retry = .01
+#
+# close = _ssl_wrap_method(socket._fileobject.close)
+# flush = _ssl_wrap_method(socket._fileobject.flush)
+# write = _ssl_wrap_method(socket._fileobject.write)
+# writelines = _ssl_wrap_method(socket._fileobject.writelines)
+# read = _ssl_wrap_method(socket._fileobject.read, is_reader=True)
+# readline = _ssl_wrap_method(socket._fileobject.readline, is_reader=True)
+# readlines = _ssl_wrap_method(socket._fileobject.readlines, is_reader=True)
class HTTPConnection(object):
あとはweb.py同様に
import cherrypy
import wsgiref.handlers
class OnePage(object):
def index(self):
return "one page!"
index.exposed = True
class HelloWorld(object):
onepage = OnePage()
def index(self):
return "hello world"
index.exposed = True
def main():
app = cherrypy.Application(HelloWorld(), "/helloworld")
wsgiref.handlers.CGIHandler().run(app)
if __name__ == '__main__':
main()
とすればGoogle App Engine上でも動きます。上の例にあるCherryPy独特の「/helloworld/onepage」も動きますよ!
これで幾らかのフレームワークが動くようになりました。幾らか敷居が低くなるのではないでしょうか。皆さんも色んなアプリケーションを作ってみませんか。
また時間が出来たら、残る
Pylonsも検証して見たいと思います。
最後に私が好きなCDを...