Edited at

PasteScriptのテンプレートエンジンにJinja2を使う

More than 3 years have passed since last update.


PasteScript

PasteScriptは以下の2つの機能を提供するコマンドラインツール.今回話題とするのはpaster createの方.


  • 指定したテンプレート(自作可能)を元に、プロジェクトの雛形を作成する(paster create)


  • PasteDeployにより設定されたWSGIアプリケーション(WSGIサーバ、関連ミドルウェアの設定含む)を起動する(paster serve)

長らくPython3に対応していないのがネックだったが、先月リリースしたPasteScript 2.0によりついにPython3がサポートされた。


paster createコマンド

以下は、同梱されているbasic_packageテンプレートを指定した例である。basic_packageテンプレートはsetup.pyを含んだPythonパッケージプロジェクトを生成する。

$ paster create -t basic_package test

Selected and implied templates:
PasteScript#basic_package A basic setuptools-enabled package

Variables:
egg: test
package: test
project: test
Enter version (Version (like 0.1)) ['']: 0.1
Enter description (One-line description of the package) ['']: test
Enter long_description (Multi-line description (in reST)) ['']: test
Enter keywords (Space-separated keywords/tags) ['']: python
Enter author (Author name) ['']: FGtatsuro
Enter author_email (Author email) ['']:
Enter url (URL of homepage) ['']:
Enter license_name (License name) ['']:
Enter zip_safe (True/False: if the package can be distributed as a .zip file) [False]:
Creating template basic_package
Creating directory ./test
Recursing into +package+
Creating ./test/test/
Copying __init__.py to ./test/test/__init__.py
Recursing into __pycache__
Creating ./test/test/__pycache__/
Copying setup.cfg to ./test/setup.cfg
Copying setup.py_tmpl to ./test/setup.py
Running /Users/tatsuro/.homesick/repos/dotfiles/home/.virtualenvs/flask-boilerplate/bin/python setup.py egg_info
# setup.pyを含むPythonパッケージプロジェクト
$ ls test
setup.cfg setup.py test test.egg-info

指定するテンプレートは自作できる。

詳細については説明しない(ドキュメント参照)がおおまかな流れは以下の通り。


  1. テンプレートを定義するPythonパッケージプロジェクトを作成する。


  2. paste.script.templates.Templateクラスを継承したクラス(以下、カスタムテンプレート)を作成する。

  3. 1のプロジェクトのsetup.pyのエントリポイントから、2で定義したクラスを指定する。


デフォルトで提供されるテンプレートエンジン

雛形生成時に与える引数により、指定したテンプレートのファイル名や内容をカスタマイズできる。

# 対話式に与えた引数が反映されている(ex. version, description)

$ cat test/setup.py
from setuptools import setup, find_packages
import sys, os

version = '0.1'

setup(name='test',
version=version,
description="test",
long_description="""\
test"""
,
classifiers=[], # Get strings from http://pypi.python.org/pypi?%3Aaction=list_classifiers
keywords='python',
author='FGtatsuro',
...
)

この際、内容の書き変えにテンプレートエンジンが用いられる。使用するテンプレートエンジンはドキュメントを見ると以下の通り。


  1. カスタムテンプレートのuse_cheetah属性がTrueの場合、Cheetahが使用される。

  2. それ以外の場合、string.Templateが使用される。


他のテンプレートエンジンを使用する

この2つのどちらかでも悪くはないが、自分の使い慣れているテンプレートエンジンを使ってカスタムテンプレートを作成したいという要求もあるだろう。

個人的には多少使い慣れているJinja2が使いたかった。

カスタムテンプレートのtemplate_renderer属性に一定の条件を満たすstaticメソッドを紐付けることで上記の要望が実現できる。以下はテンプレートエンジンにJinja2を使用した例である。

# https://github.com/FGtatsuro/flask-boilerplate/blob/master/flask_boilerplate/templates.py

class Boilerplate(Template):
_template_dir = 'templates'
summary = 'A boilerplate for Flask project'
required_templates = []
vars = [
var('app_name', 'Flask application name', default=NoDefault),
var('description', 'One-line description of the package'),
var('author', 'Author name'),
var('author_email', 'Author email'),
]
@staticmethod
def template_renderer(body, context, filename=None):
return Jinja2Template(body).render(context)
...

staticメソッドが満たさなければいけない条件は下記の通り。


  • 書き換え対象文字列を第一引数に、書き換えに使用される変数の辞書を第二引数に、置き変え対象のファイル名を第三引数に取る。なおファイル名が必要ないならば、ファイル名のデフォルトはNoneでかまわない。

  • 書き換え後の文字列をreturnする。テンプレートエンジンを使って文字列を書き換えてreturnするだけでOKのケースがほとんどだろう。

今回の例はJinja2だが、上記の条件を満たすことができる、ようは与えられた3つの引数から書き換え後の文字列を生成できるテンプレートエンジンであれば同様に使用できる。

他のエンジンは未確認のため断言できないが、大多数のテンプレートエンジンは大丈夫ではないか。