Cookiecutter は Python で実装されたプロジェクトのテンプレートを作るためのツール。 似たようなツールだと JavaScript の Yeoman とか、Python だと他にも Paste Script なんかがある。 Python で実装されているとは言ってもテンプレートを作る・使うところまでなら Python が書けなくても問題ない。
今回使う環境は Mac OS X にした。
$ sw_vers ProductName: Mac OS X ProductVersion: 10.11.2 BuildVersion: 15C50
インストールする
Python のパッケージマネージャの pip を使ってインストールする。
$ pip install cookiecutter
とりあえず使ってみる
いくつかサンプルのテンプレートがあるので、それを使ってプロジェクトを作ってみよう。
ここで紹介するテンプレートは Python のパッケージを作るときに使われるもの。 Git でリポジトリをクローンしてこよう。
$ git clone https://github.com/audreyr/cookiecutter-pypackage.git
cookiecutter コマンドを使って先ほどクローンしてきたディレクトリを指定しよう。 すると、テンプレートで変数になっている部分に何を入れるか次々に聞かれる。 変数にはデフォルト値が設定されているので、ひとまず今はエンターキーを連打しているだけでも構わない。
$ cookiecutter cookiecutter-pypackage full_name [Audrey Roy Greenfeld]: email [aroy@alum.mit.edu]: github_username [audreyr]: project_name [Python Boilerplate]: project_slug [python_boilerplate]: project_short_description [Python Boilerplate contains all the boilerplate you need to create a Python package.]: release_date [2015-12-13]: pypi_username [audreyr]: year [2015]: version [0.1.0]: use_pypi_deployment_with_travis [y]:
コマンドの実行が終わると、次のようなディレクトリツリーができあがった。 いくつかのファイル名には先ほど入力した変数の値が使われていることも分かる。
$ tree python_boilerplate python_boilerplate ├── AUTHORS.rst ├── CONTRIBUTING.rst ├── HISTORY.rst ├── LICENSE ├── MANIFEST.in ├── Makefile ├── README.rst ├── docs │ ├── Makefile │ ├── authors.rst │ ├── conf.py │ ├── contributing.rst │ ├── history.rst │ ├── index.rst │ ├── installation.rst │ ├── make.bat │ ├── readme.rst │ └── usage.rst ├── python_boilerplate │ ├── __init__.py │ └── python_boilerplate.py ├── requirements_dev.txt ├── setup.cfg ├── setup.py ├── tests │ ├── __init__.py │ └── test_python_boilerplate.py ├── tox.ini └── travis_pypi_setup.py 3 directories, 26 files
テンプレートを自作する
大体の使い方がつかめたので、次はテンプレートを自作してみることにしよう。 まずは、ごくごくシンプルな Python パッケージを作ってみることにする。
テンプレートは example というディレクトリの中に作ることにする。 まずは example ディレクトリを作って、その中にさらに二重の波括弧で囲まれた名前をもったディレクトリを作る。 二重の波括弧で囲まれて cookiecutter. から始まる名前を持ったファイルは Cookiecutter で置換対象になる。 cookiecutter. に続く名前が先ほど入力した変数名になる。
$ mkdir -p example/{{cookiecutter.package_name}}
作るのが Python のパッケージのつもりなので、ディレクトリの中に init.py モジュールも用意しておく。
$ touch example/{{cookiecutter.package_name}}/__init__.py
次に example ディレクトリの中に cookiecutter.json という名前のファイルを用意しよう。 ここで変数名と、それに対応するデフォルト値を定義する。
$ cat << 'EOF' > example/cookiecutter.json { "package_name": "helloworld" } EOF
作ったテンプレートを使ってみる
これで Cookiecutter 用のテンプレートの準備ができた。 cookiecutter コマンドで作成したテンプレートである example ディレクトリを指定しよう。 すると先ほどと同じように変数名について聞かれる。
$ cookiecutter example package_name [helloworld]:
コマンドの実行がおわると先ほど入力した変数名でディレクトリが作られる。
$ tree helloworld helloworld └── __init__.py 0 directories, 1 file
ばっちりだ。
ファイルの中身を置換する
先ほどの例ではディレクトリ名が入力した変数で置換された。 次はファイルの中身も置換されることを確認しておこう。
先ほどの example テンプレートに新しい Python モジュール (のテンプレート) を追加する。 その中にファイル名と同様、二重の波括弧で囲まれて cookiecutter. から始まる変数を埋め込んでおく。 変数の名前は cookiecutter.message にした。
$ cat << 'EOF' > example/{{cookiecutter.package_name}}/introduction.py # -*- coding: utf-8 -*- def greet(): msg = '{{ cookiecutter.message }}' print(msg) if __name__ == '__main__': main() EOF
変数が追加されたので、それを定義する設定ファイルも更新しておく。
$ cat << 'EOF' > example/cookiecutter.json { "package_name": "helloworld", "message": "Hello, World!" } EOF
再度 cookiecutter コマンドを実行しよう。 追加した変数について質問が増えている。
$ cookiecutter example package_name [helloworld]: helloworld2 message [Hello, World!]:
追加されたファイルもちゃんと展開されていることがわかる。
$ tree helloworld2 helloworld2 ├── __init__.py └── introduction.py 0 directories, 2 files
ファイルの中身を確認すると、ちゃんと変数が先ほど入力した値で置換されている。
$ cat helloworld2/introduction.py # -*- coding: utf-8 -*- def greet(): msg = 'Hello, World!' print(msg) if __name__ == '__main__': main()
Python パッケージに組み込んで使う
ちょっと特殊な使い方だけど Python パッケージにテンプレートを組み込んで使うやり方も紹介しておく。
まずはパッケージをインストールするためのセットアップスクリプトを用意する。 パッケージ名は mycutter にする。 console_scripts に登録した cutter コマンドでテンプレートを展開できるようにすることを意図してる。
$ cat << 'EOF' > setup.py #!/usr/bin/env python # -*- coding: utf-8 -*- from setuptools import setup from setuptools import find_packages def main(): description = 'mycutter' setup( name='mycutter', version='0.0.1', author='example', author_email='example@example.jp', url='www.example.jp', description=description, long_description=description, zip_safe=False, include_package_data=True, packages=find_packages(), install_requires=['cookiecutter>=1.3.0'], tests_require=[], setup_requires=[], entry_points={ 'console_scripts': [ 'cutter = mycutter:main', ], } ) if __name__ == '__main__': main() EOF
パッケージを作っていく。 mycutter パッケージにテンプレートを展開するモジュールを用意する。 Python から Cookiecutter を使うときは cookiecutter.main.cookiecutter() 関数にテンプレートのディレクトリを指定すれば良い。 テンプレートはこれからパッケージ内に作るけど、それは setuptools の pkg_resources.resource_filename() 関数で取得する。
$ mkdir mycutter $ cat << 'EOF' > mycutter/__init__.py #!/usr/bin/env python # -*- coding: utf-8 -*- import pkg_resources from cookiecutter.main import cookiecutter def main(): template_directory = pkg_resources.resource_filename('mycutter', 'template') cookiecutter(template_directory) if __name__ == '__main__': main() EOF
テンプレートのデータファイルをパッケージに含めるために MANIFEST.in ファイルも用意しよう。
$ cat << 'EOF' > MANIFEST.in recursive-include mycutter/template * EOF
mycutter パッケージの中に template ディレクトリを用意して、その中に先ほどと同じ要領でテンプレートを作っていく。
$ mkdir -p mycutter/template/{{cookiecutter.package_name}} $ touch mycutter/template/{{cookiecutter.package_name}}/__init__.py $ cat << 'EOF' > mycutter/template/cookiecutter.json { "package_name": "helloworld" } EOF
作った Python パッケージを使う
以上で Cookiecutter を組み込んだ Python パッケージの用意ができた。 セットアップスクリプトを使ってインストールしよう。
$ python setup.py install
これで mycutter パッケージがインストールされた。
$ pip list | grep mycutter mycutter (0.0.1)
mycutter パッケージをインストールすると cutter コマンドが使えるようになる。 このコマンドを実行すると、パッケージ内のテンプレートを元に Cookiecutter が実行される。
$ cutter package_name [helloworld]: helloworld3
実行すると次のようにディレクトリツリーができた。
$ tree helloworld3 helloworld3 ├── __init__.py └── __pycache__ └── __init__.cpython-35.pyc 1 directory, 2 files
めでたしめでたし。