リソース

resource は、アプリケーションに関係付けられたツリー上の「場所」 を表わすオブジェクトです。すべての Pyramid アプリケーションには 少なくとも 1 つのリソースオブジェクトがあります: root リソースです。 あなたが root リソースを手動で定義しなかったとしても、デフォルトの root リソースが自動的に作成されます。 root リソースは resource tree の根です。リソースツリーは入れ子の辞書風オブジェクトの集まりで、 ウェブサイトの構造を表わすために使用することができます。

URL をコードにマッピングするために traversal を使用するアプリ ケーションでは、リソースツリー構造は各 URL を view callable に マッピングするために頻繁に使用されます。 traversal が使用されて いる時、 Pyramidcontext リソースを見つけるために、 入れ子の辞書構造をトラバースすることによってリソースツリーを渡り歩きます。 コンテキストリソースが見つかれば、 view callable を見つける ためにコンテキストリソースとリクエスト中のデータが使用されます。

URL dispatch を使用するアプリケーションでは、リソースツリーは 間接的にのみ使用され、開発者からは多くの場合「見えないもの」です。 URL ディスパッチアプリケーションでは、リソース「ツリー」は、しばしば root リソース自身のみから構成されます。この root リソースには、セキュリティ 宣言が取り付けられることがありますが、常にそうすることは要求されません。 一般に、トラバーサルを使用するアプリケーションに比べて URL ディスパッチを 使用するアプリケーションにおいてリソースツリーはそれほど重要ではありません。

「Zope 風」の Pyramid アプリケーションではさらに、リソースオブジェクト はしばしばデータを永続的に格納します。そして、その永続的なデータを変化 させることに関係するメソッドを提供します。この種類のアプリケーションでは、 リソースはウェブサイトのサイト構造を表わすだけでなく、アプリケーションの domain model になります。

さらに、

  • add_view() (あるいは view_config() デコレータ) に対する context および containment 述語引数は、 リソースクラスまたはリソース interface を参照します。
  • リソースはビューの context として view コードに渡されます。
  • 種々の有用な Pyramid API メソッドは、引数としてリソースを期待します (例えば resource_url() など)。

リソースツリーを定義する

traversal が使用されている場合 (純粋に url dispatch に 基づいたアプリケーションとは対照的に)、 Pyramid はリソースから 構成されるツリー (resource tree)をトラバースできることを期待します。 トラバースは root リソースから始まり、別のリソースオブジェクトへのパス セグメントを解決するために各リソースの __getitem__ メソッドを試しながら、 ツリーを再帰的に下って行きます。 Pyramid はツリー上のリソース インスタンスに以下のポリシーを課します:

  • コンテナリソース (他のリソースを含むリソース) は、サブリソースへの unicode 名を解決するための __getitem__ メソッドを提供しなければ なりません。特定の名前のサブリソースがコンテナリソースに存在しない場合、 コンテナリソースの __getitem__ メソッドは KeyError を 投げげなければなりません。その名前のサブリソースが存在する場合、コンテナの __getitem__ はサブリソースを返す必要があります。
  • リーフリソース (他のリソースを含まないリソース) は __getitem__ を 実装してはなりません。あるいは、実装する場合 __getitem__ メソッドは 常に KeyError を上げなければなりません。

トラバーサルがリソースインスタンスに対してどのように動作するかについての 詳細は Traversal を参照してください。

これは root という名前の変数で表わされるサンプルのリソースツリーです:

1
2
3
4
 class Resource(dict):
     pass

 root = Resource({'a':Resource({'b':Resource({'c':Resource()})})})

上で作成したリソースツリーは、 'a' という名前の子供を持つ辞書風の root オブジェクトによって表わされます。 'a' は、 'b' という名前の 単一の子供を持っています。また、 'b''c' という名前の単一の子供を 持っています。 'c' は子供を持っていません。そのため、次のようにして 'c' リーフリソースにアクセスすることが可能です:

1
root['a']['b']['c']

もし root factory から上記の root オブジェクトを返せば、 パス /a/b/ctraversal の結果としてリソースツリー上に 'c' オブジェクトを見つけるでしょう。

この例において、ツリーの各々のリソースは同じクラスです。これは必須では ありません。ツリーのリソース要素は任意の型になることができます。私たちは、 単純性のためにツリーのすべてのリソースを表わすために単一のクラスを使用 しました。しかし、「実際の」アプリでは、ツリーのリソースは任意のクラスが 可能です。

