PyTenjinを使ったサンプル

bonlifeです。id:yatt:20080127:1201410589 を見て、HTMLを出力するならテンプレートエンジン!ということで高速テンプレートエンジンと名高いTenjin(PyTenjin)を使ってみました。(string.Templateでも良さそうな気もしますが、なんとなく。) 調子に乗って、最後にはPyYAMLも使ってみましたよ。

  • todo_tenjin_01.py
#! /usr/bin/env python
# -*- coding: utf-8 -*-

import tenjin
from tenjin.helpers import *

context = {
    "title":"todo",
    "todolists":[
        {"todo": ["write program","submit bug report"]},
        {"hobby":["bbb","plan RC"]},
        {"else":["hogehoge"]},
    ]
}

tmpl_filename = "todo.pyhtml"

engine = tenjin.Engine()
output = engine.render(tmpl_filename, context)
print output
  • todo.pyhtml
<html>
<head>
  <title>${title}</title>
</head>
<body>
<?py for genre in todolists: ?>
<h2>${genre.keys()[0]}</h2>
    <ul>
    <?py for item in genre.values()[0]: ?>
        <li>${item}</li>
    <?py #end ?>
    </ul>
<?py #end ?>
</body>
</html>

テンプレートが汚い。dict.keys()[0] とか dict.values()[0] がカコワルイ気がする…orz インデントをミスって何度かエラーになったのは秘密。

  • 結果
<html>
<head>
  <title>todo</title>
</head>
<body>
<h2>todo</h2>
    <ul>
        <li>write program</li>
        <li>submit bug report</li>
    </ul>
<h2>hobby</h2>
    <ul>
        <li>bbb</li>
        <li>plan RC</li>
    </ul>
<h2>else</h2>
    <ul>
        <li>hogehoge</li>
    </ul>
</body>
</html>

想定通り。続いて、少しだけ修正。

  • todo_tenjin_02.py
#! /usr/bin/env python
# -*- coding: utf-8 -*-

import tenjin
from tenjin.helpers import *

context = {
    "title":"todo",
    "todolists":[
        {"todo": ["write program","submit bug report"]},
        {"hobby":["bbb","plan RC"]},
        {"else":["hogehoge"]},
    ]
}

tmpl_filename = "todo.pyhtml"

template = tenjin.Template(tmpl_filename)
output = template.render(context)
print output

01との違いは最後の方のみ。engine を生成するやり方から template を生成するやり方に変更。いくらかスッキリしたような、変わらないような。
続いて、Pythonスクリプトもテンプレートも両方とも変えてみる。

  • todo_tenjin_03.py
#! /usr/bin/env python
# -*- coding: utf-8 -*-

import tenjin
from tenjin.helpers import *

context = {
    "title":"todo",
    "todolists":{
        "todo": ["write program","submit bug report"],
        "hobby":["bbb","plan RC"],
        "else":["hogehoge"],
    }
}

tmpl_filename = "todo_03.pyhtml"

template = tenjin.Template(tmpl_filename)
output = template.render(context)
print output
  • todo_03.pyhtml
<html>
<head>
  <title>${title}</title>
</head>
<body>
<?py for key, value in todolists.iteritems(): ?>
<h2>${key}</h2>
    <ul>
    <?py for item in value: ?>
        <li>${item}</li>
    <?py #end ?>
    </ul>
<?py #end ?>
</ul>
</body>
</html>
  • 結果
<html>
<head>
  <title>todo</title>
</head>
<body>
<h2>hobby</h2>
    <ul>
        <li>bbb</li>
        <li>plan RC</li>
    </ul>
<h2>todo</h2>
    <ul>
        <li>write program</li>
        <li>submit bug report</li>
    </ul>
<h2>else</h2>
    <ul>
        <li>hogehoge</li>
    </ul>
</ul>
</body>
</html>

todolistを辞書のリストからただの辞書に変更。(もはやtododict…。) テンプレートが結構スッキリ。ただ、出力順序が…orz そりゃあ、辞書だから順序は保証されないのは当然。
ということで、苦し紛れの数値PREFIX付き。

  • todo_tenjin_04.py
#! /usr/bin/env python
# -*- coding: utf-8 -*-

import tenjin
from tenjin.helpers import *

context = {
    "title":"todo",
    "todolists":{
        "01 todo": ["write program","submit bug report"],
        "02 hobby":["bbb","plan RC"],
        "03 else":["hogehoge"],
    }
}

tmpl_filename = "todo_04.pyhtml"

template = tenjin.Template(tmpl_filename)
output = template.render(context)
print output
  • todo_04.pyhtml
<html>
<head>
  <title>${title}</title>
</head>
<body>
<?py for key, value in sorted(todolists.iteritems()): ?>
<h2>${key}</h2>
    <ul>
    <?py for item in value: ?>
        <li>${item}</li>
    <?py #end ?>
    </ul>
<?py #end ?>
</ul>
</body>
</html>
  • 結果
<html>
<head>
  <title>todo</title>
</head>
<body>
<h2>01 todo</h2>
    <ul>
        <li>write program</li>
        <li>submit bug report</li>
    </ul>
<h2>02 hobby</h2>
    <ul>
        <li>bbb</li>
        <li>plan RC</li>
    </ul>
<h2>03 else</h2>
    <ul>
        <li>hogehoge</li>
    </ul>
</ul>
</body>
</html>

うーん、無理無理感が強い…。強過ぐる。なんだかんだで02ぐらいが妥当かな。
最後に02をベースにデータも別ファイル(YAML)に分離。

  • todo_tenjin_05.py
#! /usr/bin/env python
# -*- coding: utf-8 -*-

import tenjin
from tenjin.helpers import *
import yaml

tmpl_filename = "todo.pyhtml"
yaml_filename = "data.yaml"

template = tenjin.Template(tmpl_filename)
output = template.render(yaml.load(open(yaml_filename).read()))
print output
title: todo
todolists:
    - todo:
        - write program
        - submit bug report
    - hobby:
        - make figure
        - plan RC
    - else:
        - hogehoge

YAMLではタブが使えないのに気付かず、イミフなエラーに悩まされたりしましたが、なかなかスッキリしてきたんじゃないかしら。"import pyyaml"とかしてミスってたのは過去の私。出力結果は、01や02と同じ。とりあえず、この中では 05 が一番カコ良さげ!たぶん、もっとスッキリしていてスマートなやり方があるはずなので、Pythonistaの皆さん、よろしくです。
ちなみに、PyTenjin はぱいぱいに上がってないので、SourceForgeから pyTenjin-0.6.1.tar.gz をダウンロード、展開、フォルダ移動して、"python setup.py install" ですよ。面倒! PyYAML は easy_install でインストールできますのでご安心あれ。