Chris McDonough
2010-12-19 450006eb2493833ddfd3a0f623c3295f1e8a0e47
wording
1 files modified
275 ■■■■ changed files
docs/narr/traversal.rst 275 ●●●● patch | view | raw | blame | history
docs/narr/traversal.rst
@@ -3,10 +3,12 @@
Traversal
=========
:term:`Traversal` is a :term:`resource location` mechanism. It is the act of
finding a :term:`context` resource by walking over a :term:`resource tree`,
starting from a :term:`root` resource, using a :term:`request` object as a
source of path information.
:term:`Traversal` It provides an alternative to using :term:`URL dispatch` to
map a URL to a :term:`view callable`.  It is a :term:`resource location`
mechanism. It is the act of finding a :term:`context` resource by walking
over a :term:`resource tree`, starting from a :term:`root` resource, using a
:term:`request` object as a source of path information.  Once a context
resource is found, a view callable is looked up and invoked.
In this chapter, we'll provide a high-level overview of traversal, we'll
explain the concept of a resource tree, and we'll show how traversal might be
@@ -25,7 +27,7 @@
directories in a file system.  Traversal walks down the path until it finds a
published "directory" or "file".  The resource we find as the result of a
traversal becomes the :term:`context`.  A separate :term:`view lookup`
subsystem is used to then find some code willing "publish" the context
subsystem is used to then find some view code willing "publish" the context
resource.
.. index::
@@ -47,31 +49,30 @@
the sequence ``['a', 'b', 'c']``.
After the path info is converted, a lookup is performed against the resource
tree for each path segment.  Each lookup uses the ``__getitem__`` method of
a resource in the tree.
tree for each path segment.  Each lookup uses the ``__getitem__`` method of a
resource in the tree.
For example, if the path info sequence is ``['a', 'b', 'c']``:
- :term:`Traversal` pops the first element (``a``) from the path
  segment sequence and attempts to call the root resource's
  ``__getitem__`` method using that value (``a``) as an argument;
  we'll presume it succeeds.
- :term:`Traversal` pops the first element (``a``) from the path segment
  sequence and attempts to call the root resource's ``__getitem__`` method
  using that value (``a``) as an argument; we'll presume it succeeds.
- When the root resource's ``__getitem__`` succeeds it will return another
  resource, which we'll call "A".  The :term:`context` temporarily becomes
  the "A" resource.
- The next segment (``b``) is popped from the path sequence, and the
  "A" resource's ``__getitem__`` is called with that value (``b``) as an
- The next segment (``b``) is popped from the path sequence, and the "A"
  resource's ``__getitem__`` is called with that value (``b``) as an
  argument; we'll presume it succeeds.
- When the "A" resource's ``__getitem__`` succeeds it will return another
  resource, which we'll call "B".  The :term:`context` temporarily
  becomes the "B" resource.
  resource, which we'll call "B".  The :term:`context` temporarily becomes
  the "B" resource.
