フックの使用¶
Pyramid フレームワークの振る舞いに影響を及ぼすために、様々な方法で 「フック」を使用することができます。
Not Found ビューの変更¶
Pyramid は URL をビューコードにマッピングすることができない場合 not found view を起動します。それは view callable です。 デフォルトの not found ビューが存在します。デフォルトの not found ビュー は、アプリケーション設定によってオーバーライドすることができます。
アプリケーションが imperative configuration を使用している場合、
pyramid.config.Configurator.add_notfound_view()
メソッドを使って
Not Found ビューを置き換えることができます:
1 2 | from helloworld.views import notfound
config.add_notfound_view(notfound)
|
helloworld.views.notfound
を、 Not Found ビューとして使用したい
view callable への参照に置き換えてください。
not found view callable は、他と同様のビュー callable です。
一方、アプリケーションが pyramid.view.view_config
デコレータと
scan を使用している場合、
pyramid.view.notfound_view_config
デコレータを使うことで
Not Found ビューを交換することができます:
1 2 3 4 5 6 7 8 9 | from pyramid.view import notfound_view_config
@notfound_view_config()
def notfound(request):
return Response('Not Found, dude', status='404 Not Found')
def main(globals, **settings):
config = Configurator()
config.scan()
|
これは、上記の命令型 (imperative) の例で示したのとまったく同じことを 行います。
アプリケーションは、必要なら 複数の not found ビューを定義することができます。
pyramid.config.Configurator.add_notfound_view()
と
pyramid.view.notfound_view_config
の両方は、それぞれ
pyramid.config.Configurator.add_view
と
pyramid.view.view_config
とほぼ同じ引数を受け取ります。
これが意味するのは、 not found ビューには適用を制限するための述語を持た
せることができるということです。例えば:
1 2 3 4 5 6 7 8 9 10 11 12 13 | from pyramid.view import notfound_view_config
@notfound_view_config(request_method='GET')
def notfound_get(request):
return Response('Not Found during GET, dude', status='404 Not Found')
@notfound_view_config(request_method='POST')
def notfound_post(request):
return Response('Not Found during POST, dude', status='404 Not Found')
def main(globals, **settings):
config = Configurator()
config.scan()
|
ビューが見つからず、リクエストメソッドが GET
だった場合、
notfound_get
ビューが呼ばれるでしょう。ビューが見つからず、リクエスト
メソッドが POST
だった場合、 notfound_post
ビューが呼ばれるでしょう。
他のビューのように、 notfound ビューは少なくとも request
パラメータ、
あるいは context
および request
の両方を受け取らなければなりません。
request
は拒否されたアクションを表わす現在の request です。
(呼び出し署名の中で使用されていれば) context
はビューを呼び出した
HTTPNotFound
例外のインスタンスになるでしょう。
pyramid.config.Configurator.add_notfound_view()
と
pyramid.view.notfound_view_config
の両方は、リクエストを
スラッシュが追加された route に自動的にリダイレクトするために使用する
ことができます。
例については Redirecting to Slash-Appended Routes を参照してください。
これは、最小の NotFound ビュー callable を実装するサンプルコードです:
1 2 3 4 | from pyramid.httpexceptions import HTTPNotFound
def notfound(request):
return HTTPNotFound()
|
Note
NotFound ビュー callable が起動される場合、 request が渡されます。
リクエストの exception
属性は、 not found ビューが呼び出される原因と
なった HTTPNotFound
例外のインスタンスに
なります。 request.exception.message
の値は、なぜ not found エラーが
生じたのかを説明する値になります。 pyramid.debug_notfound
環境設定が
true の場合と false の場合で、このメッセージは異なるでしょう。
Note
pyramid.config.Configurator.add_notfound_view()
と
pyramid.view.notfound_view_config
の両方は Pyramid 1.3 から
新しく追加されました。古い Pyramid ドキュメンテーションでは、代わりに
context
を HTTPNotFound
として add_view
を使うような指示が
ありました。これは今でも動作します; 簡便なメソッドとデコレータは、
この機能に対する単なるラッパーです。
Warning
NotFound ビュー callable が
ビュー callable の引数/呼び出し規約を変更する に記述されているような
引数リストを受け取った時、ビュー callable への最初の引数として渡される
context
は HTTPNotFound
例外
インスタンスになります。もしリソースコンテキストがあれば、それは
依然として request.context
として参照することができます。
Forbidden View の変更¶
Pyramid は、使用中の authorization policy に基づいてビュー の実行を認可することができない場合に forbidden view を起動します。 デフォルトの fobidden レスポンスは 403 ステータスコードを持ち、非常に 簡素です。しかし、必要に応じて forbidden レスポンスを生成するビューを オーバーライドすることができます。
forbidden view callable も他のものと同じようにビュー callable
の一つです。それを “forbidden” ビューにさせる view
configuration は pyramid.config.Configurator.add_forbidden_view()
API または pyramid.view.forbidden_view_config
デコレータの使用から
なります。
例えば、 forbidden ビューを登録する
pyramid.config.Configurator.add_forbidden_view()
メソッドを使用して
forbidden ビューを追加することができます:
1 2 3 | from helloworld.views import forbidden_view
from pyramid.httpexceptions import HTTPForbidden
config.add_forbidden_view(forbidden_view)
|
helloworld.views.forbidden_view
を、 Forbidden ビューを表わすために
使用したい Python view callable への参照に置き換えてください。
あるいはデコレータと scan を使用したければ、ビュー callable を
forbidden ビューとしてマークするために
pyramid.view.forbidden_view_config
デコレータを使用することが
できます:
1 2 3 4 5 6 7 8 9 | from pyramid.view import forbidden_view_config
@forbidden_view_config()
def forbidden(request):
return Response('forbidden')
def main(globals, **settings):
config = Configurator()
config.scan()
|
他のビューと同じように、 forbidden ビューは少なくとも request
パラメータ、あるいは context
および request
の両方を受け取らなければ
なりません。 forbidden ビュー callable が context
と request
の両方を受け取る場合、 HTTP 例外がコンテキストとして渡されます。
(通常期待するような) ルーター (router) によって見つかった context
は、
ビューが拒否された時には request.context
として利用可能です。
request
は拒否されたアクションを表わす現在の request です。
これは、最小の forbidden ビューを実装するサンプルコードです:
1 2 3 4 5 | from pyramid.view import view_config
from pyramid.response import Response
def forbidden_view(request):
return Response('forbidden')
|
Note
forbidden ビュー callable が起動される場合、 request が渡されます。
request の exception
属性は forbidden ビューを呼び出した
HTTPForbidden
例外のインスタンスです。
request.exception.message
の値は、forbidden が発生した理由を
説明する値になります。また request.exception.result
は forbidden
例外に関する拡張情報になります。
pyramid.debug_authorization
環境設定が true の場合と false の場合で、
これらのメッセージは異なるでしょう。
リクエストファクトリの変更¶
Pyramid が WSGI サーバからのリクエストを扱う場合は常に、
渡された WSGI 環境に基づいて request オブジェクトが生成されます。
デフォルトでは、リクエストオブジェクトを表わすために
pyramid.request.Request
クラスのインスタンスが生成されます。
リクエストオブジェクトのインスタンスを生成するために Pyramid が
使用するクラス (別名「ファクトリ」) は、 configurator の
コンストラクタに request_factory
引数を渡すことで変更できます。
この引数は、 callable か、または callable を表す dotted Python name
のいずれかです。
1 2 3 4 5 6 | from pyramid.request import Request
class MyRequest(Request):
pass
config = Configurator(request_factory=MyRequest)
|
命令型の設定を行っていて、 configurator を構築した後に
行いたければ、 pyramid.config.Configurator.set_request_factory()
メソッドによって登録することもできます:
1 2 3 4 5 6 7 8 | from pyramid.config import Configurator
from pyramid.request import Request
class MyRequest(Request):
pass
config = Configurator()
config.set_request_factory(MyRequest)
|
Before Render イベントの使用¶
pyramid.events.BeforeRender
イベントの subscriber は、
renderer globals のセットが renderer に渡される前に
検査して修正することができます。イベントオブジェクト自身には、この目的のために
使用することができる辞書風のインタフェースがあります。例えば:
1 2 3 4 5 6 | from pyramid.events import subscriber
from pyramid.events import BeforeRender
@subscriber(BeforeRender)
def add_global(event):
event['mykey'] = 'foo'
|
renderer が起動される直前に (ただし
set_renderer_globals_factory
によって追加されたアプリケーションレベルのレンダラーグローバルファクトリが
もしあれば、それらがレンダラグローバル辞書にそれ自身のキーを注入した後で)
この型のオブジェクトがイベントとして送られます。
subscriber がレンダラーグローバル辞書に既に存在するキーを追加しようとした
場合、 KeyError
が発生します。イベント subscriber は相対順序を
保持しないので、この制限が強制されます。すべての
pyramid.events.BeforeRender
subscriber およびレンダラーグローバル
ファクトリによってレンダラーグローバル辞書に追加されるキーのセットは、
ユニークでなければなりません。
ビューから返された辞書は、 BeforeRender
イベントの
rendering_val
属性によってアクセスできます。
以下のようにビュー callable から
{'mykey': 'somevalue', 'mykey2': 'somevalue2'}
を返すことを考えてください:
1 2 3 4 5 | from pyramid.view import view_config
@view_config(renderer='some_renderer')
def myview(request):
return {'mykey': 'somevalue', 'mykey2': 'somevalue2'}
|
BeforeRender
オブジェクトからこれらの値に
アクセスするために rendering_val
を使うことができます:
1 2 3 4 5 6 7 | from pyramid.events import subscriber
from pyramid.events import BeforeRender
@subscriber(BeforeRender)
def read_return(event):
# {'mykey': 'somevalue'} is returned from the view
print(event.rendering_val['mykey'])
|
BeforeRender
イベントインタフェースについては
pyramid.interfaces.IBeforeRender
の API ドキュメンテーションを
参照してください。
レンダラーグローバルに値を追加する際に、イベント subscriber により多くの コントロールを与える別の (非推奨の) メカニズムが レンダラーグローバルの追加 (非推奨) にあります。
レンダラーグローバルの追加 (非推奨)¶
Warning
この機能は Pyramid 1.1 から非推奨になりました。イベント subscriber が レンダラーグローバルに値を追加できるようにするための推奨される メカニズムは Before Render イベントの使用 の中で文書化されます。
Pyramid がレンダリングを実行するリクエストを扱う場合
(renderer=
設定属性を持つビューが起動された後、あるいは
pyramid.renderers
モジュール内の render
で始まるメソッドの
うちのいずれかが呼ばれた場合) は常に、 レンダラーグローバル をレンダラー
に送られる システム 値に注入することができます。デフォルトではレンダラー
グローバルは注入されず、 (request
, context
, view
,
renderer_name
のような) 「素の」システム値が、すべてのレンダラーに
渡されるシステム辞書の中にある唯一の値です。
configurator のコンストラクタに renderer_globals_factory
引数を
渡すことにより、レンダラーが起動される度に Pyramid が呼び出す
コールバックを追加することができます。このコールバックは、 callable
オブジェクト、あるいはそのような callable を表す dotted Python name
のいずれかです。
1 2 3 4 5 | def renderer_globals_factory(system):
return {'a': 1}
config = Configurator(
renderer_globals_factory=renderer_globals_factory)
|
このようなコールバックは、オリジナルのシステム値を含む単一の位置引数
(名目上 system
という名前が付けられます) を受け取らなければなりません。
それは、システム辞書にマージされる値の辞書を返さなければなりません。
システム辞書の中にある値の説明については、
System Values Used During Rendering を参照してください。
命令型の設定を行っていて、 configurator を構築した後に
行いたければ、 pyramid.config.Configurator.set_renderer_globals_factory()
メソッドによって登録することもできます:
1 2 3 4 5 6 7 | from pyramid.config import Configurator
def renderer_globals_factory(system):
return {'a': 1}
config = Configurator()
config.set_renderer_globals_factory(renderer_globals_factory)
|
レスポンスコールバックの使用¶
他の多くのウェブフレームワークと異なり、 Pyramid は積極的に グローバルなレスポンスオブジェクトを生成しません。 アプリケーションは response callback を追加することによって、 ビューから返されるすべてのレスポンスオブジェクトに対して実行されるアクションを (通常レスポンスを変更するために) 登録できます。
pyramid.request.Request.add_response_callback()
メソッドが
レスポンスコールバックを登録するために使用されます。
レスポンスコールバックは、 2 つの位置パラメータ request
と
response
を受け取る callable です。例えば:
1 2 3 4 5 | def cache_callback(request, response):
"""Set the cache_control max_age for the response"""
if request.exception is not None:
response.cache_control.max_age = 360
request.add_response_callback(cache_callback)
|
未処理の例外がアプリケーションコードの中で起こった場合、あるいは
view callable によって返されたレスポンスオブジェクトが無効の
場合、レスポンスコールバックは呼ばれません。しかし、 exception
view が正常にレンダリングされる場合、レスポンスコールバックは起動
されます: そのような場合、レスポンスコールバックが呼ばれた時の
リクエストの request.exception
属性は、デフォルト値 None
の
代わりに例外オブジェクトになります。
レスポンスコールバックは、追加された順番で
(first-to-most-recently-added; 最後に追加されたものが最初に) 呼ばれます。
NewResponse
イベントが送られた 後で 、すべて
のレスポンスコールバックが呼ばれます。レスポンスコールバックで発生した
エラーは特別な扱いは受けません。それは呼び出し元の Pyramid ルーター
アプリケーションに伝搬するでしょう。
レスポンスコールバックは、単一リクエストのライフタイムを持ちます。
すべての リクエストの結果としてレスポンスコールバックが起こることを
期待する場合、新しく作られるすべてのリクエストにコールバックを再登録
しなければなりません (恐らく NewRequest
イベントの subscriber 内で)。
finished コールバックの使用¶
finished callback は、 Pyramid router によって リクエスト処理の最後に無条件で呼ばれる関数です。 finished コールバックは、 リクエストの終わりに無条件でアクションを行なうために使用することができます。
pyramid.request.Request.add_finished_callback()
メソッドは、
finished コールバックを登録するために使用されます。
finished コールバックは、単一の位置パラメータ request
を受け取る
callable です。例えば:
1 2 3 4 5 6 7 8 | import logging
log = logging.getLogger(__name__)
def log_callback(request):
"""Log information at the end of request"""
log.debug('Request is finished.')
request.add_finished_callback(log_callback)
|
finished コールバックは、追加された順番で (first-to-most-recently-added; 最後に追加されたものが最初に) 呼ばれます。 (response callback と異なり) finished コールバックは、 レスポンスが生成されるのを妨げる例外がアプリケーションコード内で 起こっても常に呼ばれます。
リクエストに関連付けられた finished コールバックのセットは、そのリクエスト
を処理する 最終段階で 呼ばれます; それらは、本質的にリクエストが「終わる」
前に router によって呼ばれるまさに最後のものです。レスポンス処理が
既に生じた後、 ルーターのリクエスト処理コード内のトップレベルの finally:
ブロックでそれらが呼ばれます。その結果、レスポンス処理は既に終わって
いるため、 finished コールバックに渡された request
に対して行なった
変更には意味のある効果はありません。また、リクエストのスコープはすべての
finished コールバックが処理された後でほとんど直ちに終了します。
finished コールバックで発生したエラーは特別な扱いは受けません。それは 呼び出し元の Pyramid ルーターアプリケーションに伝搬するでしょう。
finished コールバックは、単一リクエストのライフタイムを持ちます。
すべての リクエストの結果として finished コールバックが起こることを
期待する場合、すべての新しく作られるリクエストにコールバックを再登録
しなければなりません (恐らく NewRequest
イベントの subscriber 内で)。
トラバーサーの変更¶
Pyramid が使用するデフォルトの traversal アルゴリズムは The Traversal Algorithm の中で説明されています。必要になることは めったにありませんが、設定によってこのデフォルトのアルゴリズムを異なる トラバーサルパターンと選択的に交換することができます。
1 2 3 4 | from pyramid.config import Configurator
from myapp.traversal import Traverser
config = Configurator()
config.add_traverser(Traverser)
|
上記の例において、 myapp.traversal.Traverser
は次のインタフェースを
実装するクラスであると仮定されます:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | class Traverser(object):
def __init__(self, root):
""" Accept the root object returned from the root factory """
def __call__(self, request):
""" Return a dictionary with (at least) the keys ``root``,
``context``, ``view_name``, ``subpath``, ``traversed``,
``virtual_root``, and ``virtual_root_path``. These values are
typically the result of a resource tree traversal. ``root``
is the physical root object, ``context`` will be a resource
object, ``view_name`` will be the view name used (a Unicode
name), ``subpath`` will be a sequence of Unicode names that
followed the view name but were not traversed, ``traversed``
will be a sequence of Unicode names that were traversed
(including the virtual root path, if any) ``virtual_root``
will be a resource object representing the virtual root (or the
physical root if traversal was not performed), and
``virtual_root_path`` will be a sequence representing the
virtual root path (a sequence of Unicode names) or None if
traversal was not performed.
Extra keys for special purpose functionality can be added as
necessary.
All values returned in the dictionary will be made available
as attributes of the ``request`` object.
"""
|
複数のトラバーサルアルゴリズムを同時に有効にすることもできます。例えば、 root factory が条件付きで複数の型のオブジェクトを返す場合、 代替トラバーサーアダプタをある特定のクラスあるいはインタフェース 「専用」と宣言することができます。root ファクトリがそのクラスまたは インタフェースを実装したオブジェクトを返した場合、カスタムトラバーサーが 使用されます。そうでなければ、デフォルトトラバーサーが使用されます。例えば:
1 2 3 4 5 | from myapp.traversal import Traverser
from myapp.resources import MyRoot
from pyramid.config import Configurator
config = Configurator()
config.add_traverser(Traverser, MyRoot)
|
もし上記のコード断片が Pyramid __init__.py
ファイルの main
関数に
追加されれば、 Pyramid は アプリケーション root factory が
myapp.resources.MyRoot
オブジェクトのインスタンスを返した時にだけ
myapp.traversal.Traverser
を使用します。そうでなければ、トラバーサルを
行うためにデフォルトの Pyramid トラバーサーが使用されます。
pyramid.request.Request.resource_url()
の URL 生成方法の変更¶
トラバーサーの変更 で説明されるようなトラバーサーを追加する場合、
pyramid.request.Request.resource_url()
API を使用し続けることは
多くの場合有用です。しかし、この API がカスタムトラバーサーに由来する
リソースに対して使用された場合、トラバーサルが終了する方法が修正されて
いるためデフォルトで生成される URL は正しくないかもしれません。
トラバーサーを追加している場合、
pyramid.config.add_resource_url_adapter()
呼び出しを追加することに
よって resource_url()
が特定の型の
リソースに対する URL を生成する方法を変更できます。
例えば:
1 2 3 4 | from myapp.traversal import ResourceURLAdapter
from myapp.resources import MyRoot
config.add_resource_url_adapter(ResourceURLAdapter, MyRoot)
|
上記の例において、 resource_url
に渡された resource がクラス
myapp.resources.MyRoot
である場合は常に、
resource_url()
にサービスを提供するために
myapp.traversal.ResourceURLAdapter
クラスが使用されます。
resource_iface
の引数 MyRoot
は、見つかったリソース url ファクトリ
に対してリソースによって所有されなければならないインタフェースの型を
表わしています。 resource_iface
引数が省略されれば、このリソース
url アダプターはすべてのリソースに使用されます。
IResourceURL
を提供するクラスで実装
しなければならない API は以下の通りです:
1 2 3 4 5 6 7 8 9 | class MyResourceURL(object):
""" An adapter which provides the virtual and physical paths of a
resource
"""
def __init__(self, resource, request):
""" Accept the resource and request and set self.physical_path and
self.virtual_path"""
self.virtual_path = some_function_of(resource, request)
self.physical_path = some_other_function_of(resource, request)
|
デフォルトのコンテキスト URL ジェネレータを熟読したければ、
Pylons GitHub Pyramid リポジトリの traversal module
に含まれるクラス pyramid.traversal.ResourceURL
が利用可能です。
詳細は pyramid.config.add_resource_url_adapter()
を参照してください。
Pyramid がビューレスポンスを扱う方法の変更¶
pyramid.config.Configurator.add_response_adapter()
あるいは
response_adapter
デコレータに関係するフック
を使うことにより、 Pyramid がビュー callable を呼び出した結果をどのように
扱うかを型に応じてコントロールすることが可能です。
Note
これは Pyramid 1.1 からの新機能です。
Pyramid は、ビュー callable が返したオブジェクトが「本物の」レスポンス
オブジェクトであることを保証するために、様々な場所でビュー callable を
呼び出した結果を IResponse
インタフェースに
適合させます。ほとんどの場合、この適合の結果は結果のオブジェクト自体です。
なぜなら、このマニュアルに含まれるドキュメンテーションを読んだ
「一般ユーザ」によって書かれたビュー callable は、常に
IResponse
インタフェースを実装する
オブジェクトを返すからです。最も典型的には、これは
pyramid.response.Response
クラスあるいはそのサブクラスの
インスタンスになるでしょう。一般のユーザが renderer を使用する
ように設定されていないビュー callable から非レスポンスオブジェクトを
返す場合、そのユーザは、典型的にはルーターがエラーを発生させることを
期待するでしょう。しかしながら、任意の戻り値から
IResponse
を実装するオブジェクトに変換する
アダプターを提供することにより、ユーザがビュー callable から任意の値を
返せるように Pyramid をフックすることができます。
例えば、ビュー callable が (文字列をレスポンスオブジェクトに変換する renderer を必要とせずに) 裸の文字列オブジェクトを返せるように したければ、文字列をレスポンスに変換するアダプターを登録することができます:
1 2 3 4 5 6 7 8 9 | from pyramid.response import Response
def string_response_adapter(s):
response = Response(s)
return response
# config is an instance of pyramid.config.Configurator
config.add_response_adapter(string_response_adapter, str)
|
同様に、ビュー callable から単純化されたレスポンスオブジェクトの一種を 返せるようにしたければ、より複雑な IResponse インタフェースへの アダプターを登録するために IResponse フックを使用することができます:
1 2 3 4 5 6 7 8 9 10 11 12 13 | from pyramid.response import Response
class SimpleResponse(object):
def __init__(self, body):
self.body = body
def simple_response_adapter(simple_response):
response = Response(simple_response.body)
return response
# config is an instance of pyramid.config.Configurator
config.add_response_adapter(simple_response_adapter, SimpleResponse)
|
いずれの場合であっても、 pyramid.response.Response
オブジェクト
を使用する代わりに自分のレスポンスオブジェクトを実装したければ、
pyramid.interfaces.IResponse
の中で概説されているすべての
属性とメソッドをそのオブジェクトが実装していることを保証しなければなりません。
また、クラスデコレータとして zope.interface.implementer(IResponse)
を使用する必要があります。
1 2 3 4 5 6 7 | from pyramid.interfaces import IResponse
from zope.interface import implementer
@implementer(IResponse)
class MyResponse(object):
# ... an implementation of every method and attribute
# documented in IResponse should follow ...
|
代替レスポンスオブジェクトの実装がビュー callable によって返された場合、
そのオブジェクトが (zope.interface.implementer(IResponse)
によって)
IResponse
を実装すると主張するなら、その
オブジェクトのためにアダプターを登録する必要はありません; Pyramid は
それを直接使用するでしょう。
webob.Response
のための IResponse アダプターは、
(pyramid.response.Response
とは対照的に) Pyramid によって
スタートアップ時にデフォルトで登録されます。なぜなら、このクラスの
インスタンス (またこのクラスのサブクラスのインスタンス) はその性質上
IResponse をネイティブに提供するからです。 webob.Response
に対して
登録されたアダプターは、単にレスポンスオブジェクトを返します。
pyramid.config.Configurator.add_response_adapter()
を使用する代わりに、
pyramid.response.response_adapter
デコレータを使用しても構いません:
1 2 3 4 5 6 7 | from pyramid.response import Response
from pyramid.response import response_adapter
@response_adapter(str)
def string_response_adapter(s):
response = Response(s)
return response
|
上記の例は、 scan された時に以下と同じ効果があります:
config.add_response_adapter(string_response_adapter, str)
scan によって活性化されるまで、
response_adapter
デコレータは効果がないでしょう。
ビューマッパーの変更¶
ビュー callable のためのデフォルトの呼び出し規則は ビュー 章の中で文書化されます。 view mapper を 使用することで、ユーザがビュー callable を定義する方法を変更できます。
ビューマッパーは、いくつかのキーワード引数を受け取って 1 つの callable
を返すオブジェクトです。返された callable は view callable
オブジェクトと共に呼び出されます。返された callable は、それ自体
「内部呼び出しプロトコル」 (context, request)
で呼び出すことのできる
別の callable を返す必要があります。
複数の方法でビューマッパーを使用することができます:
- ビュー callable 自体に
__view_mapper__
属性 (それはビューマッパーオブジェクトです) をセットすることによって。 - マッパーオブジェクトを
pyramid.config.Configurator.add_view()
(あるいはその宣言的/デコレータ等価物) にmapper
引数として渡す ことによって。 - デフォルト ビューマッパーを登録することによって。
これは Pylons 「コントローラー」を (ある程度) 模倣するビューマッパーの
一例です。マッパーはいくつかのキーワード引数で初期化されます。その
__call__
メソッドはビューオブジェクト (それはクラスになるでしょう)
を受け取ります。それは、アクションメソッドとして使用すべき属性を決定す
るために、渡される attr
キーワード引数を使用します。それが返す
ラッパーメソッドは、 (context, request)
を受け取り、 matchdict
から action
をポップした後で matchdict によって示唆された
キーワード引数を伴ってアクションメソッドを呼び出した結果を返します。これは、
route マッチ辞書から取り出されたルーティングパラメータをキーワード引数
としてアクションメソッドを呼び出す Pylons スタイルをある程度エミュレート
します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | # framework
class PylonsControllerViewMapper(object):
def __init__(self, **kw):
self.kw = kw
def __call__(self, view):
attr = self.kw['attr']
def wrapper(context, request):
matchdict = request.matchdict.copy()
matchdict.pop('action', None)
inst = view(request)
meth = getattr(inst, attr)
return meth(**matchdict)
return wrapper
class BaseController(object):
__view_mapper__ = PylonsControllerViewMapper
|
ユーザは、これらのフレームワークコンポーネントを以下のように使用 するでしょう:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | # user application
from pyramid.response import Response
from pyramid.config import Configurator
import pyramid_handlers
from wsgiref.simple_server import make_server
class MyController(BaseController):
def index(self, id):
return Response(id)
if __name__ == '__main__':
config = Configurator()
config.include(pyramid_handlers)
config.add_handler('one', '/{id}', MyController, action='index')
config.add_handler('two', '/{action}/{id}', MyController)
server.make_server('0.0.0.0', 8080, config.make_wsgi_app())
server.serve_forever()
|
pyramid.config.Configurator.set_view_mapper()
メソッドは、
(Pyramid 自体によって使用されるスーパーデフォルトビューマッパーをオーバーライド
して) デフォルト ビューマッパーをセットするために使用することができます。
単一の ビュー登録は、マッパーを mapper
引数として
add_view()
へ渡すことによって、
ビューマッパーを使用することができます。
設定デコレータの登録¶
view_config
のようなデコレータは、それがデコレート
する関数またはクラスの振る舞いを変更しません。代わりに、 scan が
実行された時に、関数またはクラスの修正版が Pyramid に登録されます。
そのような振る舞いを提供する自分のデコレータが欲しいと思うかもしれません。 これは、 Pyramid が行っているのと同じ方法で Venusian パッケージを使用することにより実現可能です。
例として、関数を登録するデコレータを書きたいと仮定しましょう。その デコレータは、 Pyramid によって提供される application registry の中に Zope Component Architecture 「ユーティリティ」 としてそれがラップする関数を登録します。アプリケーションレジストリおよび レジストリ内部のユーティリティは、アプリケーション設定が少なくとも 部分的に完了してから初めて利用可能になります。設定が開始される前にそれが 実行された場合、通常のデコレータは失敗します。
しかし、 Venusian を使用すれば以下のようにデコレータを書く ことができます:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | import venusian
from mypackage.interfaces import IMyUtility
class registerFunction(object):
def __init__(self, path):
self.path = path
def register(self, scanner, name, wrapped):
registry = scanner.config.registry
registry.getUtility(IMyUtility).register(
self.path, wrapped)
def __call__(self, wrapped):
venusian.attach(wrapped, self.register)
return wrapped
|
その後、このデコレータを使用してコードのどこでも関数を登録することが できます:
1 2 3 | @registerFunction('/some/path')
def my_function():
do_stuff()
|
しかし、事前にユーティリティをセットアップできるにもかかわらず、 scan が行なわれた時にだけユーティリティが検索されます:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | from zope.interface import implementer
from wsgiref.simple_server import make_server
from pyramid.config import Configurator
from mypackage.interfaces import IMyUtility
@implementer(IMyUtility)
class UtilityImplementation:
def __init__(self):
self.registrations = {}
def register(self, path, callable_):
self.registrations[path] = callable_
if __name__ == '__main__':
config = Configurator()
config.registry.registerUtility(UtilityImplementation())
config.scan()
app = config.make_wsgi_app()
server = make_server('0.0.0.0', 8080, app)
server.serve_forever()
|
完全な詳細については Venusian documentation を読んでください。
“tween” の登録¶
Note
tween は Pyramid 1.2 から追加された機能です。旧バージョンでは利用 できません。
tween (単語 “between” の短縮形) は、 Pyramid ルーターのメイン リクエスト処理関数と、 Pyramid を “app” として使用する上流の WSGI コンポーネントの間に存在するコードです。この機能は Pyramid フレームワーク 拡張によって使われることがあります。例えば、上流の WSGI アプリケーション に返される前に例外を検証するような Pyramid 専用の view timing サポートの ための bookkeeping コードを提供することができます。 tween は WSGI ミドルウェアと多少似た動作をしますが、 Pyramid のレンダリング機構と同様 Pyramid の application registry にアクセスできるコンテキスト内で 動作するという利点があります。
tween ファクトリの作成¶
tweens を利用するためには「tween ファクトリ」を構築する必要があります。
tween ファクトリは、 2 つの引数 handler
と registry
を受け取る
グローバルにインポート可能な callable です。 handler
はメインの
Pyramid リクエスト処理関数か、あるいは別の tween のいずれかです。
registry
はこの Configurator によって表わされる Pyramid
application registry です。 tween ファクトリは
呼び出された時に tween を返さなければなりません。
tween は、 request オブジェクトを受け取って、 response オブジェクトを返す callable です。
これは tween ファクトリの例です:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | # in a module named myapp.tweens
import time
from pyramid.settings import asbool
import logging
log = logging.getLogger(__name__)
def timing_tween_factory(handler, registry):
if asbool(registry.settings.get('do_timing')):
# if timing support is enabled, return a wrapper
def timing_tween(request):
start = time.time()
try:
response = handler(request)
finally:
end = time.time()
log.debug('The request took %s seconds' %
(end - start))
return response
return timing_tween
# if timing support is not enabled, return the original
# handler
return handler
|
覚えているかもしれませんが、 tween は request オブジェクトを
受け取って response を返すオブジェクトです。 tween に対する
request
引数は、 Pyramid ルーターが WSGI リクエストを受け取った時
に生成されたリクエストです。レスポンスオブジェクトは下流の Pyramid
アプリケーションによって生成され、 tween によって返されます。
上記の例で tween ファクトリは timing_tween
tween を定義していて、
asbool(registry.settings.get('do_timing'))
が true の場合はそれを
返します。そうでなければ渡されたハンドラを単に返します。
registry.settings
属性は、ユーザによって提供される (通常 .ini
ファイル中の) 設定へのハンドルです。この場合、ユーザが do_timing
設定を定義していてその設定値が True なら、ユーザは timing を行いたいと
言ったことになり、したがって tween ファクトリは timing tween を返します;
そうでなければ timing は一切行わず、単に提供されたハンドラを返します。
この例 の timing tween は、単に開始時刻を記録し、下流のハンドラを呼び、 下流のハンドラによって消費された秒数を記録し、レスポンスを返します。
暗黙的な tween ファクトリの登録¶
tween ファクトリを作成したら、
pyramid.config.Configurator.add_tween()
メソッドを使用して、
その dotted Python name を用いてそれを暗黙の tween チェインに
登録することができます。
これは、 Pyramid アプリケーションで tween ファクトリを「暗黙の」 tween として登録する例です:
1 2 3 | from pyramid.config import Configurator
config = Configurator()
config.add_tween('myapp.tweens.timing_tween_factory')
|
pyramid.config.Configurator.add_tween()
への最初の引数として
dotted Python name を使用する必要があることに注意してください;
これは tween ファクトリを指していなければなりません。 tween ファクトリ
オブジェクト自体をメソッドへ渡すことはできません: それはグローバルに
インポート可能なオブジェクトを指す dotted Python name である必要が
あります。上記の例では、 timing_tween_factory
tween ファクトリが
myapp.tweens
という名前のモジュールに定義されていると仮定されます。
したがって、 tween ファクトリは myapp.tweens.timing_tween_factory
のようにしてインポート可能です。
pyramid.config.Configurator.add_tween()
を使用する場合、
あなたはシステムに対して、設定で明示的な tween リストが提供されない限り
この tween ファクトリをスタートアップ時に使うように、と伝えています。
これが「暗黙の」 tween の意味することです。ユーザはいつでも、暗黙に追加
された tween を並び替えたり除外したりして、明示的な tween リストを提供
することを選択できます。 tween の明示的な順序についての詳細は
明示的な tween 順序 を参照してください。
1つのアプリケーション設定中で
pyramid.config.Configurator.add_tween()
への呼び出しが複数回
行われた場合、それらの tween はアプリケーションのスタートアップ時に
まとめてチェインされます。 add_tween
によって追加された 最初の
tween ファクトリが Pyramid 例外ビュー tween ファクトリをその
handler
引数として呼び出され、次にその直後に追加された tween
ファクトリが最初の tween ファクトリの結果をその handler
引数として
呼び出されます。このようにして、すべての tween ファクトリが呼び出される
まで際限なく続きます。 Pyramid ルーターは、このチェインによって生成された
最も外側の tween (最後に追加された tween ファクトリによって生成された
tween) をそのリクエストハンドラ関数として使用します。例えば:
1 2 3 4 5 | from pyramid.config import Configurator
config = Configurator()
config.add_tween('myapp.tween_factory1')
config.add_tween('myapp.tween_factory2')
|
上記の例は、以下に見るような暗黙の tween チェインを生成するでしょう:
INGRESS (implicit)
myapp.tween_factory2
myapp.tween_factory1
pyramid.tweens.excview_tween_factory (implicit)
MAIN (implicit)
暗黙的な tween 順序の指示¶
上述のように、デフォルトではチェインの順序は
pyramid.config.Configurator.add_tween()
の呼び出しの相対的な
順番によって完全にコントロールされます。しかし、 add_tween の呼び出し元は
add_tween()
に under
または
over
(あるいはその両方) の引数を渡すことで、暗黙の tween チェインの
順序に影響を及ぼすためのオプションのヒントを提供することができます。
これらのヒントは、明示的な tween 順序が使用されていない場合にだけ使用されます。
明示的な tween 順序を設定する方法の説明については、
明示的な tween 順序 を参照してください。
under
や over
(またはその両方) に対して可能な値は:
None
(デフォルト)- tween ファクトリに対する dotted Python name: 同じ設定セッション
内で
add_tween
呼び出しで追加された tween ファクトリの predicted dotted name を表わす文字列。 - 定数
pyramid.tweens.MAIN
,pyramid.tweens.INGRESS
あるいはpyramid.tweens.EXCVIEW
のうちの1つ。 - 上記のものの任意の組み合わせによる iterable 。これは、期待する tween が含まれていない場合や、他の複数の tween との互換性のために、ユーザが fallback を指定することを可能にします。
実質的に、 under
は「メインの Pyramid アプリケーションにより近い」
ことを意味して、 over
は「リクエストの入口により近い」ことを意味します。
例えば、以下の add_tween()
に対する
呼び出しは、 myapp.tween_factory
で表わされる tween ファクトリを
(ptweens
の順で) メインの Pyramid リクエストハンドラの直接「上」に
置こうとします。
1 2 3 | import pyramid.tweens
config.add_tween('myapp.tween_factory', over=pyramid.tweens.MAIN)
|
上記の例は、以下に見るような暗黙の tween チェインを生成するでしょう:
INGRESS (implicit)
pyramid.tweens.excview_tween_factory (implicit)
myapp.tween_factory
MAIN (implicit)
同様に、以下の add_tween()
に対する
呼び出しでは、この tween ファクトリをメインハンドラより「上」で、別に追加
された tween ファクトリより「下」に置こうとします:
1 2 3 4 5 6 7 | import pyramid.tweens
config.add_tween('myapp.tween_factory1',
over=pyramid.tweens.MAIN)
config.add_tween('myapp.tween_factory2',
over=pyramid.tweens.MAIN,
under='myapp.tween_factory1')
|
上記の例は、以下に見るような暗黙の tween チェインを生成するでしょう:
INGRESS (implicit)
pyramid.tweens.excview_tween_factory (implicit)
myapp.tween_factory1
myapp.tween_factory2
MAIN (implicit)
over
も under
も指定しないことは、 under=INGRESS
を指定した
ことと等価です。
under
(あるいは over
) に対するすべてのオプションが現在の設定で
見つからない場合、それはエラーです。あるオプションが純粋に他の tween
との互換性のために指定される場合、単に MAIN または INGRESS の fallback
を追加してください。例えば、 under=('someothertween',
'someothertween2', INGRESS)
。この制約は、 tween を ‘someothertween’
tween, ‘someothertween2’ tween, INGRESS のすべての下に置くことを要求
します。これらのうちのいずれかが現在の設定にない場合は、この制約は単に
存在する tween に基づいて自分自身を組織するでしょう。
明示的な tween 順序¶
暗黙の tween 順序は明らかに単なるベストエフォートです。 Pyramid は、
add_tween()
の呼び出しから得られる
ヒントを用いてできるだけ暗黙の tween 順序を提供しようとしますが、
それは単なるベストエフォートなので、非常に正確な tween 順序が必要な場合、
それを得る唯一の方法は明示的な tween 順序を使用することです。
デプロイを行うユーザは、 pyramid.tweens
設定値を使用することで
add_tween()
の呼び出しによって暗黙
的に指定された tween の選択および順序を完全にオーバーライドすることができます。
この設定値が使われた場合、それは暗黙の tween チェイン中での tween
ファクトリの順序 (または選択) をオーバーライドするような Python dotted names の
リストでなければなりません。例えば:
1 2 3 4 5 6 7 8 9 | [app:main]
use = egg:MyApp
pyramid.reload_templates = true
pyramid.debug_authorization = false
pyramid.debug_notfound = false
pyramid.debug_routematch = false
pyramid.debug_templates = true
pyramid.tweens = myapp.my_cool_tween_factory
pyramid.tweens.excview_tween_factory
|
上記の設定では、設定中に行われた
pyramid.config.Configurator.add_tween()
の呼び出しは無視されます。
また、ユーザは pyramid.config.Configurator.add_tween()
によって
追加された任意の tween ファクトリの代わりに pyramid.tweens
設定に
リストした tween ファクトリ (各々は tween ファクトリを指す
dotted Python name です) を使用するようにシステムに指示しています。
pyramid.tweens
リスト中の 最初の tween ファクトリは、
有効な Pyramid リクエスト処理関数の producer として使用されるでしょう;
それは直下で宣言された tween ファクトリをラップして、それが
無制限に続きます。「メイン」 Pyramid リクエストハンドラは暗黙的です。
そして常に「一番下」にあります。
Note
Pyramid 自身の exception view 処理ロジックは tween
ファクトリ関数として実装されます:
pyramid.tweens.excview_tween_factory()
。もし Pyramid 例外ビューの
処理が行われることを期待していて、 pyramid.tweens
設定で
tween ファクトリを指定しているなら、 pyramid.tweens
設定リストに
明示的に pyramid.tweens.excview_tween_factory()
関数を追加
しなければなりません。もしそれが存在しなければ、 Pyramid は例外ビュー
処理を行ないません。
tween の衝突と順序の循環¶
Pyramid は、設定衝突検知を使用して同じ tween ファクトリが複数回
tween チェインに追加されることを防ぎます。設定に複数回同じ tween
ファクトリを追加したければ、以下のことをする必要があります: a) それが
衝突するファクトリとは別の、グローバルにインポート可能なインスタンス
オブジェクトである tween ファクトリを使用する b) tween ファクトリとして
それが衝突する別の tween ファクトリと同じロジックで異なる __name__
属性を持つ関数またはクラスを使用する、あるいは c)
pyramid.config.Configurator.add_tween()
の複数回の呼び出しの間に
pyramid.config.Configurator.commit()
を呼び出す。
“add_tween” への任意の呼び出しの中で over
と under
が使用されている
時に暗黙の tween 順序に循環が検知された場合、スタートアップ時に例外が発生
します。
tween 順序の表示¶
ptweens
コマンドラインユーティリティを使って、アプリケーションによって
使用される現在の暗黙的および明示的な tween チェインを表示することができます。
Displaying “Tweens” を参照してください。
Adding A Third Party View, Route, or Subscriber Predicate¶
Note
Third-party view, route, and subscriber predicates are a feature new as of Pyramid 1.4.
View and Route Predicates¶
View and route predicates used during configuration allow you to narrow the
set of circumstances under which a view or route will match. For example,
the request_method
view predicate can be used to ensure a view callable
is only invoked when the request’s method is POST
:
@view_config(request_method='POST')
def someview(request):
...
Likewise, a similar predicate can be used as a route predicate:
config.add_route('name', '/foo', request_method='POST')
Many other built-in predicates exists (request_param
, and others). You
can add third-party predicates to the list of available predicates by using
one of pyramid.config.Configurator.add_view_predicate()
or
pyramid.config.Configurator.add_route_predicate()
. The former adds a
view predicate, the latter a route predicate.
When using one of those APIs, you pass a name and a factory to add a predicate during Pyramid’s configuration stage. For example:
config.add_view_predicate('content_type', ContentTypePredicate)
The above example adds a new predicate named content_type
to the list of
available predicates for views. This will allow the following view
configuration statement to work:
1 2 | @view_config(content_type='File')
def aview(request): ...
|
The first argument to pyramid.config.Configurator.add_view_predicate()
,
the name, is a string representing the name that is expected to be passed to
view_config
(or its imperative analogue add_view
).
The second argument is a view or route predicate factory. A view or route
predicate factory is most often a class with a constructor (__init__
), a
text
method, a phash
method and a __call__
method. For example:
1 2 3 4 5 6 7 8 9 10 11 | class ContentTypePredicate(object):
def __init__(self, val, config):
self.val = val
def text(self):
return 'content_type = %s' % (self.val,)
phash = text
def __call__(self, context, request):
return getattr(context, 'content_type', None) == self.val
|
The constructor of a predicate factory takes two arguments: val
and
config
. The val
argument will be the argument passed to
view_config
(or add_view
). In the example above, it will be the
string File
. The second arg, config
will be the Configurator
instance at the time of configuration.
The text
method must return a string. It should be useful to describe
the behavior of the predicate in error messages.
The phash
method must return a string or a sequence of strings. It’s
most often the same as text
, as long as text
uniquely describes the
predicate’s name and the value passed to the constructor. If text
is
more general, or doesn’t describe things that way, phash
should return a
string with the name and the value serialized. The result of phash
is
not seen in output anywhere, it just informs the uniqueness constraints for
view configuration.
The __call__
method of a predicate factory must accept a resource
(context
) and a request, and must return True
or False
. It is
the “meat” of the predicate.
You can use the same predicate factory as both a view predicate and as a
route predicate, but you’ll need to call add_view_predicate
and
add_route_predicate
separately with the same factory.
Subscriber Predicates¶
Subscriber predicates work almost exactly like view and route predicates. They narrow the set of circumstances in which a subscriber will be called. There are several minor differences between a subscriber predicate and a view/route predicate:
- There are no default subscriber predicates. You must register one to use one.
- The
__call__
method of a subscriber predicate accepts a singleevent
object instead of acontext
and arequest
. - Not every subscriber predicate can be used with every event type. Some subscriber predicates will assume a certain event type.
Here’s an example of a subscriber predicate that can be used in conjunction
with a subscriber that subscribes to the pyramid.events.NewReqest
event type.
1 2 3 4 5 6 7 8 9 10 11 | class RequestPathStartsWith(object):
def __init__(self, val, config):
self.val = val
def text(self):
return 'path_startswith = %s' % (self.val,)
phash = text
def __call__(self, event):
return event.request.path.startswith(self.val)
|
Once you’ve created a subscriber predicate, it may registered via
pyramid.config.Configurator.add_subscriber_predicate()
. For example:
config.add_subscriber_predicate(
'request_path_startswith', RequestPathStartsWith)
Once a subscriber predicate is registered, you can use it in a call to
pyramid.config.Configurator.add_subscriber()
or to
pyramid.events.subscriber
. Here’s an example of using the
previously registered request_path_startswith
predicate in a call to
add_subscriber()
:
1 2 3 4 5 6 7 8 9 | # define a subscriber in your code
def yosubscriber(event):
event.request.yo = 'YO!'
# and at configuration time
config.add_subscriber(yosubscriber, NewRequest,
request_path_startswith='/add_yo')
|
Here’s the same subscriber/predicate/event-type combination used via
subscriber
.
1 2 3 4 5 | from pyramid.events import subscriber
@subscriber(NewRequest, request_path_startswith='/add_yo')
def yosubscriber(event):
event.request.yo = 'YO!'
|
In either of the above configurations, the yosubscriber
callable will
only be called if the request path starts with /add_yo
. Otherwise the
event subscriber will not be called.
Note that the request_path_startswith
subscriber you defined can be used
with events that have a request
attribute, but not ones that do not. So,
for example, the predicate can be used with subscribers registered for
pyramid.events.NewRequest
and pyramid.events.ContextFound
events, but it cannot be used with subscribers registered for
pyramid.events.ApplicationCreated
because the latter type of event
has no request
attribute. The point being: unlike route and view
predicates, not every type of subscriber predicate will necessarily be
applicable for use in every subscriber registration. It is not the
responsibility of the predicate author to make every predicate make sense for
every event type; it is the responsibility of the predicate consumer to use
predicates that make sense for a particular event type registration.