Python2.7でGAEの基本的なコードを書いてみました

いつの間にかGoogleのサイトにPython2.7向けのGoogle App Engineチュートリアルができていたので改めて最初から読んでみました。
以前Google app engineと文字コードという記事を書いた際にはPython2.5を使用していたのですがこの時とは少なからず仕様の変更があったようです。

Python2.5を使ったチュートリアルHello Worldの項目では

print 'Content-Type: text/plain'
print ''
print 'Hello, world!'

というprint文をつかってHTTPヘッダや本文を出力する例が示されているのですがPython2.7のチュートリアル内のHello world項目ではいきなりwebapp2フレームワークを使った例が示されています。

import webapp2

class MainPage(webapp2.RequestHandler):
  def get(self):
      self.response.headers['Content-Type'] = 'text/plain'
      self.response.out.write('Hello, webapp World!')

app = webapp2.WSGIApplication([('/', MainPage)],
                              debug=True)

print文を使って標準出力から出力する方法は使えなくなったのかな、と思ったのですがそういうわけではなくこれは(アプリ自体の)スレッドセーフのための処理と関係があるようです。
GAEの設定ファイルであるapp.yamlにはPython2.7を使う場合threadsafeという項目が追加されており、チュートリアルではいきなりこれをtrueに設定した前提で話が進められるためprint文を使う書き方が飛ばされてしまったようです。
チュートリアルのapp.yamlのthreadsafeの項目をfalseにし、scriptの項目の拡張子を.appから.pyに変更するとPython2.5使用時と同様にprint文を使って書くことができます。

#app.yaml
application: helloworld
version: 1
runtime: python27
api_version: 1
threadsafe: false # ←falseにして

handlers:
- url: /.*
  script: helloworld.py # ←拡張子を.pyに

こうすれば下のように書ける。

#helloworld.py
print 'Content-Type: text/plain'
print ''
print 'Hello, world!'

逆に言うとthreadsafeを有効にした場合は上のようにprint文をつかって直接標準出力へ書き出すことはできないようです。

上にも書いたようにPython2.7のチュートリアルはthreadsafe:trueを前提に書かれているので私もそれに倣って書くことにします。
手始めにhttps://developers.google.com/appengine/docs/python/gettingstartedpython27/handlingforms?hl=jaのサンプルコードにヘッダでの文字コード指定などの改変を加えて、入力された文字列を次の画面で表示するコードを書いてみました。

# coding: utf-8

import cgi
import webapp2


class MainPage(webapp2.RequestHandler):
    def get(self):
        self.response.headers["Content-Type"] = "text/html; charset=utf-8"
        self.response.out.write("""
                                <html>
                                  <head>
                                    <title>
                                      入力画面
                                    </title>
                                  <head>
                                  <body>
                                    <form action="/result" method="post">
                                      <textarea name="testText">
                                      </textarea>
                                      <br>
                                      <input type="submit">
                                    </form>
                                  </body>
                                </html>
                                """)


class ResultPage(webapp2.RequestHandler):
    def post(self):
        self.response.headers["Content-Type"] = "text/html; charset=utf-8"
        self.response.out.write("""
                                <html>
                                  <head>
                                    <title>
                                      表示画面
                                    </title>
                                  <head>
                                  <body>
                                    入力されたのは
                                """)
        self.response.out.write(cgi.escape(self.request.get("testText")))
        self.response.out.write("""です。
                                  </body>
                                </html>
                                """
                                )

app = webapp2.WSGIApplication([("/", MainPage),
                               ("/result", ResultPage)],
                              debug=True)

このようにappという変数で応答するurlと対応するクラスの組み合わせを指定し、app.yamlで拡張子を.appにしておけばthreadsafeに実行してくれるようです。(この場合拡張子という言い方は適切でないかもしれませんが)