This process continues until the path segment sequence is exhausted or a
lookup for a path element fails.  In either case, a :term:`context` resouce
is found.
This process continues until the path segment sequence is exhausted or a path
element cannot be resolved to a resource.  In either case, a :term:`context`
resource is chosen.
Traversal "stops" when it either reaches a leaf level resource in your
resource tree or when the path segments implied by the URL "run out".  The
@@ -81,10 +82,10 @@
a :exc:`KeyError`, traversal ends immediately, and that resource becomes the
:term:`context`.
The results of a :term:`traversal` also include a :term:`view name`.
The :term:`view name` is the *first* URL path segment in the set of
``PATH_INFO`` segments "left over" in the path segment list popped by
the traversal process *after* traversal finds a context resource.
The results of a :term:`traversal` also include a :term:`view name`.  The
:term:`view name` is the *first* URL path segment in the set of ``PATH_INFO``
segments "left over" in the path segment list popped by the traversal process
*after* traversal finds a context resource.
The combination of the context resource and the :term:`view name` found via
traversal is used later in the same request by a separate :app:`Pyramid`
@@ -102,10 +103,11 @@
The Resource Tree
-----------------
When your application uses :term:`traversal` to resolve URLs to code, your
When your application uses :term:`traversal` to resolve URLs to code, the
application must supply a :term:`resource tree` to :app:`Pyramid`.  The
resource tree is a set of nested dictionary-like objects. The root of the
tree is represented by a :term:`root` resource.
tree is represented by a :term:`root` resource.  The tree is effectively a
nested set of dictionary-like objects.
In order to supply a root resource for an application, at system startup
time, the :app:`Pyramid` :term:`Router` is configured with a callback known
@@ -138,7 +140,7 @@
which refers to a root factory defined in a different module.
A root factory is passed a :term:`request` object and it is expected to
return a resource which represents the root of the resource tree.  All
return an object which represents the root of the resource tree.  All
:term:`traversal` will begin at this root resource.  Usually a root factory
for a traversal-based application will be more complicated than the above
``Root`` class; in particular it may be associated with a database connection
@@ -151,9 +153,9 @@
.. sidebar:: Emulating the Default Root Factory
   For purposes of understanding the default root factory better,
   we'll note that you can emulate the default root factory by using
   this code as an explicit root factory in your application setup:
   For purposes of understanding the default root factory better, we'll note
   that you can emulate the default root factory by using this code as an
   explicit root factory in your application setup:
   .. code-block:: python
      :linenos:
@@ -190,12 +192,11 @@
Each container resource is presumed to be willing to return a child resource
or raise a ``KeyError`` based on a name passed to its ``__getitem__``.
Leaf-level instances must not have a ``__getitem__``.  If
instances that you'd like to be leaves already happen to have a
``__getitem__`` through some historical inequity, you should subclass
these resource types and cause their ``__getitem__`` methods to simply
raise a ``KeyError``.  Or just disuse them and think up another
strategy.
Leaf-level instances must not have a ``__getitem__``.  If instances that
you'd like to be leaves already happen to have a ``__getitem__`` through some
historical inequity, you should subclass these resource types and cause their
``__getitem__`` methods to simply raise a ``KeyError``.  Or just disuse them
and think up another strategy.
Usually, the traversal root is a *container* resource, and as such it
contains other resources.  However, it doesn't *need* to be a container.
@@ -218,19 +219,17 @@
The Traversal Algorithm
-----------------------
This section will attempt to explain the :app:`Pyramid` traversal
algorithm.  We'll provide a description of the algorithm, a diagram of
how the algorithm works, and some example traversal scenarios that
might help you understand how the algorithm operates against a
specific resource tree.
This section will attempt to explain the :app:`Pyramid` traversal algorithm.
We'll provide a description of the algorithm, a diagram of how the algorithm
works, and some example traversal scenarios that might help you understand
how the algorithm operates against a specific resource tree.
We'll also talk a bit about :term:`view lookup`.  The
:ref:`views_chapter` chapter discusses :term:`view lookup` in detail,
and it is the canonical source for information about views.
Technically, :term:`view lookup` is a :app:`Pyramid` subsystem that
is separated from traversal entirely.  However, we'll describe the
fundamental behavior of view lookup in the examples in the next few
sections to give you an idea of how traversal and view lookup
We'll also talk a bit about :term:`view lookup`.  The :ref:`views_chapter`
chapter discusses :term:`view lookup` in detail, and it is the canonical
source for information about views.  Technically, :term:`view lookup` is a
:app:`Pyramid` subsystem that is separated from traversal entirely.  However,
we'll describe the fundamental behavior of view lookup in the examples in the
next few sections to give you an idea of how traversal and view lookup
cooperate, because they are almost always used together.
.. index::
@@ -243,25 +242,24 @@
A Description of The Traversal Algorithm
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
When a user requests a page from your :mod:`traversal` -powered
application, the system uses this algorithm to find a :term:`context`
and a :term:`view name`.
When a user requests a page from your :mod:`traversal` -powered application,
the system uses this algorithm to find a :term:`context` resource and a
:term:`view name`.
#.  The request for the page is presented to the :app:`Pyramid`
    :term:`router` in terms of a standard :term:`WSGI` request, which
    is represented by a WSGI environment and a WSGI ``start_response``
    callable.
    :term:`router` in terms of a standard :term:`WSGI` request, which is
    represented by a WSGI environment and a WSGI ``start_response`` callable.
