Displaying posts tagged with

“Python2”

Google App Engine習作: Thumbs.db reader

Google App EngineでWindows XPのThumbs.dbを読み出すWebサービスを作りました。

Thumbs.db reader

アップロードされたThumbs.dbを解析して、サムネイル画像(JPEGファイル)を取り出します。結果はdata:スキームを使ってimgタグで一覧表示するか、zipでまとめて取得するか選べます。アップロードされたファイルはサーバ側には保存されません。

Thumbs.dbの解析にはvinettoというプログラムを改造して使っていますが、GAEの制約によってtype 2という形式のものしか解析できません。

コマンドラインから使用する場合は http://thumbsdbreader.appspot.com/zip というURLに対してPOSTリクエストを送信してください。zipファイルが標準出力に出力されます。

curl -X POST --data-binary @Thumbs.db http://thumbsdbreader.appspot.com/zip > files.zip

Google App EngineでMakoを使う

Google App EngineでテンプレートエンジンMakoを使う方法……といっても、特別なことは何も必要ない。アーカイブを展開してできた mako ディレクトリをアプリケーションディレクトリにコピーすれば使えるようになる。

日本語を使う場合の注意点についてはこちらを参照のこと。GAEではRequestもResponseもDatastoreもUnicodeに対応しているので、あまり神経質にならなくても大丈夫。

コード例

  • テンプレートファイルは views/ ディレクトリに置く
  • デフォルトの拡張子は .html
  • エンコーディングは utf-8 固定

次のようなベースクラスを用意しておく。

from mako.template import Template
from mako.lookup import TemplateLookup
 
class RequestHandler(webapp.RequestHandler):
    viewDir = os.path.join(os.path.dirname(__file__), "views")
    lookup = TemplateLookup(directories=[viewDir], input_encoding='utf-8')
 
    def render(self, view, vars={}, type=".html"):
        tmpl = self.lookup.get_template(view + type)
        return tmpl.render_unicode(**vars)
 
    def display(self, *args, **named):
        self.response.out.write(self.render(*args, **named))

サブクラスでは display または render メソッドでレンダリングを行う。

class MainPage(RequestHandler):
    def get(self):
        self.display('index', {"var": "value"})

テンプレートエンジンMakoで日本語を使う

PythonのテンプレートエンジンMakoで日本語を使う方法まとめ。

テスト環境: Python 2.5, Mako-0.3.2

Makoの内部処理はunicodeで行われる。そのため入出力時にエンコーディング指定を正しく行い、テンプレート変数の展開時にunicodeオブジェクトに変換することが必要になる。

入力時

テンプレートファイルが読み込まれる際に、ファイルで使用されている特定のエンコーディング・スキーム(utf-8など)に基づいて、unicode オブジェクトへのデコードが行われる。

最も優先順位の高い指定は、テンプレートファイル先頭行の magic encoding comment である。この一行はテンプレートの内容に含まれないので、HTMLなどに書いても問題ない。

## -*- coding: utf-8 -*-
<p>まこまこ</p>

次に優先されるのは Template コンストラクタにおける input_encoding の指定である。

from mako.template import Template
 
tmpl = Template(filename="view.html", input_encoding="utf-8")

そして最も優先順位が低く、広範囲に適用されるのが TemplateLookup のコンストラクタにおける input_encoding の指定である。実際のアプリケーションで最も良く使われるのがこれだと思われる。

from mako.lookup import TemplateLookup
 
lookup = TemplateLookup(directories=["views/"], input_encoding='utf-8')
tmpl = lookup.get_template("index.html")

出力時

render メソッドを使ってレンダリング結果を取り出す際に、Mako内部の unicode オブジェクトが str オブジェクトにエンコードされる。このとき使用されるエンコーディングは Template または TemplateLookup の output_encoding で指定できる。

## coding: utf-8
from mako.template import Template
 
tmpl = Template(u"まこまこ", input_encoding="utf-8", output_encoding="utf-8")
out = tmpl.render()
print len(out)  # => 12
print type(out) # => <type 'str'>

しかし render_unicode メソッドを使えば unicode オブジェクトをそのまま取り出すことができる。出力先が unicode に対応しているのなら、これをそのまま使うのが最もトラブルが少ないと思う。

tmpl = Template(u"まこまこ", input_encoding="utf-8")
out = tmpl.render_unicode()
print len(out)  # => 4
print type(out) # => <type 'unicode'>

もちろん必要なら取り出したunicodeオブジェクトの encode メソッドを使うこともできる。

tmpl = Template(u"まこまこ", input_encoding="utf-8")
out = tmpl.render_unicode().encode('euc-jp')
print len(out)  # => 8
print type(out) # => <type 'str'>

式展開

テンプレート内の式は自動的に unicode オブジェクトに変換されるため、非ASCII文字を含む可能性のある str オブジェクトを使用する場合は、手動で適切なエンコーディングを指定してデコードしなければならない。

<p>${strobj.decode('utf-8')}</p>

まとめ

  • TemplateLookup の input_encoding で最も一般的なエンコーディングを指定しておく。必要に応じて Template の input_encoding や magic coding comment を使用する。
  • 可能な限り render_unicode を使用する。
  • 非ASCII文字を含む可能性のある str オブジェクトをテンプレート内で使用する場合は、手動でデコードする。

参照