水曜日に Google Appengine 1.4.3 がリリースされました! 1.4.1 と 1.4.2 はブログ記事を書くほど 大きくはなかったのですか、 1.4.3 はまたいろいろ入っているので、ご紹介します。

Prospective Search API

以前、 Matcher API のブログ記事 を書きましたが、 Trusted Tester リリースで出ていた Matcher API は 「Prospective Search API」という名前で開発者全員にリリースされています。 まだ、Labs機能で、正式リリースではない様ですけど、 モジュール名が変わっています。

from google.appengine.api import prospective_search

def add_tweet_alert(user, tweet_text):
    # クエリーはMapper API のクエリー言語を使う
    # 参考: http://code.google.com/p/google-app-engine-samples/wiki/AppEngineMatcherService#Query_Language
    query = 'text:"%s"' % tweet_text

    # 読者IDはユニーク化しないといけないので、user_id と テキストから作る
    subscribe_name = "%s:%s" % (user.user_id(), tweet_text)

    # dict もしくは、 db.Entity オブジェクトで登録すると、スキーマが必須です。
    # 参考: http://code.google.com/p/google-app-engine-samples/wiki/AppEngineMatcherService#Document_Schema
    schema = {
        'str': 'text',
    }

    # dict もしくは、 db.Entity オブジェクトで登録すると、スキーマが必須です。
    # topic はデータスキーマの名前という意味がします。
    topic='Tweet'

    prospective_search.subscribe(dict, query, subscribe_name, schema=schema, topic=topic)

def remove_tweet_alert(user, tweet_text):
    query = 'text:"%s"' % tweet_text
    subscribe_name = "%s:%s" % (user.user_id(), tweet_text)
    topic='Tweet'

    prospective_search.unsubscribe(query, subscribe_name, topic=topic)

matcher というモジュールが、 prospective_search というモジュール名になった意外は、特に大きいな変更はなさそうですね。

Testbed

Testbed はテストを実行できるために、 Appengine 環境を偽装するものです。 開発サーバーみたいに、 Appengine本番にデプロイせずに、ローカル環境で、Memcached、 Datastore などの Appengineのサービスが テストの中に使えます。

import unittest
from google.appengine.ext import testbed

class TestModel(db.Model):
    """A model class used for testing."""
    number = db.IntegerProperty(default=42)
    text = db.StringProperty()

class DemoTestCase(unittest.TestCase):

    def setUp(self):
        # Testbedクラスインスタンスを生成
        self.testbed = testbed.Testbed()

        # Testbed を活性化させる
        self.testbed.activate()
        # 使用するサービススタブを設定する。
        self.testbed.init_datastore_v3_stub()
        self.testbed.init_memcache_stub()

    def tearDown(self):
        # クリーンアップ
        self.testbed.deactivate()

    def testInsertEntity(self):
        """ モデル格納のテスト """
        TestModel().put()
        self.assertEqual(1, len(TestModel.all().fetch(2)))

デフォールト環境変数も設定できます。

class DemoTestCase(unittest.TestCase):
    def setUp(self):
        self.testbed.setup_env(app_id=application-id)
        self.testbed.activate()
        self.testbed.init_datastore_v3_stub()

    # ...

テストを実行するために、テストランナーが必要です。 gaeunit 、もしくは、 nose-gae のテストランナー を使うことが出来ます。 簡単な例は以下のテストランナー。 unittest2 が必要なので、まずそれをインストールする必要があります。

#!/usr/bin/python
import optparse
import sys
# Install the Python unittest2 package before you run this script.
import unittest2

USAGE = """%prog SDK_PATH TEST_PATH
Run unit tests for App Engine apps.

SDK_PATH    Path to the SDK installation
TEST_PATH   Path to package containing test modules"""

def main(sdk_path, test_path):
    sys.path.insert(0, sdk_path)
    import dev_appserver
    dev_appserver.fix_sys_path()
    suite = unittest2.loader.TestLoader().discover(test_path)
    unittest2.TextTestRunner(verbosity=2).run(suite)


if __name__ == '__main__':
    parser = optparse.OptionParser(USAGE)
    options, args = parser.parse_args()
    if len(args) != 2:
        print 'Error: Exactly 2 arguments required.'
        parser.print_help()
        sys.exit(1)
    SDK_PATH = args[0]
    TEST_PATH = args[1]
    main(SDK_PATH, TEST_PATH)

それで、スクリプトを実行すれば、プロジェクトの test*.py でテストケースを探して来て、テストを実行することができます。 モジュール、もしくは、テストクラスを指定することもできます。

$ python testrunner.py demo.tests.DemoTestCase

ファイルAPI

ファイルAPI で Appengine の Blobstore にファイル読み込み、書き込みができます。 レポートの生成、データインポートなど、 ファイルシステムに必要なことに使えます。

from __future__ import with_statement
from google.appengine.api import files

# ファイル作成
file_name = files.blobstore.create(mime_type='application/octet-stream')

# ファイルの中身を書き込む
with files.open(file_name, 'a') as f:
  f.write('data')

# ファイルデータを格納 (flush)
files.finalize(file_name)

# Blob キーを取得
blob_key = files.blobstore.get_blob_key(file_name)

Cron と Task キューのヴァージョン指定

Cron ジョブを実行するアプリケーションバージョンを指定することができるようになりました。 cron.yamltarget プロパティでバージョン名を指定します。

cron:
- description: new daily summary job
  url: /tasks/summary
  schedule: every 24 hours
  target: version-2

キューの定義でも、あるキューのタスクがどのバージョンで実行されるかを queue.yamltarget プロパティで指定できます。

queue:
- name: my-queue
  rate: 20/s
  bucket_size: 40
  max_concurrent_requests: 10
  target: version-2

まとめ

このリリースも結構大きくて、いろいろ改善されています。 ファイルAPIを 早速触ってみたいところです。