Date: 2009-08-09
Tags: python, programming, web

buildoutで開発5: ファイル構成の整理とpaster-template対応

buildoutで開発4: mod_wsgiからegg指定でアプリ起動する 、というところまで開発してくると、開発に使っていたディレクトリの直下が、buildoutで自動生成されるDIRや、egg-infoなどでごちゃごちゃしてきたので、整理する。

ファイル・ディレクトリの再配置

現状のファイル構成(コミット分のみ):

c:\Project\buildout\env1\
 +-- wsgiapp
     +-- bootstrap.py
     +-- buildout.cfg
     +-- setup.cfg
     +-- setup.py
     +-- wsgi.ini
     +-- wsgiapp/
         +-- __init__.py
         +-- scraper.py
         +-- startup.py
         +-- tests.py

これを以下のようにしたい。

新しいファイル構成(コミット分のみ):

c:\Project\buildout\env1\
 +-- wsgiapp
     +-- bootstrap.py
     +-- buildout.cfg
     +-- setup.cfg
     +-- setup.py
     +-- src/
         +-- wsgi.ini
         +-- wsgiapp/
             +-- __init__.py
             +-- scraper.py
             +-- startup.py
             +-- tests.py

buildoutで開発4: mod_wsgiからegg指定でアプリ起動する でインストールして使った部分は上記のsrcディレクトリに移動した部分だけなので、実際に配布するものだけを切り分けた感じ。実際に配布するもの、というのは python setup.py bdist_egg で作られるeggの中身に相当する。

ソースコードの配置に合わせてsetup.pyを書き換える。

setup.py(diff差分):

@@ -16,3 +16,4 @@
       license='ZPL',
-      packages=find_packages(exclude=['ez_setup', 'examples', 'tests']),
+      packages=find_packages('src'),
+      package_dir={'': 'src'},
       include_package_data=True,

packagesの検索位置をsrcディレクトリにして、src以下には配布に必要なものしか置かないことにするので、find_packages()のexclude指定は不要になった。また、distutilsにパッケージ位置を教えるためpackage_dirの指定も追加。(find_packages()とpackage_dirについて、詳しくは [Python] setuptools - SumiTomohikoの日記 (2007-06-22) または原文 Building and Distributing Packages with setuptools を参照)

eggを作成して中身を確認。

bdist_egg

> python setup.py bdist_egg
> ls dist
wsgiapp-0.1dev_r10-py2.4.egg

distディレクトリに wsgiapp-0.1dev_r10-py2.4.egg が出来ている。拡張子eggのファイルは実はzipファイルなので、拡張子をzipに変える等で中身を見ることが出来る。中身に問題がなければOK。

wsgi.ini, wsgi.py をPasteで作成する

既にコミットしているwsgi.iniやwsgi.pyを配布物に含めたい。含めたいけど、 前回(buildoutで開発4) のようにeasy_installでパッケージとしてインストールする事を考えると、iniのような設定ファイルをwsgiappのパッケージ本体のフォルダに入れて配布するのは微妙。

今回はpasterコマンドで設定ファイルを作れるようにしてみる。参照: Paste Script: Development — Paste Script v1.7 documentation

まず、setup.pyにtemplate対応を書く。

setup.py(diff差分):

@@ -20,9 +20,14 @@
       zip_safe=False,
       install_requires=[
           'BeautifulSoup',
+          'PasteDeploy',
+          'PasteScript',
       ],
       entry_points="""
       [paste.app_factory]
       main = wsgiapp.startup:application_factory
+
+      [paste.paster_create_template]
+      wsgiapp_ini = wsgiapp.paster_templates:WSGIAppTemplate
       """,
       )

まずはinstall_requiresを更新。 前回(buildoutで開発4) で手動で入れたPasteDeployと、今回template生成に使用することになるPasteScriptを追加する。

次にpaste用のtemplate登録コマンドをentry_pointsに追加する。 wsgiapp_ini はテンプレート名で、 wsgiapp.paster_templates:WSGIAppTemplate は今から作成するパッケージ名。

テンプレート作成方法を実装するプログラム src/wsgiapp/paster_templates.py を以下のように作成する。

src/wsgiapp/paster_templates.py:

from paste.script.templates import Template, var

class WSGIAppTemplate(Template):
    summary = 'Template for creating a deploy setting files (include wsgi.ini).'
    _template_dir = 'paster-template'
    vars = [
        var('host', 'The host to serve on', '127.0.0.1'),
        var('port', 'The port to serve on', '8080'),
    ]

最後に、上記で _template_dir に指定したディレクトリを作成し、テンプレートファイルを追加する。ということで、src/wsgiapp/paster-templateディレクトリにwsgi.ini_tmplとwsgi.pyを置いた。ここで、wsgi.iniの後ろに _tmpl と付けているが、こうすると上記のプログラムで定義した変数(host, port)で文字列を置き換えて、ファイルを配置してくれる。

wsgi.ini_tmpl:

[app:main]
use = egg:wsgiapp

[server:main]
use = egg:Paste#http
host = ${host}
port = ${port}

最後に動作確認。

paster create

> cd c:Projectbuildoutenv1wsgiapp
> buildout
...

> cd /tmp
> paster create --list-templates
Available templates:
basic_package: A basic setuptools-enabled package
paste_deploy: A web application deployed through paste.deploy
wsgiapp_ini: Template for creating a deploy setting files (include wsgi.ini).

> paster create -t wsgiapp_ini deploy
Selected and implied templates:
wsgiapp#wsgiapp_ini Template for creating a deploy setting files (include wsgi.ini).

Variables:
egg: deploy
package: deploy
project: deploy
Enter host (The host to serve on) ['127.0.0.1']:
Enter port (The port to serve on) ['8080']: 8180
Creating template wsgiapp_ini
Creating directory .deploy
Copying wsgi.ini_tmpl to .deploywsgi.ini
Copying wsgi.py to .deploywsgi.py

これでdeployというディレクトリが出来ていて、中にwsgi.iniとwsgi.pyがあればOK。今までのように起動もOKだし、mod_wsgiからの起動スクリプトにも指定可能になった。

paster serve

> paster serve deploy/wsgi.ini
Starting server in PID 9140.

paster-template をeggに含める

ところで、今の状態で python setup.py bdist_egg しても、pythonパッケージとして認識されないpaster-templateディレクトリはeggに含まれない。これが含まれるようにするため、setup.pyを以下のように修正する。

@@ -18,2 +18,3 @@
       package_dir={'': 'src'},
+      package_data = {'': ['paster-template/*.*']},
       include_package_data=True,

これでeggにpaster-template以下も含まれるようになった。他にも.txtとか.gifとか含めたかったら、package_dataの[]部分に追加すればよい。

(じゃあinclude_package_data=Trueって何なの?ディレクトリが増えたらsetup.pyを書き換えなきゃいけないの?と、疑問は残る...)

まとめ

最終的なファイル構成(コミット分のみ):

c:\Project\buildout\env1\
 +-- wsgiapp
     +-- bootstrap.py
     +-- buildout.cfg
     +-- setup.cfg
     +-- setup.py
     +-- src/
         +-- wsgiapp/
             +-- __init__.py
             +-- paster_template.py
             +-- scraper.py
             +-- startup.py
             +-- tests.py
             +-- paster-template
                 +-- wsgi.ini_tmpl
                 +-- wsgi.py

そういえば今までソースコードを付けてなかった。添付します。