上記のサンプルのツリーはトラバーサルを実行することができますが、上記の 例におけるリソースインスタンスは location aware ではありません。 したがって、「実際の」アプリケーションでの有用性は制限されています。 内蔵の Pyramid API 機能を最良に利用するために、リソースは 「location-aware (位置を意識)」すべきです。次のセクションは、リソースを location-aware にする方法を詳しく説明します。

location aware なリソース

適切な Pyramid ロケーション、セキュリティ、 URL 生成および トラバーサル API がリソースツリー上のリソースに対して適切に働くために、 ツリー上のすべてのリソースは location -aware である必要があります。 これは、それらのリソースが __parent____name__ という 2 つの 属性を持っている必要があるということを意味します。

location-aware なリソースの __parent__ 属性は、そのリソースのツリー 上の親リソースインスタンスへの参照でなければなりません。 __name__ 属性はリソースの親が __getitem__ によってそのリソースを参照する時の 名前でなければなりません。

root リソースの __parent__None でなければなりません。また、 その __name__ は空文字列でなければなりません。例えば:

1
2
3
class MyRootResource(object):
    __name__ = ''
    __parent__ = None

root リソースの __getitem__ メソッドから返されたリソースは、 root リソースへの参照である __parent__ 属性を持っていなければなりません。 また、その __name__ 属性は、 root リソースの __getitem__ によって 到達可能な名前と一致しなければなりません。 root リソース内のコンテナリ ソースは、コンテナを指す __parent__ 属性を備えたリソースを返す __getitem__ を持たなければなりません。また、これらのサブオブジェクトは、 __getitem__ によってコンテナから検索される名前と一致する __name__ 属性を持たなければなりません。このパターンは、 root から木を「上に」 再帰的に継続します。

各リソースの __parent__ 属性は、 root に向かって「下方へ」指すリンク リストを形成します。これはファイルシステムのディレクトリ中の .. エントリ と類似しています。リソースツリーの任意のリソースから __parent__ 値 を追って行けば、やがて root リソースに達するでしょう。ちょうど、ファイル システムコマンド cd .. を実行し続けるといずれファイルシステムのルート ディレクトリーに達するように。

Warning

root リソースが None または空文字列でない __name__ 引数を 持っていると、 resource_url() 関数に よって返された URLおよび resource_path()resource_path_tuple() API によって生成された パスは、不適当に生成されるでしょう。 __name__ の値は、生成された すべてのパスおよび URL に前置されます (単一の先頭のスラッシュあるいは 空のタプル要素とは対照的に)。

ツリーをたどるための Pyramid API を使用するアプリケーションは location-aware なリソースを必要とします。これらの API は、以下のもの を含んでいます (しかしこれだけに限りません): resource_url(), find_resource(), find_root(), find_interface(), resource_path(), resource_path_tuple(), あるいは traverse(), virtual_root(), そして (通常は) has_permission()principals_allowed_by_permission().

一般に、非常に多くの Pyramid 基盤が location-aware なリソースに 依存しているので、ツリーに含まれる各リソースを location-aware にすることは 良い考えです。

リソースの URL を生成する

リソースが location aware である場合、リソース用の URL を生成す るために pyramid.request.Request.resource_url() API を使用することが できます。この URL は、リソースパスを生成するためにリソースの親ツリー における位置を使用します。また、それは、スキーム、ホスト、ポートおよび パスを持つ完全修飾 URLを形成するためにパスの前に現在のアプリケーション URL を付けます。さらに、生成された URL に影響を及ぼすために追加の引数を resource_url() へ渡すことができます。

resource_url() への最も単純な呼び出しは このようになります:

1
url = request.resource_url(resource)

上記の例で requestPyramid request オブジェクトの インスタンスです。

上記の例で resource として参照されるリソースが root リソースで、 サーバにコンタクトするために使用されたホストが example.com だった場合、 生成される URL は http://example.com/ になります。しかし、もしリソースが a という名前の root リソースの子供なら、生成される URL は http://example.com/a/ になります。

resource_url() を使用してこの単純な方法で リソース URL を生成する場合、すべてのリソース URL にはスラッシュが追加 されます。なぜなら、リソースは階層における「場所」であり、 URL はそこを 訪れるためにクリックされるべきものだからです。リソースのデフォルトビュー の結果としてレンダリングされた HTML ページに含まれる相対 URL は、 その親に対してではなく、そのリソースに対して相対的であることが適切です。

さらに、追加の要素を resource_url() へ 渡すことができます:

1
url = request.resource_url(resource, 'foo', 'bar')

