psp モジュールでは、特別なブラケット表記中に Python コードを 埋め込んだテキストドキュメント (HTMLも含みますが、それだけではありません) を変換して、 mod_python ハンドラ内で実行できるような適切な 形式の pure Python コードにします。これにより、ASP や JSP などといった 動的なコンテンツを配信するための融通のきくメカニズムを実現しています。
psp の使っているパーザは (flex で生成した) C で書かれている ため、非常に高速に動作します。
PSP の詳細については6.2 節「PSP ハンドラ」を参照してください。
ドキュメント中の Python のコード (code) は"<%" と "%>"で囲わねばなりません。Python の式 (expression) は"<%=" と "%>" で囲みます。ディレクティブ (directive) は"<%@"と "%>" で囲みます。コメント(処理後のコード中には入りません) は "<%--" と "--%>" で囲います。
コードと式の両方をを HTML ドキュメントに埋め込んでいる 簡単な PSP ページを以下に示します:
<html>
<%
import time
%>
Hello world, the time is: <%=time.strftime("%Y-%m-%d, %H:%M:%S")%>
</html>
内部では、PSP パーザが上のページを以下の Python コードに翻訳します:
req.write("""<html>
""")
import time
req.write("""
Hello world, the time is: """); req.write(str(time.strftime("%Y-%m-%d, %H:%M:%S"))); req.write("""
</html>
""")
このコードをハンドラ内で実行すると、"Hello world, the time is:" の後ろに現在の時刻が入ったページになります。
Python コードを使って、条件やループでページの一部分を表示できます。 Python コード内のブロックはインデントで表現されます。ある Python コード ブロックの最後の行のインデントは (コメント文であっても) ドキュメントの 末尾か、次の Python コードブロックまで持続します。
例を示します:
<html>
<%
for n in range(3):
# This indent will persist
%>
<p>This paragraph will be
repeated 3 times.</p>
<%
# This line will cause the block to end
%>
This line will only be shown once.<br>
</html>
上の例は、内部的には以下の Python コードになります:
req.write("""<html>
""")
for n in range(3):
# This indent will persist
req.write("""
<p>This paragraph will be
repeated 3 times.</p>
""")
# This line will cause the block to end
req.write("""
This line will only be shown once.<br>
</html>
""")
パーザは賢くて、Python コードブロックの最後の行が ":" (コロン) で終っている場合にも正しくインデントを推測します。このことと、 "<% %>" の中で改行に到達するとインデントはリセットされることを 考慮すると、上のページは以下のようにも書けます:
<html> <% for n in range(3): %> <p>This paragraph will be repeated 3 times.</p> <% %> This line will only be shown once.<br> </html>
とはいえ、このコードには困惑させられるでしょう。ですから、行儀として、 ブロック間で説明用のコメントを入れておくよう強く勧めます。
現時点でサポートしているディレクティブは include だけで、
以下のようにして使います:
<%@ include file="/file/to/include"%>
parse() 関数を dir 引数つきで呼び出す場合には、 "file" は相対パスで指定できます。それ以外の場合には絶対パスで なければなりません。
| req, [, filename, string, vars]) |
req はリクエストオブジェクトです; filename およびstring
はオプションのキーワード引数で、 PSP コードのソースを表します。
これらの変数はいずれか一つだけを指定できます。両方とも指定しなかった場合、
filename にreq.filename を使います。
vars はグローバル変数の辞書です。run() メソッドに 変数を渡すと、ここで渡したvars の内容をオーバライドします。
このクラスは PSP ハンドラが内部で利用しますが、汎用のテンプレートツール としても使えます。
ファイルをソースに使う場合、特定のファイルから得られるコードオブジェクトは ファイル名と更新時刻をキーにしてメモリキャッシュ上に保存されます。 キャッシュは Python インタプリタ上のグローバルな値です。従って、 ファイル更新時刻が変わらない限り、ファイルのパーズとコードオブジェクトの コンパイルはインタプリタごとに一度しか行いません。
キャッシュされたページのサイズが時としてかなりのメモリを消費することが
あるため、キャッシュのサイズは 512 ページに制限されています。
メモリの消費量が問題になる場合は dbm によるファイルキャッシュに切替え
られます。bsd db を使った簡単なテストでは、速度はわずか 20% しか低下
しませんでした。dbm ライブラリによってはレコードエントリのサイズに制限を
課しているために利用できないことがあります。そのため、自分のシステムでの
anydbmのデフォルトの実装が何かを調べておく必要があるでしょう。
dbm によるキャッシュは"PythonOption"ディレクティブに
PSPDbmCache を指定して有効にします:
PythonOption PSPDbmCache ``/tmp/pspcache.dbm''
dbm キャッシュファイルはサーバの再起動時に削除されないので注意してください。
ファイルと違い、文字列から生成したコードオブジェクトはメモリ上にしか キャッシュされません。現時点では、dbm ファイル上にキャッシュするという 選択肢はありません。
| [vars]) |
さらに、PSP コードには req, psp, session および
form といったグローバル変数が渡されます。
コード中でsession を参照している場合に限り、セッション情報が生成され、
変数session に代入されます (PSP ハンドラはコードオブジェクトの
co_names を調べてsession への参照の有無を判定します)。
session を一度でも参照すると、好むと好まざるとにかかわらず
session はクッキーを生成してセッションのロックを開始するという
ことを覚えておいてください。同様に、form がコード中で
参照されていると、mod_python クラスの FieldStorage
オブジェクトがインスタンス化されます。
psp には PSPInstance のインスタンスが渡されます。
| ) |
PSP をテンプレートメカニズムとして使う例を以下に示します:
テンプレートファイルは以下のようになります:
<html> <!-- This is a simple psp template called template.html --> <h1>Hello, <%=what%>!</h1> </html>
from mod_python import apache, psp
def handler(req):
template = psp.PSP(req, filename='template.html')
template.run({'what':'world'})
return apache.OK
| ) |
psp として PSP コードに渡されるオブジェクトの
クラスです。このクラスのインスタンスは内部的にインスタンス化されることに
なっています。__init__ のインタフェースはわざとドキュメント化
していません。
| filename) |
sys.exc_info() の返す三要素の
タプルを引数exception で受け取ります。
| object[, **kw]) |
| location[, permanent=0]) |
例:
<%
# note that the '<' above is the first byte of the page!
psp.redirect('http://www.modpython.org')
%>
この他に、 psp では以下の低水準関数を提供しています:
| filename[, dir]) |
この関数はfilename という名前のファイルを開き、内容を読み出して 解析し、得られた Python コードの入った文字列を返します。
dir を指定すると、解析対象となるファイルの完全な名前を dir
とfilename を使って決め、include ディレクティブの引数を
相対パスとして指定できるようになります。(ファイル名は単に二つの変数を
つなげて作成するため、dir の末尾にパス区切り文字が入っていなくても
補完されないので注意してください)。
| string) |
この関数は string の内容を解析し、得られた Python コードを 文字列で返します。