| | |
| | | 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`. The default Not Found View |
| | | can be overridden through application configuration. |
| | | When :app:`Pyramid` can't map a URL to view code, it invokes a :term:`Not Found |
| | | View`, which is a :term:`view callable`. The default Not Found View can be |
| | | overridden through application configuration. |
| | | |
| | | If your application uses :term:`imperative configuration`, you can replace |
| | | the Not Found View by using the |
| | | If your application uses :term:`imperative configuration`, you can replace the |
| | | Not Found View by using the |
| | | :meth:`pyramid.config.Configurator.add_notfound_view` method: |
| | | |
| | | .. code-block:: python |
| | |
| | | config = Configurator() |
| | | config.scan() |
| | | |
| | | The ``notfound_get`` view will be called when a view could not be found and |
| | | the request method was ``GET``. The ``notfound_post`` view will be called |
| | | when a view could not be found and the request method was ``POST``. |
| | | The ``notfound_get`` view will be called when a view could not be found and the |
| | | request method was ``GET``. The ``notfound_post`` view will be called when a |
| | | view could not be found and the request method was ``POST``. |
| | | |
| | | Like any other view, the Not Found 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 |
| | | 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.httpexceptions.HTTPNotFound` exception that caused the view to |
| | | be called. |
| | | |
| | |
| | | |
| | | .. note:: |
| | | |
| | | When a Not Found View callable is invoked, it is passed a |
| | | :term:`request`. The ``exception`` attribute of the request will be an |
| | | instance of the :exc:`~pyramid.httpexceptions.HTTPNotFound` exception that |
| | | caused the Not Found View to be called. The value of |
| | | ``request.exception.message`` will be a value explaining why the Not Found |
| | | error was raised. This message has different values depending whether the |
| | | ``pyramid.debug_notfound`` environment setting is true or false. |
| | | When a Not Found View callable is invoked, it is passed a :term:`request`. |
| | | The ``exception`` attribute of the request will be an instance of the |
| | | :exc:`~pyramid.httpexceptions.HTTPNotFound` exception that caused the Not |
| | | Found View to be called. The value of ``request.exception.message`` will be |
| | | a value explaining why the Not Found exception was raised. This message has |
| | | different values depending on whether the ``pyramid.debug_notfound`` |
| | | environment setting is true or false. |
| | | |
| | | .. note:: |
| | | |
| | |
| | | |
| | | .. warning:: |
| | | |
| | | When a Not Found View callable accepts an argument list as |
| | | described in :ref:`request_and_context_view_definitions`, the ``context`` |
| | | passed as the first argument to the view callable will be the |
| | | When a Not Found View callable accepts an argument list as described in |
| | | :ref:`request_and_context_view_definitions`, the ``context`` passed as the |
| | | first argument to the view callable will be the |
| | | :exc:`~pyramid.httpexceptions.HTTPNotFound` exception instance. If |
| | | available, the resource context will still be available as |
| | | ``request.context``. |
| | |
| | | --------------------------- |
| | | |
| | | 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 403 status code and is very plain, but |
| | | the view which generates it can be overridden as necessary. |
| | | :term:`authorization policy` in use, it invokes a :term:`forbidden view`. The |
| | | default forbidden response has a 403 status code and is very plain, but the |
| | | view which generates it can be overridden as necessary. |
| | | |
| | | The :term:`forbidden view` callable is a view callable like any other. The |
| | | :term:`view configuration` which causes it to be a "forbidden" view consists |
| | | of using the :meth:`pyramid.config.Configurator.add_forbidden_view` API or the |
| | | :term:`view configuration` which causes it to be a "forbidden" view consists of |
| | | using the :meth:`pyramid.config.Configurator.add_forbidden_view` API or the |
| | | :class:`pyramid.view.forbidden_view_config` decorator. |
| | | |
| | | For example, you can add a forbidden view by using the |
| | |
| | | config.scan() |
| | | |
| | | Like any other view, the forbidden view must accept at least a ``request`` |
| | | parameter, or both ``context`` and ``request``. If a forbidden view |
| | | callable accepts both ``context`` and ``request``, the HTTP Exception is passed |
| | | as context. The ``context`` as found by the router when view was |
| | | denied (that you normally would expect) is available as |
| | | ``request.context``. The ``request`` is the current :term:`request` |
| | | representing the denied action. |
| | | |
| | | |
| | | parameter, or both ``context`` and ``request``. If a forbidden view callable |
| | | accepts both ``context`` and ``request``, the HTTP Exception is passed as |
| | | context. The ``context`` as found by the router when the view was denied (which |
| | | you normally would expect) is available as ``request.context``. The |
| | | ``request`` is the current :term:`request` representing the denied action. |
| | | |
| | | Here's some sample code that implements a minimal forbidden view: |
| | | |
| | |
| | | |
| | | .. note:: |
| | | |
| | | When a forbidden view callable is invoked, it is passed a |
| | | :term:`request`. The ``exception`` attribute of the request will be an |
| | | instance of the :exc:`~pyramid.httpexceptions.HTTPForbidden` exception |
| | | that caused the forbidden view to be called. The value of |
| | | ``request.exception.message`` will be a value explaining why the forbidden |
| | | was raised and ``request.exception.result`` will be extended information |
| | | about the forbidden exception. These messages have different values |
| | | depending whether the ``pyramid.debug_authorization`` environment setting |
| | | is true or false. |
| | | When a forbidden view callable is invoked, it is passed a :term:`request`. |
| | | The ``exception`` attribute of the request will be an instance of the |
| | | :exc:`~pyramid.httpexceptions.HTTPForbidden` exception that caused the |
| | | forbidden view to be called. The value of ``request.exception.message`` |
| | | will be a value explaining why the forbidden exception was raised, and |
| | | ``request.exception.result`` will be extended information about the |
| | | forbidden exception. These messages have different values depending on |
| | | whether the ``pyramid.debug_authorization`` environment setting is true or |
| | | false. |
| | | |
| | | .. index:: |
| | | single: request factory |
| | |
| | | |
| | | Whenever :app:`Pyramid` handles a request from a :term:`WSGI` server, 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. |
| | | 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 |
| | | The class (a.k.a., "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. |
| | | |
| | |
| | | config = Configurator(request_factory=MyRequest) |
| | | |
| | | 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 |
| | | already constructed a :term:`configurator`, it can also be registered via the |
| | | :meth:`pyramid.config.Configurator.set_request_factory` method: |
| | | |
| | | .. code-block:: python |
| | |
| | | |
| | | .. _adding_request_method: |
| | | |
| | | Adding Methods or Properties to Request Object |
| | | ---------------------------------------------- |
| | | Adding Methods or Properties to a Request Object |
| | | ------------------------------------------------ |
| | | |
| | | .. versionadded:: 1.4. |
| | | |
| | | Since each Pyramid application can only have one :term:`request` factory, |
| | | :ref:`changing the request factory <changing_the_request_factory>` |
| | | is not that extensible, especially if you want to build composable features |
| | | (e.g., Pyramid add-ons and plugins). |
| | | :ref:`changing the request factory <changing_the_request_factory>` is not that |
| | | extensible, especially if you want to build composable features (e.g., Pyramid |
| | | add-ons and plugins). |
| | | |
| | | A lazy property can be registered to the request object via the |
| | | :meth:`pyramid.config.Configurator.add_request_method` API. This allows you |
| | | to specify a callable that will be available on the request object, but will not |
| | | :meth:`pyramid.config.Configurator.add_request_method` API. This allows you to |
| | | specify a callable that will be available on the request object, but will not |
| | | actually execute the function until accessed. |
| | | |
| | | .. warning:: |
| | |
| | | config.add_request_method(total) |
| | | config.add_request_method(prop, reify=True) |
| | | |
| | | In the above example, ``total`` is added as a method. However, ``prop`` is added |
| | | as a property and its result is cached per-request by setting ``reify=True``. |
| | | This way, we eliminate the overhead of running the function multiple times. |
| | | In the above example, ``total`` is added as a method. However, ``prop`` is |
| | | added as a property and its result is cached per-request by setting |
| | | ``reify=True``. This way, we eliminate the overhead of running the function |
| | | multiple times. |
| | | |
| | | >>> request.total(1, 2, 3) |
| | | 6 |
| | |
| | | .. _changing_the_response_factory: |
| | | |
| | | Changing the Response Factory |
| | | ------------------------------- |
| | | ----------------------------- |
| | | |
| | | .. versionadded:: 1.6 |
| | | |
| | | Whenever :app:`Pyramid` returns a response from a view it creates a |
| | | Whenever :app:`Pyramid` returns a response from a view, it creates a |
| | | :term:`response` object. By default, an instance of the |
| | | :class:`pyramid.response.Response` class is created to represent the response |
| | | object. |
| | | |
| | | The factory that :app:`Pyramid` uses to create a response object instance can be |
| | | changed by passing a :class:`pyramid.interfaces.IResponseFactory` argument to |
| | | the constructor of the :term:`configurator`. This argument can be either a |
| | | The factory that :app:`Pyramid` uses to create a response object instance can |
| | | be changed by passing a :class:`pyramid.interfaces.IResponseFactory` 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 factory takes a single positional argument, which is a :term:`Request` |
| | |
| | | |
| | | config = Configurator(response_factory=lambda r: MyResponse()) |
| | | |
| | | 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 |
| | | 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_response_factory` method: |
| | | |
| | | .. code-block:: python |
| | |
| | | |
| | | .. _beforerender_event: |
| | | |
| | | Using The Before Render Event |
| | | Using the Before Render Event |
| | | ----------------------------- |
| | | |
| | | Subscribers to the :class:`pyramid.events.BeforeRender` event may introspect |
| | | and modify the set of :term:`renderer globals` before they are passed to a |
| | | :term:`renderer`. This event object iself has a dictionary-like interface |
| | | that can be used for this purpose. For example: |
| | | :term:`renderer`. This event object iself has a dictionary-like interface that |
| | | can be used for this purpose. For example: |
| | | |
| | | .. code-block:: python |
| | | :linenos: |
| | |
| | | def add_global(event): |
| | | event['mykey'] = 'foo' |
| | | |
| | | An object of this type is sent as an event just before a :term:`renderer` |
| | | is invoked. |
| | | An object of this type is sent as an event just before a :term:`renderer` is |
| | | invoked. |
| | | |
| | | If a subscriber attempts to add a key that already exist in the renderer |
| | | If a subscriber attempts to add a key that already exists in the renderer |
| | | globals dictionary, a :exc:`KeyError` is raised. This limitation is enforced |
| | | because event subscribers do not possess any relative ordering. The set of |
| | | keys added to the renderer globals dictionary by all |
| | | :class:`pyramid.events.BeforeRender` subscribers and renderer globals |
| | | factories must be unique. |
| | | :class:`pyramid.events.BeforeRender` subscribers and renderer globals factories |
| | | must be unique. |
| | | |
| | | The dictionary returned from the view is accessible through the |
| | | :attr:`rendering_val` attribute of a :class:`~pyramid.events.BeforeRender` |
| | | event. |
| | | |
| | | Suppose you return ``{'mykey': 'somevalue', 'mykey2': 'somevalue2'}`` from |
| | | your view callable, like so: |
| | | Suppose you return ``{'mykey': 'somevalue', 'mykey2': 'somevalue2'}`` from your |
| | | view callable, like so: |
| | | |
| | | .. code-block:: python |
| | | :linenos: |
| | |
| | | response.cache_control.max_age = 360 |
| | | request.add_response_callback(cache_callback) |
| | | |
| | | 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``. |
| | | 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``. |
| | | |
| | | Response callbacks are called in the order they're added |
| | | (first-to-most-recently-added). All response callbacks are called *before* |
| | | the :class:`~pyramid.events.NewResponse` event is sent. Errors raised by |
| | | response callbacks are not handled specially. They will be propagated to the |
| | | caller of the :app:`Pyramid` router application. |
| | | (first-to-most-recently-added). All response callbacks are called *before* the |
| | | :class:`~pyramid.events.NewResponse` event is sent. Errors raised by response |
| | | callbacks are not handled specially. They will be propagated to the caller of |
| | | the :app:`Pyramid` router application. |
| | | |
| | | A response callback has a lifetime of a *single* request. If you want a |
| | | 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). |
| | | re-register the callback into every new request (perhaps within a subscriber of |
| | | a :class:`~pyramid.events.NewRequest` event). |
| | | |
| | | .. index:: |
| | | single: finished callback |
| | |
| | | ------------------------ |
| | | |
| | | 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 |
| | | 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. |
| | | |
| | | A finished callback is a callable which accepts a single positional |
| | | parameter: ``request``. For example: |
| | | A finished callback is a callable which accepts a single positional parameter: |
| | | ``request``. For example: |
| | | |
| | | .. code-block:: python |
| | | :linenos: |
| | |
| | | request.add_finished_callback(log_callback) |
| | | |
| | | 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. |
| | | (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. |
| | | 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. |
| | | |
| | | Errors raised by finished callbacks are not handled specially. They |
| | | will be propagated to the caller of the :app:`Pyramid` router |
| | | application. |
| | | Errors raised by finished callbacks are not handled specially. They will be |
| | | propagated to the caller of the :app:`Pyramid` router application. |
| | | |
| | | A finished callback has a lifetime of a *single* request. If you want a |
| | | 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). |
| | | re-register the callback into every new request (perhaps within a subscriber of |
| | | a :class:`~pyramid.events.NewRequest` event). |
| | | |
| | | .. index:: |
| | | single: 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. |
| | | algorithm can be swapped out selectively for a different traversal pattern via |
| | | configuration. |
| | | |
| | | .. code-block:: python |
| | | :linenos: |
| | |
| | | |
| | | 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" |
| | | conditionally, you could claim that an alternative 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: |
| | | used. Otherwise the default traverser would be used. For example: |
| | | |
| | | .. code-block:: python |
| | | :linenos: |
| | |
| | | config.add_traverser(Traverser, MyRoot) |
| | | |
| | | 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 |
| | | 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. |
| | | |
| | | .. index:: |
| | | single: url generator |
| | | single: URL generator |
| | | |
| | | .. _changing_resource_url: |
| | | |
| | |
| | | When you add a traverser as described in :ref:`changing_the_traverser`, it's |
| | | often convenient to continue to use the |
| | | :meth:`pyramid.request.Request.resource_url` API. However, since the way |
| | | traversal is done will have been modified, the URLs it generates by default |
| | | may be incorrect when used against resources derived from your custom |
| | | traverser. |
| | | traversal is done will have been modified, the URLs it generates by default may |
| | | be incorrect when used against resources derived from your custom traverser. |
| | | |
| | | If you've added a traverser, you can change how |
| | | :meth:`~pyramid.request.Request.resource_url` generates a URL for a specific |
| | |
| | | |
| | | config.add_resource_url_adapter(ResourceURLAdapter, MyRoot) |
| | | |
| | | In the above example, the ``myapp.traversal.ResourceURLAdapter`` class will |
| | | be used to provide services to :meth:`~pyramid.request.Request.resource_url` |
| | | any time the :term:`resource` passed to ``resource_url`` is of the class |
| | | In the above example, the ``myapp.traversal.ResourceURLAdapter`` class will be |
| | | used to provide services to :meth:`~pyramid.request.Request.resource_url` any |
| | | time the :term:`resource` passed to ``resource_url`` is of the class |
| | | ``myapp.resources.MyRoot``. The ``resource_iface`` argument ``MyRoot`` |
| | | represents the type of interface that must be possessed by the resource for |
| | | this resource url factory to be found. If the ``resource_iface`` argument is |
| | | omitted, this resource url adapter will be used for *all* resources. |
| | | omitted, this resource URL adapter will be used for *all* resources. |
| | | |
| | | The API that must be implemented by a class that provides |
| | | :class:`~pyramid.interfaces.IResourceURL` is as follows: |
| | |
| | | resource |
| | | """ |
| | | def __init__(self, resource, request): |
| | | """ Accept the resource and request and set self.physical_path and |
| | | self.virtual_path""" |
| | | """ 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) |
| | | |
| | |
| | | <https://github.com/Pylons/pyramid/blob/master/pyramid/traversal.py>`_ of the |
| | | :term:`Pylons` GitHub Pyramid repository. |
| | | |
| | | See :meth:`pyramid.config.add_resource_url_adapter` for more information. |
| | | See :meth:`pyramid.config.Configurator.add_resource_url_adapter` for more |
| | | information. |
| | | |
| | | .. index:: |
| | | single: IResponse |
| | |
| | | :meth:`pyramid.config.Configurator.add_response_adapter` or the |
| | | :class:`~pyramid.response.response_adapter` decorator. |
| | | |
| | | Pyramid, in various places, adapts the result of calling a view callable to |
| | | the :class:`~pyramid.interfaces.IResponse` interface to ensure that the |
| | | object returned by the view callable is a "true" response object. The vast |
| | | majority of time, the result of this adaptation is the result object itself, |
| | | as view callables written by "civilians" who read the narrative documentation |
| | | contained in this manual will always return something that implements the |
| | | :class:`~pyramid.interfaces.IResponse` interface. Most typically, this will |
| | | be an instance of the :class:`pyramid.response.Response` class or a subclass. |
| | | If a civilian returns a non-Response object from a view callable that isn't |
| | | configured to use a :term:`renderer`, he will typically expect the router to |
| | | Pyramid, in various places, adapts the result of calling a view callable to the |
| | | :class:`~pyramid.interfaces.IResponse` interface to ensure that the object |
| | | returned by the view callable is a "true" response object. The vast majority |
| | | of time, the result of this adaptation is the result object itself, as view |
| | | callables written by "civilians" who read the narrative documentation contained |
| | | in this manual will always return something that implements the |
| | | :class:`~pyramid.interfaces.IResponse` interface. Most typically, this will be |
| | | an instance of the :class:`pyramid.response.Response` class or a subclass. If a |
| | | civilian returns a non-Response object from a view callable that isn't |
| | | configured to use a :term:`renderer`, they will typically expect the router to |
| | | raise an error. However, you can hook Pyramid in such a way that users can |
| | | return arbitrary values from a view callable by providing an adapter which |
| | | converts the arbitrary return value into something that implements |
| | | :class:`~pyramid.interfaces.IResponse`. |
| | | |
| | | For example, if you'd like to allow view callables to return bare string |
| | | objects (without requiring a :term:`renderer` to convert a string to a |
| | | response object), you can register an adapter which converts the string to a |
| | | Response: |
| | | objects (without requiring a :term:`renderer` to convert a string to a response |
| | | object), you can register an adapter which converts the string to a Response: |
| | | |
| | | .. code-block:: python |
| | | :linenos: |
| | |
| | | |
| | | config.add_response_adapter(string_response_adapter, str) |
| | | |
| | | Likewise, if you want to be able to return a simplified kind of response |
| | | object from view callables, you can use the IResponse hook to register an |
| | | adapter to the more complex IResponse interface: |
| | | Likewise, if you want to be able to return a simplified kind of response object |
| | | from view callables, you can use the IResponse hook to register an adapter to |
| | | the more complex IResponse interface: |
| | | |
| | | .. code-block:: python |
| | | :linenos: |
| | |
| | | |
| | | If you want to implement your own Response object instead of using the |
| | | :class:`pyramid.response.Response` object in any capacity at all, you'll have |
| | | to make sure the object implements every attribute and method outlined in |
| | | to make sure that the object implements every attribute and method outlined in |
| | | :class:`pyramid.interfaces.IResponse` and you'll have to ensure that it uses |
| | | ``zope.interface.implementer(IResponse)`` as a class decorator. |
| | | |
| | |
| | | |
| | | @implementer(IResponse) |
| | | class MyResponse(object): |
| | | # ... an implementation of every method and attribute |
| | | # ... an implementation of every method and attribute |
| | | # documented in IResponse should follow ... |
| | | |
| | | When an alternate response object implementation is returned by a view |
| | |
| | | subclasses of the class) will natively provide IResponse. The adapter |
| | | registered for ``webob.Response`` simply returns the response object. |
| | | |
| | | Instead of using :meth:`pyramid.config.Configurator.add_response_adapter`, |
| | | you can use the :class:`pyramid.response.response_adapter` decorator: |
| | | Instead of using :meth:`pyramid.config.Configurator.add_response_adapter`, you |
| | | can use the :class:`pyramid.response.response_adapter` decorator: |
| | | |
| | | .. code-block:: python |
| | | :linenos: |
| | |
| | | |
| | | A view mapper is an object that accepts a set of keyword arguments and which |
| | | returns a callable. The returned callable is called with the :term:`view |
| | | callable` object. The returned callable should itself return another |
| | | callable which can be called with the "internal calling protocol" ``(context, |
| | | callable` object. The returned callable should itself return another callable |
| | | which can be called with the "internal calling protocol" ``(context, |
| | | request)``. |
| | | |
| | | You can use a view mapper in a number of ways: |
| | | |
| | | - by setting a ``__view_mapper__`` attribute (which is the view mapper |
| | | object) on the view callable itself |
| | | - by setting a ``__view_mapper__`` attribute (which is the view mapper object) |
| | | on the view callable itself |
| | | |
| | | - by passing the mapper object to |
| | | :meth:`pyramid.config.Configurator.add_view` (or its declarative/decorator |
| | | equivalents) as the ``mapper`` argument. |
| | | - by passing the mapper object to :meth:`pyramid.config.Configurator.add_view` |
| | | (or its declarative and decorator equivalents) as the ``mapper`` argument |
| | | |
| | | - by registering a *default* view mapper. |
| | | - by registering a *default* view mapper |
| | | |
| | | Here's an example of a view mapper that emulates (somewhat) a Pylons |
| | | "controller". The mapper is initialized with some keyword arguments. Its |
| | | ``__call__`` method accepts the view object (which will be a class). It uses |
| | | the ``attr`` keyword argument it is passed to determine which attribute |
| | | should be used as an action method. The wrapper method it returns accepts |
| | | ``(context, request)`` and returns the result of calling the action method |
| | | with keyword arguments implied by the :term:`matchdict` after popping the |
| | | ``action`` out of it. This somewhat emulates the Pylons style of calling |
| | | action methods with routing parameters pulled out of the route matching dict |
| | | as keyword arguments. |
| | | the ``attr`` keyword argument it is passed to determine which attribute should |
| | | be used as an action method. The wrapper method it returns accepts ``(context, |
| | | request)`` and returns the result of calling the action method with keyword |
| | | arguments implied by the :term:`matchdict` after popping the ``action`` out of |
| | | it. This somewhat emulates the Pylons style of calling action methods with |
| | | routing parameters pulled out of the route matching dict as keyword arguments. |
| | | |
| | | .. code-block:: python |
| | | :linenos: |
| | |
| | | set a *default* view mapper (overriding the superdefault view mapper used by |
| | | Pyramid itself). |
| | | |
| | | A *single* view registration can use a view mapper by passing the mapper as |
| | | the ``mapper`` argument to :meth:`~pyramid.config.Configurator.add_view`. |
| | | A *single* view registration can use a view mapper by passing the mapper as the |
| | | ``mapper`` argument to :meth:`~pyramid.config.Configurator.add_view`. |
| | | |
| | | .. index:: |
| | | single: configuration decorator |
| | |
| | | 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`. |
| | | 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`. |
| | | 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" |
| | |
| | | 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: |
| | | However, using :term:`Venusian`, the decorator could be written as follows: |
| | | |
| | | .. code-block:: python |
| | | :linenos: |
| | |
| | | venusian.attach(wrapped, self.register) |
| | | return wrapped |
| | | |
| | | This decorator could then be used to register functions throughout |
| | | your code: |
| | | This decorator could then be used to register functions throughout your code: |
| | | |
| | | .. code-block:: python |
| | | :linenos: |
| | | |
| | | @registerFunction('/some/path') |
| | | def my_function(): |
| | | do_stuff() |
| | | do_stuff() |
| | | |
| | | However, the utility would only be looked up when a :term:`scan` was |
| | | performed, enabling you to set up the utility in advance: |
| | | However, the utility would only be looked up when a :term:`scan` was performed, |
| | | enabling you to set up the utility in advance: |
| | | |
| | | .. code-block:: python |
| | | :linenos: |
| | |
| | | class UtilityImplementation: |
| | | |
| | | def __init__(self): |
| | | self.registrations = {} |
| | | self.registrations = {} |
| | | |
| | | def register(self, path, callable_): |
| | | self.registrations[path] = callable_ |
| | | self.registrations[path] = callable_ |
| | | |
| | | if __name__ == '__main__': |
| | | config = Configurator() |
| | |
| | | A :term:`tween` (a contraction of the word "between") is a bit of code that |
| | | sits between the Pyramid router's main request handling function and the |
| | | upstream WSGI component that uses :app:`Pyramid` as its "app". This is a |
| | | feature that may be used by Pyramid framework extensions, to provide, for |
| | | feature that may be used by Pyramid framework extensions to provide, for |
| | | example, Pyramid-specific view timing support bookkeeping code that examines |
| | | exceptions before they are returned to the upstream WSGI application. Tweens |
| | | behave a bit like :term:`WSGI` :term:`middleware` but they have the benefit of |
| | | behave a bit like :term:`WSGI` :term:`middleware`, but they have the benefit of |
| | | running in a context in which they have access to the Pyramid :term:`request`, |
| | | :term:`response` and :term:`application registry` as well as the Pyramid |
| | | :term:`response`, and :term:`application registry`, as well as the Pyramid |
| | | rendering machinery. |
| | | |
| | | Creating a Tween |
| | | ~~~~~~~~~~~~~~~~ |
| | | |
| | | To create a tween, you must write a "tween factory". A tween factory |
| | | must be a globally importable callable which accepts two arguments: |
| | | ``handler`` and ``registry``. ``handler`` will be either the main |
| | | Pyramid request handling function or another tween. ``registry`` will be the |
| | | Pyramid :term:`application registry` represented by this Configurator. A |
| | | tween factory must return the tween (a callable object) when it is called. |
| | | To create a tween, you must write a "tween factory". A tween factory must be a |
| | | globally importable callable which accepts two arguments: ``handler`` and |
| | | ``registry``. ``handler`` will be either the main Pyramid request handling |
| | | function or another tween. ``registry`` will be the Pyramid :term:`application |
| | | registry` represented by this Configurator. A tween factory must return the |
| | | tween (a callable object) when it is called. |
| | | |
| | | A tween is called with a single argument, ``request``, which is the |
| | | :term:`request` created by Pyramid's router when it receives a WSGI request. |
| | | A tween should return a :term:`response`, usually the one generated by the |
| | | :term:`request` created by Pyramid's router when it receives a WSGI request. A |
| | | tween should return a :term:`response`, usually the one generated by the |
| | | downstream Pyramid application. |
| | | |
| | | You can write the tween factory as a simple closure-returning function: |
| | |
| | | |
| | | return response |
| | | |
| | | You should avoid mutating any state on the tween instance. The tween is |
| | | invoked once per request and any shared mutable state needs to be carefully |
| | | handled to avoid any race conditions. |
| | | You should avoid mutating any state on the tween instance. The tween is invoked |
| | | once per request and any shared mutable state needs to be carefully handled to |
| | | avoid any race conditions. |
| | | |
| | | The closure style performs slightly better and enables you to conditionally |
| | | omit the tween from the request processing pipeline (see the following timing |
| | | tween example), whereas the class style makes it easier to have shared mutable |
| | | state, and it allows subclassing. |
| | | state and allows subclassing. |
| | | |
| | | Here's a complete example of a tween that logs the time spent processing each |
| | | request: |
| | |
| | | |
| | | In the above example, the tween factory defines a ``timing_tween`` tween and |
| | | returns it if ``asbool(registry.settings.get('do_timing'))`` is true. It |
| | | otherwise simply returns the handler it was given. The ``registry.settings`` |
| | | attribute is a handle to the deployment settings provided by the user |
| | | (usually in an ``.ini`` file). In this case, if the user has defined a |
| | | ``do_timing`` setting, and that setting is ``True``, the user has said she |
| | | wants to do timing, so the tween factory returns the timing tween; it |
| | | otherwise just returns the handler it has been provided, preventing any |
| | | timing. |
| | | otherwise simply returns the handler which it was given. The |
| | | ``registry.settings`` attribute is a handle to the deployment settings provided |
| | | by the user (usually in an ``.ini`` file). In this case, if the user has |
| | | defined a ``do_timing`` setting and that setting is ``True``, the user has said |
| | | they want to do timing, so the tween factory returns the timing tween; it |
| | | otherwise just returns the handler it has been provided, preventing any timing. |
| | | |
| | | The example timing tween simply records the start time, calls the downstream |
| | | handler, logs the number of seconds consumed by the downstream handler, and |
| | |
| | | Note that you must use a :term:`dotted Python name` as the first argument to |
| | | :meth:`pyramid.config.Configurator.add_tween`; this must point at a tween |
| | | factory. You cannot pass the tween factory object itself to the method: it |
| | | must be :term:`dotted Python name` that points to a globally importable |
| | | object. In the above example, we assume that a ``timing_tween_factory`` |
| | | tween factory was defined in a module named ``myapp.tweens``, so the tween |
| | | factory is importable as ``myapp.tweens.timing_tween_factory``. |
| | | must be :term:`dotted Python name` that points to a globally importable object. |
| | | In the above example, we assume that a ``timing_tween_factory`` tween factory |
| | | was defined in a module named ``myapp.tweens``, so the tween factory is |
| | | importable as ``myapp.tweens.timing_tween_factory``. |
| | | |
| | | When you use :meth:`pyramid.config.Configurator.add_tween`, you're |
| | | instructing the system to use your tween factory at startup time unless the |
| | | user has provided an explicit tween list in his configuration. This is |
| | | what's meant by an "implicit" tween. A user can always elect to supply an |
| | | explicit tween list, reordering or disincluding implicitly added tweens. See |
| | | When you use :meth:`pyramid.config.Configurator.add_tween`, you're instructing |
| | | the system to use your tween factory at startup time unless the user has |
| | | provided an explicit tween list in their configuration. This is what's meant |
| | | by an "implicit" tween. A user can always elect to supply an explicit tween |
| | | list, reordering or disincluding implicitly added tweens. See |
| | | :ref:`explicit_tween_ordering` for more information about explicit tween |
| | | ordering. |
| | | |
| | | If more than one call to :meth:`pyramid.config.Configurator.add_tween` is |
| | | made within a single application configuration, the tweens will be chained |
| | | together at application startup time. The *first* tween factory added via |
| | | ``add_tween`` will be called with the Pyramid exception view tween factory as |
| | | its ``handler`` argument, then the tween factory added directly after that |
| | | one will be called with the result of the first tween factory as its |
| | | ``handler`` argument, and so on, ad infinitum until all tween factories have |
| | | been called. The Pyramid router will use the outermost tween produced by this |
| | | chain (the tween generated by the very last tween factory added) as its |
| | | request handler function. For example: |
| | | If more than one call to :meth:`pyramid.config.Configurator.add_tween` is made |
| | | within a single application configuration, the tweens will be chained together |
| | | at application startup time. The *first* tween factory added via ``add_tween`` |
| | | will be called with the Pyramid exception view tween factory as its ``handler`` |
| | | argument, then the tween factory added directly after that one will be called |
| | | with the result of the first tween factory as its ``handler`` argument, and so |
| | | on, ad infinitum until all tween factories have been called. The Pyramid router |
| | | will use the outermost tween produced by this chain (the tween generated by the |
| | | very last tween factory added) as its request handler function. For example: |
| | | |
| | | .. code-block:: python |
| | | :linenos: |
| | |
| | | config.add_tween('myapp.tween_factory1') |
| | | config.add_tween('myapp.tween_factory2') |
| | | |
| | | The above example will generate an implicit tween chain that looks like |
| | | this:: |
| | | The above example will generate an implicit tween chain that looks like this:: |
| | | |
| | | INGRESS (implicit) |
| | | myapp.tween_factory2 |
| | |
| | | By default, as described above, the ordering of the chain is controlled |
| | | entirely by the relative ordering of calls to |
| | | :meth:`pyramid.config.Configurator.add_tween`. However, the caller of |
| | | add_tween can provide an optional hint that can influence the implicit tween |
| | | chain ordering by supplying ``under`` or ``over`` (or both) arguments to |
| | | :meth:`~pyramid.config.Configurator.add_tween`. These hints are only |
| | | used when an explicit tween ordering is not used. See |
| | | :ref:`explicit_tween_ordering` for a description of how to set an explicit |
| | | tween ordering. |
| | | ``add_tween`` can provide an optional hint that can influence the implicit |
| | | tween chain ordering by supplying ``under`` or ``over`` (or both) arguments to |
| | | :meth:`~pyramid.config.Configurator.add_tween`. These hints are only used when |
| | | an explicit tween ordering is not used. See :ref:`explicit_tween_ordering` for |
| | | a description of how to set an explicit tween ordering. |
| | | |
| | | Allowable values for ``under`` or ``over`` (or both) are: |
| | | |
| | | - ``None`` (the default). |
| | | - ``None`` (the default), |
| | | |
| | | - A :term:`dotted Python name` to a tween factory: a string representing the |
| | | predicted dotted name of a tween factory added in a call to ``add_tween`` |
| | | in the same configuration session. |
| | | - a :term:`dotted Python name` to a tween factory: a string representing the |
| | | predicted dotted name of a tween factory added in a call to ``add_tween`` in |
| | | the same configuration session, |
| | | |
| | | - One of the constants :attr:`pyramid.tweens.MAIN`, |
| | | :attr:`pyramid.tweens.INGRESS`, or :attr:`pyramid.tweens.EXCVIEW`. |
| | | - one of the constants :attr:`pyramid.tweens.MAIN`, |
| | | :attr:`pyramid.tweens.INGRESS`, or :attr:`pyramid.tweens.EXCVIEW`, or |
| | | |
| | | - An iterable of any combination of the above. This allows the user to specify |
| | | - an iterable of any combination of the above. This allows the user to specify |
| | | fallbacks if the desired tween is not included, as well as compatibility |
| | | with multiple other tweens. |
| | | |
| | | Effectively, ``over`` means "closer to the request ingress than" and |
| | | ``under`` means "closer to the main Pyramid application than". |
| | | You can think of an onion with outer layers over the inner layers, |
| | | the application being under all the layers at the center. |
| | | Effectively, ``over`` means "closer to the request ingress than" and ``under`` |
| | | means "closer to the main Pyramid application than". You can think of an onion |
| | | with outer layers over the inner layers, the application being under all the |
| | | layers at the center. |
| | | |
| | | For example, the following call to |
| | | :meth:`~pyramid.config.Configurator.add_tween` will attempt to place the |
| | | tween factory represented by ``myapp.tween_factory`` directly 'above' (in |
| | | ``ptweens`` order) the main Pyramid request handler. |
| | | :meth:`~pyramid.config.Configurator.add_tween` will attempt to place the tween |
| | | factory represented by ``myapp.tween_factory`` directly "above" (in ``ptweens`` |
| | | order) the main Pyramid request handler. |
| | | |
| | | .. code-block:: python |
| | | :linenos: |
| | |
| | | |
| | | config.add_tween('myapp.tween_factory', over=pyramid.tweens.MAIN) |
| | | |
| | | The above example will generate an implicit tween chain that looks like |
| | | this:: |
| | | The above example will generate an implicit tween chain that looks like this:: |
| | | |
| | | INGRESS (implicit) |
| | | pyramid.tweens.excview_tween_factory (implicit) |
| | |
| | | MAIN (implicit) |
| | | |
| | | Likewise, calling the following call to |
| | | :meth:`~pyramid.config.Configurator.add_tween` will attempt to place this |
| | | tween factory 'above' the main handler but 'below' a separately added tween |
| | | factory: |
| | | :meth:`~pyramid.config.Configurator.add_tween` will attempt to place this tween |
| | | factory "above" the main handler but "below" a separately added tween factory: |
| | | |
| | | .. code-block:: python |
| | | :linenos: |
| | |
| | | over=pyramid.tweens.MAIN, |
| | | under='myapp.tween_factory1') |
| | | |
| | | The above example will generate an implicit tween chain that looks like |
| | | this:: |
| | | The above example will generate an implicit tween chain that looks like this:: |
| | | |
| | | INGRESS (implicit) |
| | | pyramid.tweens.excview_tween_factory (implicit) |
| | |
| | | |
| | | If all options for ``under`` (or ``over``) cannot be found in the current |
| | | configuration, it is an error. If some options are specified purely for |
| | | compatibilty with other tweens, just add a fallback of MAIN or INGRESS. |
| | | For example, ``under=('someothertween', 'someothertween2', INGRESS)``. |
| | | This constraint will require the tween to be located under both the |
| | | 'someothertween' tween, the 'someothertween2' tween, and INGRESS. If any of |
| | | these is not in the current configuration, this constraint will only organize |
| | | itself based on the tweens that are present. |
| | | compatibilty with other tweens, just add a fallback of ``MAIN`` or ``INGRESS``. |
| | | For example, ``under=('someothertween', 'someothertween2', INGRESS)``. This |
| | | constraint will require the tween to be located under the ``someothertween`` |
| | | tween, the ``someothertween2`` tween, and ``INGRESS``. If any of these is not |
| | | in the current configuration, this constraint will only organize itself based |
| | | on the tweens that are present. |
| | | |
| | | .. _explicit_tween_ordering: |
| | | |
| | | Explicit Tween Ordering |
| | | ~~~~~~~~~~~~~~~~~~~~~~~ |
| | | |
| | | Implicit tween ordering is obviously only best-effort. Pyramid will attempt |
| | | to provide an implicit order of tweens as best it can using hints provided by |
| | | calls to :meth:`~pyramid.config.Configurator.add_tween`, but because it's |
| | | only best-effort, if very precise tween ordering is required, the only |
| | | surefire way to get it is to use an explicit tween order. The deploying user |
| | | can override the implicit tween inclusion and ordering implied by calls to |
| | | Implicit tween ordering is obviously only best-effort. Pyramid will attempt to |
| | | provide an implicit order of tweens as best it can using hints provided by |
| | | calls to :meth:`~pyramid.config.Configurator.add_tween`. But because it's only |
| | | best-effort, if very precise tween ordering is required, the only surefire way |
| | | to get it is to use an explicit tween order. The deploying user can override |
| | | the implicit tween inclusion and ordering implied by calls to |
| | | :meth:`~pyramid.config.Configurator.add_tween` entirely by using the |
| | | ``pyramid.tweens`` settings value. When used, this settings value must be a |
| | | list of Python dotted names which will override the ordering (and inclusion) |
| | | of tween factories in the implicit tween chain. For example: |
| | | list of Python dotted names which will override the ordering (and inclusion) of |
| | | tween factories in the implicit tween chain. For example: |
| | | |
| | | .. code-block:: ini |
| | | :linenos: |
| | |
| | | In the above configuration, calls made during configuration to |
| | | :meth:`pyramid.config.Configurator.add_tween` are ignored, and the user is |
| | | telling the system to use the tween factories he has listed in the |
| | | ``pyramid.tweens`` configuration setting (each is a :term:`dotted Python |
| | | name` which points to a tween factory) instead of any tween factories added |
| | | via :meth:`pyramid.config.Configurator.add_tween`. The *first* tween factory |
| | | in the ``pyramid.tweens`` list will be used as the producer of the effective |
| | | ``pyramid.tweens`` configuration setting (each is a :term:`dotted Python name` |
| | | which points to a tween factory) instead of any tween factories added via |
| | | :meth:`pyramid.config.Configurator.add_tween`. The *first* tween factory in |
| | | the ``pyramid.tweens`` list will be used as the producer of the effective |
| | | :app:`Pyramid` request handling function; it will wrap the tween factory |
| | | declared directly "below" it, ad infinitum. The "main" Pyramid request |
| | | handler is implicit, and always "at the bottom". |
| | | declared directly "below" it, ad infinitum. The "main" Pyramid request handler |
| | | is implicit, and always "at the bottom". |
| | | |
| | | .. note:: |
| | | |
| | | Pyramid's own :term:`exception view` handling logic is implemented |
| | | as a tween factory function: :func:`pyramid.tweens.excview_tween_factory`. |
| | | If Pyramid exception view handling is desired, and tween factories are |
| | | Pyramid's own :term:`exception view` handling logic is implemented as a |
| | | tween factory function: :func:`pyramid.tweens.excview_tween_factory`. If |
| | | Pyramid exception view handling is desired, and tween factories are |
| | | specified via the ``pyramid.tweens`` configuration setting, the |
| | | :func:`pyramid.tweens.excview_tween_factory` function must be added to the |
| | | ``pyramid.tweens`` configuration setting list explicitly. If it is not |
| | |
| | | Tween Conflicts and Ordering Cycles |
| | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| | | |
| | | Pyramid will prevent the same tween factory from being added to the tween |
| | | chain more than once using configuration conflict detection. If you wish to |
| | | add the same tween factory more than once in a configuration, you should |
| | | either: a) use a tween factory that is a separate globally importable |
| | | instance object from the factory that it conflicts with b) use a function or |
| | | class as a tween factory with the same logic as the other tween factory it |
| | | conflicts with but with a different ``__name__`` attribute or c) call |
| | | Pyramid will prevent the same tween factory from being added to the tween chain |
| | | more than once using configuration conflict detection. If you wish to add the |
| | | same tween factory more than once in a configuration, you should either: (a) |
| | | use a tween factory that is a separate globally importable instance object from |
| | | the factory that it conflicts with; (b) use a function or class as a tween |
| | | factory with the same logic as the other tween factory it conflicts with, but |
| | | with a different ``__name__`` attribute; or (c) call |
| | | :meth:`pyramid.config.Configurator.commit` between calls to |
| | | :meth:`pyramid.config.Configurator.add_tween`. |
| | | |
| | | If a cycle is detected in implicit tween ordering when ``over`` and ``under`` |
| | | are used in any call to "add_tween", an exception will be raised at startup |
| | | are used in any call to ``add_tween``, an exception will be raised at startup |
| | | time. |
| | | |
| | | Displaying Tween Ordering |
| | | ~~~~~~~~~~~~~~~~~~~~~~~~~ |
| | | |
| | | The ``ptweens`` command-line utility can be used to report the current |
| | | implict and explicit tween chains used by an application. See |
| | | The ``ptweens`` command-line utility can be used to report the current implict |
| | | and explicit tween chains used by an application. See |
| | | :ref:`displaying_tweens`. |
| | | |
| | | .. _registering_thirdparty_predicates: |
| | | |
| | | Adding A Third Party View, Route, or Subscriber Predicate |
| | | Adding a Third Party View, Route, or Subscriber Predicate |
| | | --------------------------------------------------------- |
| | | |
| | | .. versionadded:: 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 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``: |
| | | |
| | | .. code-block:: python |
| | | |
| | |
| | | |
| | | 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 :meth:`pyramid.config.Configurator.add_view_predicate` or |
| | | 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 |
| | | :meth:`pyramid.config.Configurator.add_view_predicate` or |
| | | :meth:`pyramid.config.Configurator.add_route_predicate`. The former adds a |
| | | view predicate, the latter a route predicate. |
| | | |
| | |
| | | The second argument is a view or route predicate factory, or a :term:`dotted |
| | | Python name` which refers to 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__`` |
| | | (``__init__``), a ``text`` method, a ``phash`` method, and a ``__call__`` |
| | | method. For example: |
| | | |
| | | .. code-block:: python |
| | |
| | | |
| | | 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. |
| | | ``view_config`` (or ``add_view``). In the example above, it will be the string |
| | | ``File``. The second argument, ``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 ``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 ``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. |
| | | (``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 |
| | | 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 |
| | | ~~~~~~~~~~~~~~~~~~~~~ |
| | | |
| | | 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: |
| | | 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 or route |
| | | predicate: |
| | | |
| | | - There are no default subscriber predicates. You must register one to use |
| | | one. |
| | | |
| | | - The ``__call__`` method of a subscriber predicate accepts a single |
| | | ``event`` object instead of a ``context`` and a ``request``. |
| | | - The ``__call__`` method of a subscriber predicate accepts a single ``event`` |
| | | object instead of a ``context`` and a ``request``. |
| | | |
| | | - Not every subscriber predicate can be used with every event type. Some |
| | | subscriber predicates will assume a certain event type. |
| | |
| | | |
| | | Once a subscriber predicate is registered, you can use it in a call to |
| | | :meth:`pyramid.config.Configurator.add_subscriber` or to |
| | | :class:`pyramid.events.subscriber`. Here's an example of using the |
| | | previously registered ``request_path_startswith`` predicate in a call to |
| | | :class:`pyramid.events.subscriber`. Here's an example of using the previously |
| | | registered ``request_path_startswith`` predicate in a call to |
| | | :meth:`~pyramid.config.Configurator.add_subscriber`: |
| | | |
| | | .. code-block:: python |
| | |
| | | |
| | | # and at configuration time |
| | | |
| | | config.add_subscriber(yosubscriber, NewRequest, |
| | | config.add_subscriber(yosubscriber, NewRequest, |
| | | request_path_startswith='/add_yo') |
| | | |
| | | Here's the same subscriber/predicate/event-type combination used via |
| | |
| | | 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. |
| | | 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 |
| | | :class:`pyramid.events.NewRequest` and :class:`pyramid.events.ContextFound` |
| | | events, but it cannot be used with subscribers registered for |
| | | :class:`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. |
| | | |
| | | |
| | | |
| | | :class:`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. |