summaryrefslogtreecommitdiff
path: root/docs/narr/hooks.rst
diff options
context:
space:
mode:
Diffstat (limited to 'docs/narr/hooks.rst')
-rw-r--r--docs/narr/hooks.rst668
1 files changed, 308 insertions, 360 deletions
diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst
index 006f5d5cb..2917b5254 100644
--- a/docs/narr/hooks.rst
+++ b/docs/narr/hooks.rst
@@ -3,8 +3,8 @@
Using Hooks
===========
-"Hooks" can be used to influence the behavior of the :app:`Pyramid`
-framework in various ways.
+"Hooks" can be used to influence the behavior of the :app:`Pyramid` framework
+in various ways.
.. index::
single: not found view
@@ -14,61 +14,38 @@ framework in various ways.
Changing the Not Found View
---------------------------
-When :app:`Pyramid` can't map a URL to view code, it invokes a
-:term:`not found view`, which is a :term:`view callable`. A default
-notfound view exists. The default not found view can be overridden
-through application configuration. This override can be done via
-:term:`imperative configuration` or :term:`ZCML`.
+When :app:`Pyramid` can't map a URL to view code, it invokes a :term:`not
+found view`, which is a :term:`view callable`. A default notfound view
+exists. The default not found view can be overridden through application
+configuration.
-The :term:`not found view` callable is a view callable like any other.
-The :term:`view configuration` which causes it to be a "not found"
-view consists only of naming the :exc:`pyramid.exceptions.NotFound`
-class as the ``context`` of the view configuration.
+The :term:`not found view` callable is a view callable like any other. The
+:term:`view configuration` which causes it to be a "not found" view consists
+only of naming the :exc:`pyramid.exceptions.NotFound` class as the
+``context`` of the view configuration.
-.. topic:: Using Imperative Configuration
+If your application uses :term:`imperative configuration`, you can replace
+the Not Found view by using the :meth:`pyramid.config.Configurator.add_view`
+method to register an "exception view":
- If your application uses :term:`imperative configuration`, you can
- replace the Not Found view by using the
- :meth:`pyramid.config.Configurator.add_view` method to
- register an "exception view":
-
- .. code-block:: python
- :linenos:
-
- from pyramid.exceptions import NotFound
- from helloworld.views import notfound_view
- config.add_view(notfound_view, context=NotFound)
-
- Replace ``helloworld.views.notfound_view`` with a reference to the
- Python :term:`view callable` you want to use to represent the Not
- Found view.
-
-.. topic:: Using ZCML
-
- If your application uses :term:`ZCML`, you can replace the Not Found
- view by placing something like the following ZCML in your
- ``configure.zcml`` file.
-
- .. code-block:: xml
- :linenos:
+.. code-block:: python
+ :linenos:
- <view
- view="helloworld.views.notfound_view"
- context="pyramid.exceptions.NotFound"
- />
+ from pyramid.exceptions import NotFound
+ from helloworld.views import notfound_view
+ config.add_view(notfound_view, context=NotFound)
- Replace ``helloworld.views.notfound_view`` with the Python dotted name
- to the notfound view you want to use.
+Replace ``helloworld.views.notfound_view`` with a reference to the
+:term:`view callable` you want to use to represent the Not Found view.
-Like any other view, the notfound view must accept at least a
-``request`` parameter, or both ``context`` and ``request``. The
-``request`` is the current :term:`request` representing the denied
-action. The ``context`` (if used in the call signature) will be the
-instance of the :exc:`pyramid.exceptions.NotFound` exception that
-caused the view to be called.
+Like any other view, the notfound view must accept at least a ``request``
+parameter, or both ``context`` and ``request``. The ``request`` is the
+current :term:`request` representing the denied action. The ``context`` (if
+used in the call signature) will be the instance of the
+:exc:`pyramid.exceptions.NotFound` exception that caused the view to be
+called.
-Here's some sample code that implements a minimal NotFound view
-callable:
+Here's some sample code that implements a minimal NotFound view callable:
.. code-block:: python
:linenos:
@@ -93,6 +70,9 @@ callable:
:exc:`pyramid.exceptions.NotFound` exception instance. If available, the
resource context will still be available as ``request.context``.
+For information about how to configure a not found view via :term:`ZCML`, see
+:ref:`notfound_zcml`.
+
.. index::
single: forbidden view
@@ -101,59 +81,36 @@ callable:
Changing the Forbidden View
---------------------------
-When :app:`Pyramid` can't authorize execution of a view based on
-the :term:`authorization policy` in use, it invokes a :term:`forbidden
-view`. The default forbidden response has a 401 status code and is
-very plain, but the view which generates it can be overridden as
-necessary using either :term:`imperative configuration` or
-:term:`ZCML`.
-
-The :term:`forbidden view` callable is a view callable like any other.
-The :term:`view configuration` which causes it to be a "not found"
-view consists only of naming the :exc:`pyramid.exceptions.Forbidden`
-class as the ``context`` of the view configuration.
-
-.. topic:: Using Imperative Configuration
-
- If your application uses :term:`imperative configuration`, you can
- replace the Forbidden view by using the
- :meth:`pyramid.config.Configurator.add_view` method to
- register an "exception view":
-
- .. code-block:: python
- :linenos:
-
- from helloworld.views import forbidden_view
- from pyramid.exceptions import Forbidden
- config.add_view(forbidden_view, context=Forbidden)
-
- Replace ``helloworld.views.forbidden_view`` with a reference to the
- Python :term:`view callable` you want to use to represent the
- Forbidden view.
+When :app:`Pyramid` can't authorize execution of a view based on the
+:term:`authorization policy` in use, it invokes a :term:`forbidden view`.
+The default forbidden response has a 401 status code and is very plain, but
+the view which generates it can be overridden as necessary.
-.. topic:: Using ZCML
+The :term:`forbidden view` callable is a view callable like any other. The
+:term:`view configuration` which causes it to be a "not found" view consists
+only of naming the :exc:`pyramid.exceptions.Forbidden` class as the
+``context`` of the view configuration.
- If your application uses :term:`ZCML`, you can replace the
- Forbidden view by placing something like the following ZCML in your
- ``configure.zcml`` file.
+You can replace the forbidden view by using the
+:meth:`pyramid.config.Configurator.add_view` method to register an "exception
+view":
- .. code-block:: xml
- :linenos:
+.. code-block:: python
+ :linenos:
- <view
- view="helloworld.views.notfound_view"
- context="pyramid.exceptions.Forbidden"
- />
+ from helloworld.views import forbidden_view
+ from pyramid.exceptions import Forbidden
+ config.add_view(forbidden_view, context=Forbidden)
- Replace ``helloworld.views.forbidden_view`` with the Python
- dotted name to the forbidden view you want to use.
+Replace ``helloworld.views.forbidden_view`` with a reference to the Python
+:term:`view callable` you want to use to represent the Forbidden view.
-Like any other view, the forbidden view must accept at least a
-``request`` parameter, or both ``context`` and ``request``. The
-``context`` (available as ``request.context`` if you're using the
-request-only view argument pattern) is the context found by the router
-when the view invocation was denied. The ``request`` is the current
-:term:`request` representing the denied action.
+Like any other view, the forbidden view must accept at least a ``request``
+parameter, or both ``context`` and ``request``. The ``context`` (available
+as ``request.context`` if you're using the request-only view argument
+pattern) is the context found by the router when the view invocation was
+denied. The ``request`` is the current :term:`request` representing the
+denied action.
Here's some sample code that implements a minimal forbidden view:
@@ -161,10 +118,10 @@ Here's some sample code that implements a minimal forbidden view:
:linenos:
from pyramid.views import view_config
+ from pyramid.response import Response
- @view_config(renderer='templates/login_form.pt')
def forbidden_view(request):
- return {}
+ return Response('forbidden')
.. note:: When a forbidden view callable is invoked, it is passed a
:term:`request`. The ``exception`` attribute of the request will
@@ -181,164 +138,26 @@ Here's some sample code that implements a minimal forbidden view:
an alternate forbidden view. For example, it would make sense to
return a response with a ``403 Forbidden`` status code.
-.. index::
- single: traverser
-
-.. _changing_the_traverser:
-
-Changing the Traverser
-----------------------
-
-The default :term:`traversal` algorithm that :app:`Pyramid` uses is
-explained in :ref:`traversal_algorithm`. Though it is rarely
-necessary, this default algorithm can be swapped out selectively for a
-different traversal pattern via configuration.
-
-Use an ``adapter`` stanza in your application's ``configure.zcml`` to
-change the default traverser:
-
-.. code-block:: xml
- :linenos:
-
- <adapter
- factory="myapp.traversal.Traverser"
- provides="pyramid.interfaces.ITraverser"
- for="*"
- />
-
-In the example above, ``myapp.traversal.Traverser`` is assumed to be
-a class that implements the following interface:
-
-.. code-block:: python
- :linenos:
-
- 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.
- """
-
-More than one traversal algorithm can be active at the same time. For
-instance, if your :term:`root factory` returns more than one type of
-object conditionally, you could claim that an alternate traverser
-adapter is ``for`` only one particular class or interface. When the
-root factory returned an object that implemented that class or
-interface, a custom traverser would be used. Otherwise, the default
-traverser would be used. For example:
-
-.. code-block:: xml
- :linenos:
-
- <adapter
- factory="myapp.traversal.Traverser"
- provides="pyramid.interfaces.ITraverser"
- for="myapp.resources.MyRoot"
- />
-
-If the above stanza was added to a ``configure.zcml`` file,
-:app:`Pyramid` would use the ``myapp.traversal.Traverser`` only
-when the application :term:`root factory` returned an instance of the
-``myapp.resources.MyRoot`` object. Otherwise it would use the default
-:app:`Pyramid` traverser to do traversal.
+For information about how to configure a forbidden view via :term:`ZCML`, see
+:ref:`forbidden_zcml`.
.. index::
- single: url generator
-
-Changing How :mod:`pyramid.url.resource_url` Generates a URL
-------------------------------------------------------------
-
-When you add a traverser as described in :ref:`changing_the_traverser`, it's
-often convenient to continue to use the :func:`pyramid.url.resource_url` API.
-However, since the way traversal is done will have been modified, the URLs it
-generates by default may be incorrect.
-
-If you've added a traverser, you can change how
-:func:`pyramid.url.resource_url` generates a URL for a specific type of
-resource by adding an adapter stanza for
-:class:`pyramid.interfaces.IContextURL` to your application's
-``configure.zcml``:
-
-.. code-block:: xml
- :linenos:
-
- <adapter
- factory="myapp.traversal.URLGenerator"
- provides="pyramid.interfaces.IContextURL"
- for="myapp.resources.MyRoot *"
- />
-
-In the above example, the ``myapp.traversal.URLGenerator`` class will
-be used to provide services to :func:`pyramid.url.resource_url` any
-time the :term:`context` passed to ``resource_url`` is of class
-``myapp.resources.MyRoot``. The asterisk following represents the type
-of interface that must be possessed by the :term:`request` (in this
-case, any interface, represented by asterisk).
-
-The API that must be implemented by a class that provides
-:class:`pyramid.interfaces.IContextURL` is as follows:
-
-.. code-block:: python
- :linenos:
-
- from zope.interface import Interface
-
- class IContextURL(Interface):
- """ An adapter which deals with URLs related to a context.
- """
- def __init__(self, context, request):
- """ Accept the context and request """
-
- def virtual_root(self):
- """ Return the virtual root object related to a request and the
- current context"""
-
- def __call__(self):
- """ Return a URL that points to the context """
-
-The default context URL generator is available for perusal as the
-class :class:`pyramid.traversal.TraversalContextURL` in the
-`traversal module
-<http://github.com/Pylons/pyramid/blob/master/pyramid/traversal.py>`_ of
-the :term:`Pylons` GitHub Pyramid repository.
+ single: request factory
.. _changing_the_request_factory:
Changing the Request Factory
----------------------------
-Whenever :app:`Pyramid` handles a :term:`WSGI` request, it creates
-a :term:`request` object based on the WSGI environment it has been
-passed. By default, an instance of the
-:class:`pyramid.request.Request` class is created to represent the
-request object.
+Whenever :app:`Pyramid` handles a :term:`WSGI` request, it creates a
+:term:`request` object based on the WSGI environment it has been passed. By
+default, an instance of the :class:`pyramid.request.Request` class is created
+to represent the request object.
-The class (aka "factory") that :app:`Pyramid` uses to create a
-request object instance can be changed by passing a
-``request_factory`` argument to the constructor of the
-:term:`configurator`. This argument can be either a callable or a
-:term:`dotted Python name` representing a callable.
+The class (aka "factory") that :app:`Pyramid` uses to create a request object
+instance can be changed by passing a ``request_factory`` argument to the
+constructor of the :term:`configurator`. This argument can be either a
+callable or a :term:`dotted Python name` representing a callable.
.. code-block:: python
:linenos:
@@ -350,24 +169,9 @@ request object instance can be changed by passing a
config = Configurator(request_factory=MyRequest)
-The same ``MyRequest`` class can alternately be registered via ZCML as
-a request factory through the use of the ZCML ``utility`` directive.
-In the below, we assume it lives in a package named
-``mypackage.mymodule``.
-
-.. code-block:: xml
- :linenos:
-
- <utility
- component="mypackage.mymodule.MyRequest"
- provides="pyramid.interfaces.IRequestFactory"
- />
-
-Lastly, if you're doing imperative configuration, and you'd rather do
-it after you've already constructed a :term:`configurator` it can also
-be registered via the
-:meth:`pyramid.config.Configurator.set_request_factory`
-method:
+If you're doing imperative configuration, and you'd rather do it after you've
+already constructed a :term:`configurator` it can also be registered via the
+:meth:`pyramid.config.Configurator.set_request_factory` method:
.. code-block:: python
:linenos:
@@ -381,26 +185,29 @@ method:
config = Configurator()
config.set_request_factory(MyRequest)
+To use ZCML for the same purpose, see :ref:`changing_request_factory_zcml`.
+
+.. index::
+ single: renderer globals
+
.. _adding_renderer_globals:
Adding Renderer Globals
-----------------------
-Whenever :app:`Pyramid` handles a request to perform a rendering
-(after a view with a ``renderer=`` configuration attribute is invoked,
-or when the any of the methods beginning with ``render`` within the
-:mod:`pyramid.renderers` module are called), *renderer globals* can
-be injected into the *system* values sent to the renderer. By
-default, no renderer globals are injected, and the "bare" system
-values (such as ``request``, ``context``, and ``renderer_name``) are
-the only values present in the system dictionary passed to every
-renderer.
-
-A callback that :app:`Pyramid` will call every time a renderer is
-invoked can be added by passing a ``renderer_globals_factory``
-argument to the constructor of the :term:`configurator`. This
-callback can either be a callable object or a :term:`dotted Python
-name` representing such a callable.
+Whenever :app:`Pyramid` handles a request to perform a rendering (after a
+view with a ``renderer=`` configuration attribute is invoked, or when the any
+of the methods beginning with ``render`` within the :mod:`pyramid.renderers`
+module are called), *renderer globals* can be injected into the *system*
+values sent to the renderer. By default, no renderer globals are injected,
+and the "bare" system values (such as ``request``, ``context``, and
+``renderer_name``) are the only values present in the system dictionary
+passed to every renderer.
+
+A callback that :app:`Pyramid` will call every time a renderer is invoked can
+be added by passing a ``renderer_globals_factory`` argument to the
+constructor of the :term:`configurator`. This callback can either be a
+callable object or a :term:`dotted Python name` representing such a callable.
.. code-block:: python
:linenos:
@@ -411,30 +218,15 @@ name` representing such a callable.
config = Configurator(
renderer_globals_factory=renderer_globals_factory)
-Such a callback must accept a single positional argument (notionally
-named ``system``) which will contain the original system values. It
-must return a dictionary of values that will be merged into the system
-dictionary. See :ref:`renderer_system_values` for discription of the
-values present in the system dictionary.
+Such a callback must accept a single positional argument (notionally named
+``system``) which will contain the original system values. It must return a
+dictionary of values that will be merged into the system dictionary. See
+:ref:`renderer_system_values` for discription of the values present in the
+system dictionary.
-A renderer globals factory can alternately be registered via ZCML as a
-through the use of the ZCML ``utility`` directive. In the below, we
-assume a ``renderers_globals_factory`` function lives in a package
-named ``mypackage.mymodule``.
-
-.. code-block:: xml
- :linenos:
-
- <utility
- component="mypackage.mymodule.renderer_globals_factory"
- provides="pyramid.interfaces.IRendererGlobalsFactory"
- />
-
-Lastly, if you're doing imperative configuration, and you'd rather do
-it after you've already constructed a :term:`configurator` it can also
-be registered via the
-:meth:`pyramid.config.Configurator.set_renderer_globals_factory`
-method:
+If you're doing imperative configuration, and you'd rather do it after you've
+already constructed a :term:`configurator` it can also be registered via the
+:meth:`pyramid.config.Configurator.set_renderer_globals_factory` method:
.. code-block:: python
:linenos:
@@ -450,6 +242,12 @@ method:
Another mechanism which allows event subscribers to add renderer global values
exists in :ref:`beforerender_event`.
+If you'd rather ZCML to register a renderer globals factory, see
+:ref:`adding_renderer_globals_zcml`.
+
+.. index::
+ single: before render event
+
.. _beforerender_event:
Using The Before Render Event
@@ -472,8 +270,8 @@ that can be used for this purpose. For example:
An object of this type is sent as an event just before a :term:`renderer` is
invoked (but *after* the application-level renderer globals factory added via
-:class:`pyramid.config.Configurator.set_renderer_globals_factory`, if
-any, has injected its own keys into the renderer globals dictionary).
+:class:`pyramid.config.Configurator.set_renderer_globals_factory`, if any,
+has injected its own keys into the renderer globals dictionary).
If a subscriber attempts to add a key that already exist in the renderer
globals dictionary, a :exc:`KeyError` is raised. This limitation is enforced
@@ -488,21 +286,24 @@ interface at :class:`pyramid.interfaces.IBeforeRender`.
Another mechanism which allows event subscribers more control when adding
renderer global values exists in :ref:`adding_renderer_globals`.
+.. index::
+ single: response callback
+
.. _using_response_callbacks:
Using Response Callbacks
------------------------
-Unlike many other web frameworks, :app:`Pyramid` does not eagerly
-create a global response object. Adding a :term:`response callback`
-allows an application to register an action to be performed against a
-response object once it is created, usually in order to mutate it.
+Unlike many other web frameworks, :app:`Pyramid` does not eagerly create a
+global response object. Adding a :term:`response callback` allows an
+application to register an action to be performed against a response object
+once it is created, usually in order to mutate it.
-The :meth:`pyramid.request.Request.add_response_callback` method is
-used to register a response callback.
+The :meth:`pyramid.request.Request.add_response_callback` method is used to
+register a response callback.
-A response callback is a callable which accepts two positional
-parameters: ``request`` and ``response``. For example:
+A response callback is a callable which accepts two positional parameters:
+``request`` and ``response``. For example:
.. code-block:: python
:linenos:
@@ -515,11 +316,11 @@ parameters: ``request`` and ``response``. For example:
No response callback is called if an unhandled exception happens in
application code, or if the response object returned by a :term:`view
-callable` is invalid. Response callbacks *are*, however, invoked when
-a :term:`exception view` is rendered successfully: in such a case, the
-:attr:`request.exception` attribute of the request when it enters a
-response callback will be an exception object instead of its default
-value of ``None``.
+callable` is invalid. Response callbacks *are*, however, invoked when a
+:term:`exception view` is rendered successfully: in such a case, the
+:attr:`request.exception` attribute of the request when it enters a response
+callback will be an exception object instead of its default value of
+``None``.
Response callbacks are called in the order they're added
(first-to-most-recently-added). All response callbacks are called *after*
@@ -532,18 +333,21 @@ response callback to happen as the result of *every* request, you must
re-register the callback into every new request (perhaps within a subscriber
of a :class:`pyramid.events.NewRequest` event).
+.. index::
+ single: finished callback
+
.. _using_finished_callbacks:
Using Finished Callbacks
------------------------
-A :term:`finished callback` is a function that will be called
-unconditionally by the :app:`Pyramid` :term:`router` at the very
-end of request processing. A finished callback can be used to perform
-an action at the end of a request unconditionally.
+A :term:`finished callback` is a function that will be called unconditionally
+by the :app:`Pyramid` :term:`router` at the very end of request processing.
+A finished callback can be used to perform an action at the end of a request
+unconditionally.
-The :meth:`pyramid.request.Request.add_finished_callback` method is
-used to register a finished callback.
+The :meth:`pyramid.request.Request.add_finished_callback` method is used to
+register a finished callback.
A finished callback is a callable which accepts a single positional
parameter: ``request``. For example:
@@ -563,25 +367,24 @@ parameter: ``request``. For example:
Finished callbacks are called in the order they're added ( first- to
most-recently- added). Finished callbacks (unlike a :term:`response
-callback`) are *always* called, even if an exception happens in
-application code that prevents a response from being generated.
-
-The set of finished callbacks associated with a request are called
-*very late* in the processing of that request; they are essentially
-the very last thing called by the :term:`router` before a request
-"ends". They are called after response processing has already occurred
-in a top-level ``finally:`` block within the router request processing
-code. As a result, mutations performed to the ``request`` provided to
-a finished callback will have no meaningful effect, because response
-processing will have already occurred, and the request's scope will
-expire almost immediately after all finished callbacks have been
-processed.
+callback`) are *always* called, even if an exception happens in application
+code that prevents a response from being generated.
+
+The set of finished callbacks associated with a request are called *very
+late* in the processing of that request; they are essentially the very last
+thing called by the :term:`router` before a request "ends". They are called
+after response processing has already occurred in a top-level ``finally:``
+block within the router request processing code. As a result, mutations
+performed to the ``request`` provided to a finished callback will have no
+meaningful effect, because response processing will have already occurred,
+and the request's scope will expire almost immediately after all finished
+callbacks have been processed.
It is often necessary to tell whether an exception occurred within
-:term:`view callable` code from within a finished callback: in such a
-case, the :attr:`request.exception` attribute of the request when it
-enters a response callback will be an exception object instead of its
-default value of ``None``.
+:term:`view callable` code from within a finished callback: in such a case,
+the :attr:`request.exception` attribute of the request when it enters a
+response callback will be an exception object instead of its default value of
+``None``.
Errors raised by finished callbacks are not handled specially. They
will be propagated to the caller of the :app:`Pyramid` router
@@ -592,28 +395,175 @@ finished callback to happen as the result of *every* request, you must
re-register the callback into every new request (perhaps within a subscriber
of a :class:`pyramid.events.NewRequest` event).
+.. index::
+ single: traverser
+
+.. _changing_the_traverser:
+
+Changing the Traverser
+----------------------
+
+The default :term:`traversal` algorithm that :app:`Pyramid` uses is explained
+in :ref:`traversal_algorithm`. Though it is rarely necessary, this default
+algorithm can be swapped out selectively for a different traversal pattern
+via configuration.
+
+.. code-block:: python
+ :linenos:
+
+ from pyramid.interfaces import ITraverser
+ from zope.interface import Interface
+ from myapp.traversal import Traverser
+
+ config.registry.registerAdapter(Traverser, (Interface,), ITraverser)
+
+In the example above, ``myapp.traversal.Traverser`` is assumed to be a class
+that implements the following interface:
+
+.. code-block:: python
+ :linenos:
+
+ 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.
+ """
+
+More than one traversal algorithm can be active at the same time. For
+instance, if your :term:`root factory` returns more than one type of object
+conditionally, you could claim that an alternate traverser adapter is ``for``
+only one particular class or interface. When the root factory returned an
+object that implemented that class or interface, a custom traverser would be
+used. Otherwise, the default traverser would be used. For example:
+
+.. code-block:: python
+ :linenos:
+
+ from pyramid.interfaces import ITraverser
+ from zope.interface import Interface
+ from myapp.traversal import Traverser
+ from myapp.resources import MyRoot
+
+ config.registry.registerAdapter(Traverser, (MyRoot,), ITraverser)
+
+If the above stanza was added to a Pyramid ``__init__.py`` file's ``main``
+function, :app:`Pyramid` would use the ``myapp.traversal.Traverser`` only
+when the application :term:`root factory` returned an instance of the
+``myapp.resources.MyRoot`` object. Otherwise it would use the default
+:app:`Pyramid` traverser to do traversal.
+
+For information about how to configure an alternate traverser via
+:term:`ZCML`, see :ref:`changing_traverser_zcml`.
+
+.. index::
+ single: url generator
+
+.. _changing_resource_url:
+
+Changing How :mod:`pyramid.url.resource_url` Generates a URL
+------------------------------------------------------------
+
+When you add a traverser as described in :ref:`changing_the_traverser`, it's
+often convenient to continue to use the :func:`pyramid.url.resource_url` API.
+However, since the way traversal is done will have been modified, the URLs it
+generates by default may be incorrect.
+
+If you've added a traverser, you can change how
+:func:`pyramid.url.resource_url` generates a URL for a specific type of
+resource by adding a registerAdapter call for
+:class:`pyramid.interfaces.IContextURL` to your application:
+
+.. code-block:: python
+ :linenos:
+
+ from pyramid.interfaces import ITraverser
+ from zope.interface import Interface
+ from myapp.traversal import URLGenerator
+ from myapp.resources import MyRoot
+
+ config.registry.registerAdapter(URLGenerator, (MyRoot, Interface),
+ IContextURL)
+
+In the above example, the ``myapp.traversal.URLGenerator`` class will be used
+to provide services to :func:`pyramid.url.resource_url` any time the
+:term:`context` passed to ``resource_url`` is of class
+``myapp.resources.MyRoot``. The second argument in the ``(MyRoot,
+Interface)`` tuple represents the type of interface that must be possessed by
+the :term:`request` (in this case, any interface, represented by
+``zope.interface.Interface``).
+
+The API that must be implemented by a class that provides
+:class:`pyramid.interfaces.IContextURL` is as follows:
+
+.. code-block:: python
+ :linenos:
+
+ from zope.interface import Interface
+
+ class IContextURL(Interface):
+ """ An adapter which deals with URLs related to a context.
+ """
+ def __init__(self, context, request):
+ """ Accept the context and request """
+
+ def virtual_root(self):
+ """ Return the virtual root object related to a request and the
+ current context"""
+
+ def __call__(self):
+ """ Return a URL that points to the context """
+
+The default context URL generator is available for perusal as the class
+:class:`pyramid.traversal.TraversalContextURL` in the `traversal module
+<http://github.com/Pylons/pyramid/blob/master/pyramid/traversal.py>`_ of the
+:term:`Pylons` GitHub Pyramid repository.
+
+.. index::
+ single: configuration decorator
+
.. _registering_configuration_decorators:
Registering Configuration Decorators
------------------------------------
Decorators such as :class:`pyramid.view.view_config` don't change the
-behavior of the functions or classes they're decorating. Instead,
-when a :term:`scan` is performed, a modified version of the function
-or class is registered with :app:`Pyramid`.
-
-You may wish to have your own decorators that offer such
-behaviour. This is possible by using the :term:`Venusian` package in
-the same way that it is used by :app:`Pyramid`.
-
-By way of example, let's suppose you want to write a decorator that
-registers the function it wraps with a :term:`Zope Component
-Architecture` "utility" within the :term:`application registry`
-provided by :app:`Pyramid`. The application registry and the
-utility inside the registry is likely only to be available once your
-application's configuration is at least partially completed. A normal
-decorator would fail as it would be executed before the configuration
-had even begun.
+behavior of the functions or classes they're decorating. Instead, when a
+:term:`scan` is performed, a modified version of the function or class is
+registered with :app:`Pyramid`.
+
+You may wish to have your own decorators that offer such behaviour. This is
+possible by using the :term:`Venusian` package in the same way that it is
+used by :app:`Pyramid`.
+
+By way of example, let's suppose you want to write a decorator that registers
+the function it wraps with a :term:`Zope Component Architecture` "utility"
+within the :term:`application registry` provided by :app:`Pyramid`. The
+application registry and the utility inside the registry is likely only to be
+available once your application's configuration is at least partially
+completed. A normal decorator would fail as it would be executed before the
+configuration had even begun.
However, using :term:`Venusian`, the decorator could be written as
follows:
@@ -671,10 +621,8 @@ performed, enabling you to set up the utility in advance:
if __name__ == '__main__':
config = Configurator()
- config.begin()
config.registry.registerUtility(UtilityImplementation())
config.scan()
- config.end()
app = config.make_wsgi_app()
serve(app, host='0.0.0.0')