#.  The router creates a :term:`request` object based on the WSGI
    environment.
#.  The :term:`root factory` is called with the :term:`request`.  It
    returns a :term:`root` resource.
#.  The :term:`root factory` is called with the :term:`request`.  It returns
    a :term:`root` resource.
#.  The router uses the WSGI environment's ``PATH_INFO`` information
    to determine the path segments to traverse.  The leading slash is
    stripped off ``PATH_INFO``, and the remaining path segments are
    split on the slash character to form a traversal sequence.
#.  The router uses the WSGI environment's ``PATH_INFO`` information to
    determine the path segments to traverse.  The leading slash is stripped
    off ``PATH_INFO``, and the remaining path segments are split on the slash
    character to form a traversal sequence.
    The traversal algorithm by default attempts to first URL-unquote and then
    Unicode-decode each path segment derived from ``PATH_INFO`` from its
@@ -273,18 +271,18 @@
    segment will be fully URL-unquoted and UTF8-decoded before it is passed
    it to the ``__getitem__`` of any resource during traversal.
    Thus, a request with a ``PATH_INFO`` variable of ``/a/b/c`` maps
    to the traversal sequence ``[u'a', u'b', u'c']``.
    Thus, a request with a ``PATH_INFO`` variable of ``/a/b/c`` maps to the
    traversal sequence ``[u'a', u'b', u'c']``.
#.  :term:`Traversal` begins at the root resource returned by the root
    factory.  For the traversal sequence ``[u'a', u'b', u'c']``, the root
    resource's ``__getitem__`` is called with the name ``a``.  Traversal
    continues through the sequence.  In our example, if the root resource's
    ``__getitem__`` called with the name ``a`` returns a resource (aka
    "resource ``a``"), that resource's ``__getitem__`` is called with the name
    ``b``.  If resource A returns a resource when asked for ``b``, "resource
    ``b``"'s ``__getitem__`` is then asked for the name ``c``, and may return
    "resource ``c``".
    "resource ``a``"), that resource's ``__getitem__`` is called with the
    name ``b``.  If resource A returns a resource when asked for ``b``,
    "resource ``b``"'s ``__getitem__`` is then asked for the name ``c``, and
    may return "resource ``c``".
#.  Traversal ends when a) the entire path is exhausted or b) when any
    resouce raises a :exc:`KeyError` from its ``__getitem__`` or c) when any
@@ -293,33 +291,31 @@
    with the set of characters ``@@`` (indicating that the characters
    following the ``@@`` token should be treated as a :term:`view name`).
#.  When traversal ends for any of the reasons in the previous step,
    the last resource found during traversal is deemed to be the
    :term:`context`.  If the path has been exhausted when traversal
    ends, the :term:`view name` is deemed to be the empty string
    (``''``).  However, if the path was *not* exhausted before
    traversal terminated, the first remaining path segment is treated
    as the view name.
#.  When traversal ends for any of the reasons in the previous step, the last
    resource found during traversal is deemed to be the :term:`context`.  If
    the path has been exhausted when traversal ends, the :term:`view name` is
    deemed to be the empty string (``''``).  However, if the path was *not*
    exhausted before traversal terminated, the first remaining path segment
    is treated as the view name.
#.  Any subsequent path elements after the :term:`view name` is found
    are deemed the :term:`subpath`.  The subpath is always a sequence
    of path segments that come from ``PATH_INFO`` that are "left over"
    after traversal has completed.
#.  Any subsequent path elements after the :term:`view name` is found are
    deemed the :term:`subpath`.  The subpath is always a sequence of path
    segments that come from ``PATH_INFO`` that are "left over" after
    traversal has completed.