上記の例で resource として参照されるリソースが root リソースで、 サーバにコンタクトするために使用されたホストが example.com だった場合、 生成される URL は http://example.com/foo/bar になります。任意の数の追加 の要素を追加の位置引数として resource_url() に渡すことができます。追加の要素が渡された場合、それらはリソースの URL に追加されます。要素が渡された場合、最終セグメントにスラッシュは追加さ れません。

さらに、クエリ文字列を渡すこともできます:

1
url = request.resource_url(resource, query={'a':'1'})

上記の例で resource として参照されるリソースが root リソースで、 サーバにコンタクトするために使用されたホストが example.com だった場合、 生成される URL は http://example.com/?a=1 になります。

virtual root が有効な場合、 resource_url() によってリソースのために 生成された URL は、その物理的なツリーパスより「短い」ことがあります。 リソースの仮想的な root 変更についての詳細は Virtual Root Support を参照してください。

リソース URL の生成に関する詳細は pyramid.request.Request.resource_url() のドキュメンテーションを 参照してください。

リソース URL 生成のオーバーライド

リソースオブジェクトが __resource_url__ メソッドを実装していれば、 このリソース用に URL を生成するために resource_url() が呼ばれる時、 resource_url() によって返されるデフォルト URL をオーバーライドしてこのメソッドが呼ばれます。

__resource_url__ フックには requestinfo という 2 つの引数 が渡されます。 requestresource_url() に渡された request オブジェクトです。 info は 2 つのキーを持つ辞書です (訳注: 「3 つ」の間違い?):

physical_path

そのリソースのために計算された「物理的パス」を表わす文字列。 pyramid.traversal.resource_path(resource) によって定義されます。 スラッシュで始まりスラッシュで終わります。

virtual_path

そのリソースのために計算された「仮想的パス」を表わす文字列。 Virtual Root Support によって定義されます。 仮想 root 変更が有効でなければ、これは物理的パスと同一でしょう。 スラッシュで始まりスラッシュで終わります。

app_url

request.resource_url の中で生成されたアプリケーション URL を 表わす文字列。スラッシュで終わりません。これは、潜在的にカスタマイズ された URL 接頭辞を表し、ユーザによって request.resource_url に 渡されたカスタムなスキーム、ホストおよびポート情報を潜在的に含みます。 request.application_url よりもこちらを使用することが推奨されます。

リソースの __resource_url__ メソッドは、 URL を表わす文字列を返す 必要があります。デフォルトをオーバーライドできない場合 None を返すべきです。 このメソッドが None を返せば、デフォルト URL が返されるでしょう。

これはサンプルの __resource_url__ メソッドです。

1
2
3
class Resource(object):
    def __resource_url__(self, request, info):
        return info['app_url'] + info['virtual_path']

上記の例は、実際には単にデフォルトの URL を生成して返します。それは デフォルトの resource_url 機構によって生成されたはずのものです。 しかし、このコードは必要に応じて任意のロジックを実行できます。例えば、 あなたのコードでは、生成された URL のホスト名またはポート番号を無視 したいと思うかもしれません。

resource_url() とともに働くために、 __resource_url__ によって生成される URL は、完全修飾形式で、 スラッシュで終わり、クエリ文字列あるいはアンカー要素を含むべきでない (パス要素だけ)ということに注意してください。

リソースへのパスの生成

pyramid.traversal.resource_path() は、リソースツリー上の位置 に基づいてリソースオブジェクトの絶対的な物理的パスを表わす文字列オブジェクト を返します。パスのセグメントはそれぞれスラッシュ文字で分離されています。

1
2
from pyramid.traversal import resource_path
url = resource_path(resource)

もし上記の例で resource がツリー上で root['a']['b'] として アクセス可能ならば、上記の例は文字列 /a/b を生成するでしょう。

resource_path() に渡されたすべての位置引数も リソースパスの末端にパスセグメントとして追加されます。

1
2
from pyramid.traversal import resource_path
url = resource_path(resource, 'foo', 'bar')

もし上記の例で resource がツリー上で root['a']['b'] として アクセス可能なら、上記の例は文字列 /a/b/foo/bar を生成するでしょう。

渡されたリソースは location aware でなければなりません。

virtual root が存在するかどうかは resource_path() の振る舞いに影響を及ぼしません。

パスからリソースを見つける

リソースへの文字列パスを持っていれば、 pyramid.traversal.find_resource() を使ってアプリケーションの リソースツリー場所からリソースを取得することができます。

/ プリフィックスを持った文字列を path 引数として渡すことによって、 絶対パスを解決することができます:

1
2
from pyramid.traversal import find_resource
url = find_resource(anyresource, '/path')

