みなさん、GoogleAppEngine (GAE) で開発をしてますか?
僕も最近 Python をよく使うようになったので、GAE 用のアプリをいくつか作っています。
Python の開発環境を作る際は buildout を使うと非常に便利です。
必要なeggパッケージのインストールや svn からのチェックアウト、Apache/MySQL のセットアップなどの作業を
設定に基づいて自動的に行ってくれます。
GAE 用のアプリを作る際の設定は @shimizukawa の?Google App Engine の開発をbuildoutで行う?に細かく書いてあります。
しかし、この設定では私の環境ではそのままでは動かなくてハマってしまいました。
この設定で利用している appfy.recipe.gae:app_lib というレシピは、
指定したライブラリをGAEで利用しやすいようZIP ファイルにまとめる仕組みを提供しているのですが、
この「指定したライブラリ」が開発環境に既にインストールされていると ZIP ファイルには含まれなくなります。
そのため、ローカル環境で動作確認すると正しく動くのですが GAE 上ではライブラリが足りずにちゃんと動作しません。
これを防ぐために allowed-eggs-from-site-packages というオプションを用います。
allowed-eggs-from-site-packages は名前の通り、ローカルの site-packages の中から利用して良いパッケージを指定するものです。
このオプションを使って、ZIP ファイルに必要な全てのパッケージを含めるようにします。
※ appfy.recipe.gae のドキュメントには載っていないオプションですが、
ベースにしている zc.recipe.egg.Scripts (がベースにしている z3c.recipe.scripts) が提供している機能です。
最終的に設定を加えた buildout.cfg はこうなります。
※ flask 用の初期設定も含めるようにしました。
[buildout]parts = prepare debug app_lib gae_sdk gae_tools test[prepare]recipe = iw.recipe.cmd:pyon_install = truecmds =>>> buildout_dir = buildout.get('directory', '.')>>> path = os.path.join(buildout_dir, 'app')>>> if not os.path.exists(path):... os.makedirs(os.path.join(buildout_dir, 'app'))... open(os.path.join(path, 'app.yaml'), 'at').write(... 'application: appname\n'... 'version: 1\n'... 'runtime: python\n'... 'api_version: 1\n'... 'handlers:\n'... '- url: /remote_api\n'... ' script: $PYTHON_LIB/google/appengine/ext/remote_api/handler.py\n'... ' login: admin\n'... '- url: .*\n'... ' script: main.py\n'... )... open(os.path.join(path, 'main.py'), 'at').write(... """# -*- coding: utf-8 -*-\n"""... """\n"""... """import sys; sys.path.insert(0, './distlib.zip')\n"""... """from google.appengine.ext.webapp.util import run_wsgi_app\n"""... """import werkzeug\n"""... """from flask import Flask\n"""... """app = Flask(__name__)\n"""... """\n"""... """@app.route('/')\n"""... """def index():\n"""... """ return 'hello world'\n"""... """\n"""... """if __name__ == '__main__':\n"""... """ run_wsgi_app(app)\n"""... )[debug]recipe = zc.recipe.egg:scripteggs = ipythonextra-paths =${gae_tools:extra-paths}${gae_tools:sdk-directory}/lib/django${gae_tools:sdk-directory}/lib/webob${gae_tools:sdk-directory}/lib/yaml/lib${buildout:directory}/appinterpreter = py[app_lib]recipe = appfy.recipe.gae:app_liblib-directory = app/distlibuse-zipimport = trueallowed-eggs-from-site-packages =.eggs =flaskignore-globs =*.c*.pyc*.pyo*/test*/tests*/testsuite*/django*/sqlalchemysimplejson/_speedups.pyignore-packages =distributesetuptoolseasy_installsitepkg_resources[gae_sdk]recipe = appfy.recipe.gae:sdkurl = http://googleappengine.googlecode.com/files/google_appengine_1.4.0.zipclear-destination = true
[gae_tools]recipe = appfy.recipe.gae:toolssdk-directory = ${gae_sdk:destination}/google_appengineextra-paths =app/libapp/distlib.zipapp[test]recipe = pbp.recipe.noserunnereggs =${app_lib:eggs}nosenosegaeextra-paths = ${debug:extra-paths}environment = nose-environmentdefaults = --gae-application=${buildout:directory}/app[nose-environment]NOSE_WITH_GAE = trueNOSE_WHERE = ${buildout:directory}/app


上記のbuildout.cfgでアプリを生成すると、最初のアクセスでwerkzeug.abortをimport出来ない問題が発生する可能性があります。flaskの前に以下のimportを追加してください。
import werkzeug
from flask import Flask
あわせて読みたい: http://www.freia.jp/taka/docs/pyhack4/
コメントありがとうございます。
本文を修正しておきました。