Once :term:`context`, :term:`view name`, and associated attributes
such as the :term:`subpath` are located, the job of :term:`traversal`
is finished.  It passes back the information it obtained to its
caller, the :app:`Pyramid` :term:`Router`, which subsequently
invokes :term:`view lookup` with the context and view name
information.
Once the :term:`context` resource, the :term:`view name`, and associated
attributes such as the :term:`subpath` are located, the job of
:term:`traversal` is finished.  It passes back the information it obtained to
its caller, the :app:`Pyramid` :term:`Router`, which subsequently invokes
:term:`view lookup` with the context and view name information.
The traversal algorithm exposes two special cases:
- You will often end up with a :term:`view name` that is the empty
  string as the result of a particular traversal.  This indicates that
  the view lookup machinery should look up the :term:`default view`.
  The default view is a view that is registered with no name or a view
  which is registered with a name that equals the empty string.
- You will often end up with a :term:`view name` that is the empty string as
  the result of a particular traversal.  This indicates that the view lookup
  machinery should look up the :term:`default view`.  The default view is a
  view that is registered with no name or a view which is registered with a
  name that equals the empty string.
- If any path segment element begins with the special characters ``@@``
  (think of them as goggles), the value of that segment minus the goggle
@@ -327,10 +323,10 @@
  stops there.  This allows you to address views that may have the same names
  as resource names in the tree unambiguously.
Finally, traversal is responsible for locating a :term:`virtual root`.
A virtual root is used during "virtual hosting"; see the
:ref:`vhosting_chapter` chapter for information.  We won't speak more
about it in this chapter.
Finally, traversal is responsible for locating a :term:`virtual root`.  A
virtual root is used during "virtual hosting"; see the
:ref:`vhosting_chapter` chapter for information.  We won't speak more about
it in this chapter.
.. image:: resourcetreetraverser.png
@@ -340,15 +336,14 @@
Traversal Algorithm Examples
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
No one can be expected to understand the traversal algorithm by
analogy and description alone, so let's examine some traversal
scenarios that use concrete URLs and resource tree compositions.
No one can be expected to understand the traversal algorithm by analogy and
description alone, so let's examine some traversal scenarios that use
concrete URLs and resource tree compositions.
Let's pretend the user asks for
``http://example.com/foo/bar/baz/biz/buz.txt``. The request's
``PATH_INFO`` in that case is ``/foo/bar/baz/biz/buz.txt``.  Let's
further pretend that when this request comes in that we're traversing
the following resource tree:
``http://example.com/foo/bar/baz/biz/buz.txt``. The request's ``PATH_INFO``
in that case is ``/foo/bar/baz/biz/buz.txt``.  Let's further pretend that
when this request comes in that we're traversing the following resource tree:
.. code-block:: text
@@ -360,20 +355,21 @@
Here's what happens:
- :mod:`traversal` traverses the root, and attempts to find "foo",
  which it finds.
- :mod:`traversal` traverses the root, and attempts to find "foo", which it
  finds.
- :mod:`traversal` traverses "foo", and attempts to find "bar", which
  it finds.
- :mod:`traversal` traverses "foo", and attempts to find "bar", which it
  finds.
- :mod:`traversal` traverses bar, and attempts to find "baz", which it
  does not find ("bar" raises a :exc:`KeyError` when asked for "baz").
- :mod:`traversal` traverses bar, and attempts to find "baz", which it does
  not find (the "bar" resource raises a :exc:`KeyError` when asked for
  "baz").
The fact that it does not find "baz" at this point does not signify an
error condition.  It signifies that:
The fact that it does not find "baz" at this point does not signify an error
condition.  It signifies that:
- the :term:`context` is "bar" (the context is the last resource found
  during traversal).
- the :term:`context` is the "bar" resource (the context is the last resource
  found during traversal).
- the :term:`view name` is ``baz``
@@ -387,13 +383,12 @@
Using the :term:`view name` (``baz``) and the type, view lookup asks the
:term:`application registry` this question:
- Please find me a :term:`view callable` registered using a
  :term:`view configuration` with the name "baz" that can be used for
  the class ``Bar``.