あるいは、 / プリフィックスを持たない文字列を渡すことにより、 指定したリソースからの相対パスを解決することができます:

1
2
from pyramid.traversal import find_resource
url = find_resource(anyresource, 'path')

find_resource() に渡すパスはしばしば resource_path() API によって生成されます。 これらの API は互いの「鏡」です。

find_resource() を呼び出したときにパスを解決 できなければ (ツリー上のそれぞれのリソースが存在しなければ) 、 KeyError 例外が投げられます。

パスからリソースへの解決に関する詳細は pyramid.traversal.find_resource() ドキュメンテーションを参照して ください。

リソースの lineage の取得

pyramid.location.lineage() は、 location aware な resource オブジェクトの lineage (系統, 血統) を表わす ジェネレータを返します。

lineage() 関数は渡されたリソースを返し、その後 順番にリソースの親をそれぞれ返します。例えば、リソースツリーが以下の ように構成される場合:

1
2
3
4
5
class Thing(object): pass

thing1 = Thing()
thing2 = Thing()
thing2.__parent__ = thing1

lineage(thing2) の呼び出しはジェネレータを返します。それをリストに 変換すると、次のような結果を得るでしょう:

1
2
list(lineage(thing2))
[ <Thing object at thing2>, <Thing object at thing1> ]

lineage() によって返されたジェネレータは、最初に 渡されたリソースを無条件に返します。次に、そのリソースが __parent__ 属性を持っている場合、 resource.__parent__ によって 表わされるリソースを返します。もし その リソースが __parent__ 属性 を持っている場合、そのリソースの親を返します。検査されているリソースが __parent__ 属性を持たないか、 __parent__ 属性が None になる までこれが続きます。

詳細は、 pyramid.location.lineage() のドキュメンテーションを参照 してください。

リソースが別のリソースの lineage かどうかの判断

あるリソースが別のリソースの lineage であるかどうかを判断するには、 pyramid.location.inside() 関数を使用してください。

例えば、リソースツリーがこのような場合:

1
2
3
4
5
class Thing(object): pass

a = Thing()
b = Thing()
b.__parent__ = a

ba を含む lineage を持つので、 inside(b, a) の呼び出しは True を返すでしょう。しかし、 ab を含む lineage を持たない ので、 inside(a, b) の呼び出しは False を返すでしょう。

inside() の引数リストは (resource1, resource2) です。 resource2resource1lineage 祖先である場合、 resource1resource2 の inside です。その親 (あるいはその親の親などのうちの1つ) が祖先ならば、それは lineage 祖先です。

詳細は、 pyramid.location.inside() を参照してください。

root リソースを見つける

root リソースを見つけるためには pyramid.traversal.find_root() API を使用してください。この root リソースは resource tree の root リソースです。この API は単一 の引数 resource を受け取ります。 resourcelocation aware なリソースです。ツリー上で root を見つけたいと思う任意のリソースを渡す ことができます。

例えば、リソースツリーが次のような場合:

1
2
3
4
5
class Thing(object): pass

a = Thing()
b = Thing()
b.__parent__ = a

find_root(b) の呼び出しは a を返すでしょう。

root リソースは view callable コード内では request.root として もアクセス可能です。

virtual root の有無は find_root() の 振る舞いに影響を及ぼしません。返された root オブジェクトは常に 物理的な root オブジェクトです。

インタフェースを実装するリソース

リソースは任意で interface を実装するように作ることができます。 インタフェースはリソースオブジェクトに「型」を用いてタグ付けするために 使用されます。型は、その後 view configuration の内で参照することが でき、 pyramid.traversal.find_interface() によって参照されることがで きます。

view configuration ステートメント内の context または containment 述語引数としてクラスの代わりにインタフェースを指定する ことで、単一のビュー callable をリソースオブジェクトの複数のクラスに対して 使用することができます。これをしたい理由が分からないくらいにあなたの アプリケーションが単純な場合、このセクションを読むのをスキップできます。

例えば、これはブログエントリについて記述するコードで、ブログエントリが interface を実装すると宣言しています。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
import datetime
from zope.interface import implementer
from zope.interface import Interface

class IBlogEntry(Interface):
    pass

@implementer(IBlogEntry)
class BlogEntry(object):
    def __init__(self, title, body, author):
        self.title = title
        self.body = body
        self.author = author
        self.created = datetime.datetime.now()

このリソースは 2 つのものから構成されます: BlogEntry クラスという リソースコンストラクタを定義するクラスと、唯一の引数として IBlogEntry インタフェースを用いてクラスデコレータ implementer によってクラスに取り付けられた interface です。

