プラグインの作成方法

将来、プラグインの作成方法が変更するかもしれません

知っておくべきこと

  • Pythonの基本的な書き方

知っておくとうれしいかもしれないこと

  • Twistedの使い方。特にtwisted.internet.defer.Deferred。
  • デコレータ、ジェネレータ、クロージャ

知らなくてもいいこと

  • 日本でのPython人口
  • その他たくさん

クイックスタート

プラグインはPythonプログラムです。特殊な機能を使わない限りhabuに依存しないので単体テストが簡単にできます(ただし、Twistedに深く依存すると単体テストはかんばってね)。また、habuとは関係なく動作させることもできます。

habuの配布物に含まれているhabu/filter/head.pyを例に説明します。次のコードは、head.pyの全文です。

  1. class Head(object):
  2. def __init__(self, config, environ):
  3. self.start = config.get("start", None)
  4. self.end = config.get("end", None)
  5. def execute(self, content):
  6. content["entries"] = content["entries"][self.start:self.end]
  7. return content
  8. def create(config, environ):
  9. return Head(config, environ)

各プラグインモジュールは必ずcreate(config, environ)関数を実装する必要があります。habuがモジュールをロードした後にcreate関数を実行して、インスタンス化します。configはプラグイン固有の設定の辞書です。environはhabuの環境全体にわたる設定情報の辞書です。environは設定ファイルのglobalセクションに対応します。create関数はexecute(content)メソッドを実装したオブジェクトを返します。executeメソッドが定義されたオブジェクトであれば、モジュールでもクラスインスタンスでも構いません。

create関数の名前は変えるかもしれません。
いや、多分もうちょっとかっこいい名前に変えるはず。

Headクラスは通常、コンストラクタにconfig, environを引数に指定した形で実装します。必要に応じてクラスメンバーとして保存します。ここでは、設定のstartとendを保持しています。

プラグインが実行されるときにはexecute(context)メソッドがコールされます。contextは入力データです。contextの詳細は後述します。ここでは、context["entries"]のリストの要素をstartからendまで抽出してcontextのオブジェクトに設定し直しています。返り値は、次のモジュールのexecuteメソッドの引数になります。

executeメソッドの返り値は、contextの辞書かtwisted.internet.defer.Deferredオブジェクト、または、それらのリストです。Deferredオブジェクトを返す場合は、非同期処理でデータを加工してからプラグインのチェーンを再開する場合に使用します。

基本的にはexecuteでcontextのデータを加工して、context自体を返すだけです。

contextのデータ構造

executeメソッドの引き数に渡されるcontextはfeedparserがパースしたオブジェクトです。subscriptionではcontextは通常,Noneです。

contextは辞書です。contextはentriesをキーとしてリストを辞書の要素として持ちます。それ以外の情報は現在のhabuでは無視されます。

context["entries"]にRSSの各エントリが保存されます。各エントリは辞書です。エントリには次のキーと値が設定されています。

キータイプ意味
author文字列作成者(オプション)
author_detail辞書作成者の詳細。
nameにauthorと同じ値。emailとかにメールアドレスが設定されるかも
link文字列エントリへのアクセスするユニークな文字列(URL)
update文字列最終更新日の文字列表記
updated_parsedタプル最終更新日の日時のタプル表記
title文字列エントリのタイトル
summary文字列エントリの本文(description)
summary_detail辞書summaryの詳細の辞書
typeにmimeタイプ,valueにhtmlやtextでの本文など

上記以外のフィールドもありますが,未使用です。上記のフィールド以外にもプラグインが独自にデータを追加できます。

詳細

モジュールの名前とモジュールへのパスは,一意であり、かつ、Python的にvalidでなければなりません。モジュールへのパスに上記以外の制約はありません。識別用にパイプラインの開始はsubscription、RSSの加工はfilter、出力はpublisherを推奨します。

モジュールはhabuが各パイプラインを実行する直前にロードします。モジュールは,habuのプロセス全体でユニークなります。ロード後にモジュールはリロードされることはありません。モジュールは,設定ファイルのmoduleに指定した名前で区別されます。その後,モジュールのcreate関数がコールされて,インスタンス化されます。同一のパイプラインで同じモジュールを複数指定している場合は,指定した数だけインスタンス化されます。インスタンス化されたオブジェクトは,パイプラインの実行期間中生きています。そのあとは,いつ死ぬかはPythonインタープリタに聞いてください。

パイプラインのモジュール(オブジェクト)のチェーンです。通常、一つのパイプラインは一つのチェーンです。executeがリストを返すと、チェーンは複数に分岐して同時並行でその後のそのあとのフィルタ処理を順次実行します。複数に分岐したチェーンはfilter.joinによってまた、一つのチェーンに集約できます。ネットワーク上のデータを取得する場合など、複数のチェーンに分割して、その後のフィルタ処理の実行タイミングをずらすことで、CPUの負荷をおさえることができます。また、データをふるい落とす処理をする場合など、若干メモリ使用量をおさえられます(ほとんど誤差の範囲なので気にしなくてもいいかもしれません)。

Twistedの使い方は、「最新Pythonエクスプローラ 」をご覧ください。