- Please find me a :term:`view callable` registered using a :term:`view
  configuration` with the name "baz" that can be used for the class ``Bar``.
Let's say that view lookup finds no matching view type.  In this
circumstance, the :app:`Pyramid` :term:`router` returns the result
of the :term:`not found view` and the request ends.
circumstance, the :app:`Pyramid` :term:`router` returns the result of the
:term:`not found view` and the request ends.
However, for this tree:
@@ -411,23 +406,23 @@
The user asks for ``http://example.com/foo/bar/baz/biz/buz.txt``
- :mod:`traversal` traverses "foo", and attempts to find "bar", which
  it finds.
- :mod:`traversal` traverses "foo", and attempts to find "bar", which it
  finds.
- :mod:`traversal` traverses "bar", and attempts to find "baz", which
  it finds.
- :mod:`traversal` traverses "bar", and attempts to find "baz", which it
  finds.
- :mod:`traversal` traverses "baz", and attempts to find "biz", which
  it finds.
- :mod:`traversal` traverses "baz", and attempts to find "biz", which it
  finds.
- :mod:`traversal` traverses "biz", and attempts to find "buz.txt"
  which it does not find.
- :mod:`traversal` traverses "biz", and attempts to find "buz.txt" which it
  does not find.
The fact that it does not find "buz.txt" at this point does not
signify an error condition.  It signifies that:
The fact that it does not find a resource related to "buz.txt" at this point
does not signify an error condition.  It signifies that:
- the :term:`context` is "biz" (the context is the last resource found
  during traversal).
- the :term:`context` is the "biz" resource (the context is the last resource
  found during traversal).
- the :term:`view name` is "buz.txt"
@@ -435,21 +430,20 @@
At this point, traversal has ended, and :term:`view lookup` begins.
Because it's the "context" resource, the view lookup machinery examines "biz"
to find out what "type" it is. Let's say it finds that the context is a
``Biz`` type (because "biz" is an instance of the Python class ``Biz``).
Using the :term:`view name` (``buz.txt``) and the type, view lookup asks the
:term:`application registry` this question:
Because it's the "context" resource, the view lookup machinery examines the
"biz" resource to find out what "type" it is. Let's say it finds that the
resource is a ``Biz`` type (because "biz" is an instance of the Python class
``Biz``).  Using the :term:`view name` (``buz.txt``) and the type, view
lookup asks the :term:`application registry` this question:
- Please find me a :term:`view callable` registered with a :term:`view
  configuration` with the name ``buz.txt`` that can be used for class
  ``Biz``.
Let's say that question is answered by the application registry; in
such a situation, the application registry returns a :term:`view
callable`.  The view callable is then called with the current
:term:`WebOb` :term:`request` as the sole argument: ``request``; it is
expected to return a response.
Let's say that question is answered by the application registry; in such a
situation, the application registry returns a :term:`view callable`.  The
view callable is then called with the current :term:`WebOb` :term:`request`
as the sole argument: ``request``; it is expected to return a response.
.. sidebar:: The Example View Callables Accept Only a Request; How Do I Access the Context Resource?
@@ -471,16 +465,15 @@
References
----------
A tutorial showing how :term:`traversal` can be used within a
:app:`Pyramid` application exists in :ref:`bfg_wiki_tutorial`.
A tutorial showing how :term:`traversal` can be used within a :app:`Pyramid`
application exists in :ref:`bfg_wiki_tutorial`.
See the :ref:`views_chapter` chapter for detailed information about
:term:`view lookup`.
The :mod:`pyramid.traversal` module contains API functions that
deal with traversal, such as traversal invocation from within
application code.
The :mod:`pyramid.traversal` module contains API functions that deal with
traversal, such as traversal invocation from within application code.
The :func:`pyramid.url.resource_url` function generates a URL when
given a resource retrieved from a resource tree.
The :func:`pyramid.url.resource_url` function generates a URL when given a
resource retrieved from a resource tree.