使用されるインタフェースオブジェクトは zope.interface.Interface から継承するクラスのインスタンスでなければなりません。

リソースクラスは 0 個以上のインタフェースを実装することができます。 クラスデコレータとして zope.interface.implementer() 関数を使用する ことにより、リソースがインタフェースを実装することを明示します。 上記の BlogEntry リソースは IBlogEntry インタフェースを実装 しています。

さらに、クラスではなく特定のリソース インスタンス がインタフェースを 提供することを明示することもできます。クラスがインタフェースを実装する と宣言した場合、そのクラスのすべてのインスタンスもそのインタフェースを 提供するようになります。しかし、単一のオブジェクトがインタフェースを 提供すると単に言うこともできます。そのためには zope.interface.directlyProvides() 関数を使用してください:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
import datetime
from zope.interface import directlyProvides
from zope.interface import Interface

class IBlogEntry(Interface):
    pass

class BlogEntry(object):
    def __init__(self, title, body, author):
        self.title = title
        self.body = body
        self.author = author
        self.created = datetime.datetime.now()

entry = BlogEntry('title', 'body', 'author')
directlyProvides(entry, IBlogEntry)

zope.interface.directlyProvides() は、それ以前にインスタンスによって 提供されていた既存のあらゆるインタフェースを置き換えます。リソースオブジェクト が既にインスタンスレベルのインタフェース宣言をしていて置き換えたくない 場合は、 zope.interface.alsoProvides() 関数を使用してください:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
import datetime
from zope.interface import alsoProvides
from zope.interface import directlyProvides
from zope.interface import Interface

class IBlogEntry1(Interface):
    pass

class IBlogEntry2(Interface):
    pass

class BlogEntry(object):
    def __init__(self, title, body, author):
        self.title = title
        self.body = body
        self.author = author
        self.created = datetime.datetime.now()

entry = BlogEntry('title', 'body', 'author')
directlyProvides(entry, IBlogEntry1)
alsoProvides(entry, IBlogEntry2)

zope.interface.alsoProvides() は、 zope.interface.directlyProvides() のようにインスタンスによって 直接提供されるインタフェースの集合を上書きする代わりに、追加します。

ビュー設定でリソースインタフェースがどのように使用されるかについての 詳細は Using Resource Interfaces In View Configuration を参照してください。

クラスまたはインタフェースを使って lineage からリソースを見つける

特定の Python クラスの、あるいは特定の interface を実装する 親を見つけるには find_interface() API を 使用してください。

例えば、リソースツリーが以下のように構成される場合:

1
2
3
4
5
6
class Thing1(object): pass
class Thing2(object): pass

a = Thing1()
b = Thing2()
b.__parent__ = a

a がクラス Thing1 なので、 find_interface(a, Thing1) の呼び 出しは a リソースを返すでしょう (最初の引数として渡されたリソースが 最初に考慮され、クラスまたはインタフェースのスペックが一致する場合それが 返されます)。

a がクラス Thing1 で、 b の lineage の中で a がこのクラス の最初のリソースなので、 find_interface(b, Thing1) の呼び出しは a リソースを返すでしょう。

find_interface(b, Thing2) の呼び出しは b リソースを返すでしょう。

find_interface への第 2 引数は、クラスの代わりに interface を 使うことも可能です。これがインタフェースの場合、 lineage 中のそれぞれ のリソースが指定されたインタフェースを実装するかどうかチェックされます (リソースがあるクラスかどうか確かめる代わりに)。 インタフェースを実装するリソース も参照してください。

リソースに対して動作する Pyramid API 関数群

リソースオブジェクトはビューに提供される context として使用され ます。リソースオブジェクトがどのようにしてコンテキストになるかについて の詳細は TraversalURL Dispatch を参照 してください。

pyramid.traversal によって提供される API は、リソースオブジェクト に対して使用されます。これらの関数は、リソースの「パス」やリソースツリー の root リソースを見つけるために、あるいはリソース用の URL を生成するた めに使用することができます。

pyramid.location によって提供される API は、リソースに対して使用 されます。これらは、リソースツリーを下へたどるか、あるいは別のリソース の「内部」のリソースを簡単に見つけるために使用することができます。

pyramid.security 中のいくつかの API は、パラメータとしてリソース オブジェクトを受け取ります。例えば has_permission() API は引数の 1 つとしてリソース オブジェクトを受け取ります; ACL がこのリソースあるいはその先祖のうちの 1 つから得られます。 pyramid.security モジュール中の他の API も 引数として context を受け取ります。そしてコンテキストは常に リソースです。