2008/04/24

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で文字列として返す様になっています。
動くコードとしては以下の様になります。
#!-*- coding:utf-8 -*-
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を...
いけないチェリー・パイ いけないチェリー・パイ
ウォレント
Sony Music Direct CD / ¥1,575 (2004年07月22日)
 
発送可能時間:

Posted at 20:00 | WriteBacks () | Edit
Edit this entry...

wikieditish message: Ready to edit this entry.






















A quick preview will be rendered here when you click "Preview" button.