- Pyramid now expects Response objects to have a __call__
method which implements the WSGI application interface
instead of the three webob attrs status, headerlist
and app_iter. Backwards compatibility exists for
code which returns response objects that do not
have a __call__.
- pyramid.response.Response is no longer an exception
(and therefore cannot be raised in order to generate
a response).
- Changed my mind about moving stuff from pyramid.httpexceptions
to pyramid.response. The stuff I moved over has been moved
back to pyramid.httpexceptions.
| | |
| | | |
| | | - Added "What's New in Pyramid 1.1" to HTML rendering of documentation. |
| | | |
| | | - Added API docs for ``pyramid.httpexceptions.abort`` and |
| | | ``pyramid.httpexceptions.redirect``. |
| | | - Added API docs for ``pyramid.httpexceptions.responsecode``. |
| | | |
| | | - Added "HTTP Exceptions" section to Views narrative chapter including a |
| | | description of ``pyramid.httpexceptions.abort``; adjusted redirect section |
| | | to note ``pyramid.httpexceptions.redirect``. |
| | | description of ``pyramid.httpexceptions.responsecode``. |
| | | |
| | | Features |
| | | -------- |
| | |
| | | more information. |
| | | |
| | | - A default exception view for the context |
| | | ``pyramid.interfaces.IExceptionResponse`` (aka |
| | | ``pyramid.response.Response`` or ``pyramid.httpexceptions.HTTPException``) |
| | | is now registered by default. This means that an instance of any exception |
| | | response class imported from ``pyramid.httpexceptions`` (such as |
| | | ``HTTPFound``) can now be raised from within view code; when raised, this |
| | | exception view will render the exception to a response. |
| | | ``pyramid.interfaces.IExceptionResponse`` is now registered by default. |
| | | This means that an instance of any exception response class imported from |
| | | ``pyramid.httpexceptions`` (such as ``HTTPFound``) can now be raised from |
| | | within view code; when raised, this exception view will render the |
| | | exception to a response. |
| | | |
| | | - New functions named ``pyramid.httpexceptions.abort`` and |
| | | ``pyramid.httpexceptions.redirect`` perform the equivalent of their Pylons |
| | | brethren when an HTTP exception handler is registered. These functions |
| | | take advantage of the newly registered exception view for |
| | | ``webob.exc.HTTPException``. |
| | | - A function named ``pyramid.httpexceptions.responsecode`` is a shortcut that |
| | | can be used to create HTTP exception response objects using an HTTP integer |
| | | status code. |
| | | |
| | | - The Configurator now accepts an additional keyword argument named |
| | | ``exceptionresponse_view``. By default, this argument is populated with a |
| | |
| | | - It is now possible to control how the Pyramid router calls the WSGI |
| | | ``start_response`` callable and obtains the WSGI ``app_iter`` based on |
| | | adapting the response object to the new ``pyramid.interfaces.IResponder`` |
| | | interface. The default ``IResponder`` uses Pyramid 1.0's logic to do this. |
| | | To override the responder:: |
| | | interface. See the section in the Hooks chapter of the documentation |
| | | entitled "Changing How Pyramid Treats Response Objects". |
| | | |
| | | from pyramid.interfaces import IResponder |
| | | from pyramid.response import Response |
| | | from myapp import MyResponder |
| | | |
| | | config.registry.registerAdapter(MyResponder, (Response,), |
| | | IResponder, name='') |
| | | |
| | | This makes it possible to reuse response object implementations which have, |
| | | for example, their own ``__call__`` expected to be used as a WSGI |
| | | application (like ``pyramid.response.Response``), e.g.: |
| | | |
| | | class MyResponder(object): |
| | | def __init__(self, response): |
| | | """ Obtain a reference to the response """ |
| | | self.response = response |
| | | def __call__(self, request, start_response): |
| | | """ Call start_response and return an app_iter """ |
| | | app_iter = self.response(request.environ, start_response) |
| | | return app_iter |
| | | - The Pyramid router will now, by default, call the ``__call__`` method of |
| | | WebOb response objects when returning a WSGI response. This means that, |
| | | among other things, the ``conditional_response`` feature of WebOb response |
| | | objects will now behave properly. |
| | | |
| | | Bug Fixes |
| | | --------- |
| | |
| | | Behavior Changes |
| | | ---------------- |
| | | |
| | | - A custom request factory is now required to return a response object that |
| | | - A custom request factory is now required to return a request object that |
| | | has a ``response`` attribute (or "reified"/lazy property) if they the |
| | | request is meant to be used in a view that uses a renderer. This |
| | | ``response`` attribute should be an instance of the class |
| | |
| | | result. |
| | | |
| | | - ``pyramid.response.Response`` is now a *subclass* of |
| | | ``webob.response.Response``. It also inherits from the built-in Python |
| | | ``Exception`` class and implements the |
| | | ``pyramid.interfaces.IExceptionResponse`` class so it can be raised as an |
| | | exception from view code. |
| | | ``webob.response.Response`` (in order to directly implement the |
| | | ``pyramid.interfaces.IResponse`` interface). |
| | | |
| | | - The ``pyramid.interfaces.IResponse`` interface now includes a ``__call__`` |
| | | method which has the WSGI application call signature (and which expects an |
| | | iterable as a result). |
| | | |
| | | - The Pyramid router now, by default, expects response objects returned from |
| | | views to implement the WSGI application interface (a ``__call__`` method |
| | | that accepts ``environ`` and ``start_response``, and which returns an |
| | | ``app_iter`` iterable). If such a method exists, Pyramid will now call it |
| | | in order to satisfy the WSGI request. Backwards compatibility code in the |
| | | default responder exists which will fall back to the older behavior, but |
| | | Pyramid will raise a deprecation warning if it is reached. See the section |
| | | in the Hooks chapter of the documentation entitled "Changing How Pyramid |
| | | Treats Response Objects" to default back to the older behavior, where the |
| | | ``app_iter``, ``headerlist``, and ``status`` attributes of the object were |
| | | consulted directly (without any indirection through ``__call__``) to |
| | | silence the deprecation warnings. |
| | | |
| | | Dependencies |
| | | ------------ |
| | |
| | | Pyramid TODOs |
| | | ============= |
| | | |
| | | Must-Have |
| | | --------- |
| | | |
| | | - Depend on only __call__ interface or only 3-attr interface in builtin code |
| | | that deals with response objects. |
| | | |
| | | Should-Have |
| | | ----------- |
| | | |
| | |
| | | |
| | | .. automodule:: pyramid.httpexceptions |
| | | |
| | | .. autofunction:: abort |
| | | |
| | | .. autofunction:: redirect |
| | | |
| | | .. attribute:: status_map |
| | | |
| | | A mapping of integer status code to exception class (eg. the |
| | | integer "401" maps to |
| | | :class:`pyramid.httpexceptions.HTTPUnauthorized`). |
| | | |
| | | .. autofunction:: responsecode |
| | | |
| | | .. autoclass:: HTTPException |
| | | |
| | | .. autoclass:: HTTPOk |
| | |
| | | .. autoclass:: Response |
| | | :members: |
| | | :inherited-members: |
| | | |
| | |
| | | |
| | | Not Found view |
| | | An :term:`exception view` invoked by :app:`Pyramid` when the |
| | | developer explicitly raises a ``pyramid.response.HTTPNotFound`` |
| | | developer explicitly raises a ``pyramid.httpexceptions.HTTPNotFound`` |
| | | exception from within :term:`view` code or :term:`root factory` |
| | | code, or when the current request doesn't match any :term:`view |
| | | configuration`. :app:`Pyramid` provides a default |
| | |
| | | Forbidden view |
| | | An :term:`exception view` invoked by :app:`Pyramid` when the |
| | | developer explicitly raises a |
| | | ``pyramid.response.HTTPForbidden`` exception from within |
| | | ``pyramid.httpexceptions.HTTPForbidden`` exception from within |
| | | :term:`view` code or :term:`root factory` code, or when the |
| | | :term:`view configuration` and :term:`authorization policy` |
| | | found for a request disallows a particular view invocation. |
| | |
| | | |
| | | 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.response.HTTPNotFound` class as the |
| | | only of naming the :exc:`pyramid.httpexceptions.HTTPNotFound` class as the |
| | | ``context`` of the view configuration. |
| | | |
| | | If your application uses :term:`imperative configuration`, you can replace |
| | |
| | | .. code-block:: python |
| | | :linenos: |
| | | |
| | | from pyramid.response import HTTPNotFound |
| | | from pyramid.httpexceptions import HTTPNotFound |
| | | from helloworld.views import notfound_view |
| | | config.add_view(notfound_view, context=HTTPNotFound) |
| | | |
| | |
| | | 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.response.HTTPNotFound` exception that caused the view to be |
| | | called. |
| | | :exc:`~pyramid.httpexceptions.HTTPNotFound` exception that caused the view to |
| | | be called. |
| | | |
| | | Here's some sample code that implements a minimal NotFound view callable: |
| | | |
| | | .. code-block:: python |
| | | :linenos: |
| | | |
| | | from pyramid.response import HTTPNotFound |
| | | from pyramid.httpexceptions import HTTPNotFound |
| | | |
| | | def notfound_view(request): |
| | | return HTTPNotFound() |
| | | |
| | | .. note:: When a NotFound view callable is invoked, it is passed a |
| | | :term:`request`. The ``exception`` attribute of the request will be an |
| | | instance of the :exc:`~pyramid.response.HTTPNotFound` exception that |
| | | instance of the :exc:`~pyramid.httpexceptions.HTTPNotFound` exception that |
| | | caused the not found view to be called. The value of |
| | | ``request.exception.args[0]`` will be a value explaining why the not found |
| | | error was raised. This message will be different when the |
| | |
| | | .. warning:: When a NotFound 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.response.HTTPNotFound` exception instance. If available, |
| | | the resource context will still be available as ``request.context``. |
| | | :exc:`~pyramid.httpexceptions.HTTPNotFound` exception instance. If |
| | | available, the resource context will still be available as |
| | | ``request.context``. |
| | | |
| | | .. index:: |
| | | single: forbidden view |
| | |
| | | |
| | | 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.response.HTTPForbidden` class as the |
| | | only of naming the :exc:`pyramid.httpexceptions.HTTPForbidden` class as the |
| | | ``context`` of the view configuration. |
| | | |
| | | You can replace the forbidden view by using the |
| | |
| | | :linenos: |
| | | |
| | | from helloworld.views import forbidden_view |
| | | from pyramid.response import HTTPForbidden |
| | | from pyramid.httpexceptions import HTTPForbidden |
| | | config.add_view(forbidden_view, context=HTTPForbidden) |
| | | |
| | | Replace ``helloworld.views.forbidden_view`` with a reference to the Python |
| | |
| | | |
| | | .. 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.response.HTTPForbidden` exception that |
| | | caused the forbidden view to be called. The value of |
| | | instance of the :exc:`~pyramid.httpexceptions.HTTPForbidden` exception |
| | | that caused the forbidden view to be called. The value of |
| | | ``request.exception.args[0]`` will be a value explaining why the forbidden |
| | | was raised. This message will be different when the |
| | | ``debug_authorization`` environment setting is true than it is when it is |
| | |
| | | It is possible to control how the Pyramid :term:`router` calls the WSGI |
| | | ``start_response`` callable and obtains the WSGI ``app_iter`` based on |
| | | adapting the response object to the :class: `pyramid.interfaces.IResponder` |
| | | interface. The default ``IResponder`` uses the three attributes ``status``, |
| | | ``headerlist``, and ``app_iter`` attached to the response object, and calls |
| | | ``start_response`` with the status and headerlist, returning the |
| | | ``app_iter``. To override the responder:: |
| | | interface. The default responder uses the ``__call__`` method of a response |
| | | object, passing it the WSGI environ and the WSGI ``start_response`` callable |
| | | (the response is assumed to be a WSGI application). To override the |
| | | responder:: |
| | | |
| | | from pyramid.interfaces import IResponder |
| | | from pyramid.response import Response |
| | |
| | | IResponder, name='') |
| | | |
| | | Overriding makes it possible to reuse response object implementations which |
| | | have, for example, their own ``__call__`` expected to be used as a WSGI |
| | | application (like :class:`pyramid.response.Response`), e.g.: |
| | | have, for example, the ``app_iter``, ``headerlist`` and ``status`` attributes |
| | | of an object returned as a response instead of trying to use the object's |
| | | ``__call__`` method:: |
| | | |
| | | class MyResponder(object): |
| | | def __init__(self, response): |
| | |
| | | self.response = response |
| | | def __call__(self, request, start_response): |
| | | """ Call start_response and return an app_iter """ |
| | | app_iter = self.response(request.environ, start_response) |
| | | return app_iter |
| | | start_response(self.response.status, self.response.headerlist) |
| | | return self.response.app_iter |
| | | |
| | | .. index:: |
| | | single: view mapper |
| | |
| | | .. code-block:: python |
| | | :linenos: |
| | | |
| | | from pyramid.response import Response |
| | | from pyramid.view import view_config |
| | | |
| | | @view_config(renderer='json') |
| | |
| | | renderers can be added by developers to the system as necessary (see |
| | | :ref:`adding_and_overriding_renderers`). |
| | | |
| | | Views which use a renderer can vary non-body response attributes (such as |
| | | headers and the HTTP status code) by attaching a property to the |
| | | ``request.response`` attribute See :ref:`request_response_attr`. |
| | | Views which use a renderer and return a non-Response value can vary non-body |
| | | response attributes (such as headers and the HTTP status code) by attaching a |
| | | property to the ``request.response`` attribute See |
| | | :ref:`request_response_attr`. |
| | | |
| | | If the :term:`view callable` associated with a :term:`view configuration` |
| | | returns a Response object directly (an object with the attributes ``status``, |
| | | ``headerlist`` and ``app_iter``), any renderer associated with the view |
| | | returns a Response object directly, any renderer associated with the view |
| | | configuration is ignored, and the response is passed back to :app:`Pyramid` |
| | | unchanged. For example, if your view callable returns an instance of the |
| | | :class:`pyramid.response.HTTPFound` class as a response, no renderer will be |
| | | employed. |
| | | |
| | | .. code-block:: python |
| | | :linenos: |
| | | |
| | | from pyramid.response import HTTPFound |
| | | |
| | | def view(request): |
| | | return HTTPFound(location='http://example.com') # any renderer avoided |
| | | |
| | | Likewise for a "plain old response": |
| | | :class:`pyramid.response.Response` class as a response, no renderer |
| | | will be employed. |
| | | |
| | | .. code-block:: python |
| | | :linenos: |
| | | |
| | | from pyramid.response import Response |
| | | from pyramid.view import view_config |
| | | |
| | | @view_config(renderer='json') |
| | | def view(request): |
| | | return Response('OK') # any renderer avoided |
| | | return Response('OK') # json renderer avoided |
| | | |
| | | Mutations to ``request.response`` in views which return a Response object |
| | | like this directly (unless that response *is* ``request.response``) will be |
| | | ignored. |
| | | Likewise for an :term:`HTTP exception` response: |
| | | |
| | | .. code-block:: python |
| | | :linenos: |
| | | |
| | | from pyramid.httpexceptions import HTTPNotFound |
| | | from pyramid.view import view_config |
| | | |
| | | @view_config(renderer='json') |
| | | def view(request): |
| | | return HTTPFound(location='http://example.com') # json renderer avoided |
| | | |
| | | You can of course also return the ``request.response`` attribute instead to |
| | | avoid rendering: |
| | | |
| | | .. code-block:: python |
| | | :linenos: |
| | | |
| | | from pyramid.view import view_config |
| | | |
| | | @view_config(renderer='json') |
| | | def view(request): |
| | | request.response.body = 'OK' |
| | | return request.response # json renderer avoided |
| | | |
| | | .. index:: |
| | | single: renderers (built-in) |
| | |
| | | request.response.status = '404 Not Found' |
| | | return {'URL':request.URL} |
| | | |
| | | Note that mutations of ``request.response`` in views which return a Response |
| | | object directly will have no effect unless the response object returned *is* |
| | | ``request.response``. For example, the following example calls |
| | | ``request.response.set_cookie``, but this call will have no effect, because a |
| | | different Response object is returned. |
| | | |
| | | .. code-block:: python |
| | | :linenos: |
| | | |
| | | from pyramid.response import Response |
| | | |
| | | def view(request): |
| | | request.response.set_cookie('abc', '123') # this has no effect |
| | | return Response('OK') # because we're returning a different response |
| | | |
| | | If you mutate ``request.response`` and you'd like the mutations to have an |
| | | effect, you must return ``request.response``: |
| | | |
| | | .. code-block:: python |
| | | :linenos: |
| | | |
| | | def view(request): |
| | | request.response.set_cookie('abc', '123') |
| | | return request.response |
| | | |
| | | For more information on attributes of the request, see the API documentation |
| | | in :ref:`request_module`. For more information on the API of |
| | | ``request.response``, see :class:`pyramid.response.Response`. |
| | |
| | | combination of objects (based on the type of the context, the type of the |
| | | request, and the value of the view name, and any :term:`predicate` |
| | | attributes applied to the view configuration), :app:`Pyramid` raises a |
| | | :class:`~pyramid.response.HTTPNotFound` exception, which is meant to be |
| | | caught by a surrounding exception handler. |
| | | :class:`~pyramid.httpexceptions.HTTPNotFound` exception, which is meant to |
| | | be caught by a surrounding :term:`exception view`. |
| | | |
| | | #. If a view callable was found, :app:`Pyramid` attempts to call |
| | | the view function. |
| | |
| | | information in the request and security information attached to the |
| | | context. If it returns ``True``, :app:`Pyramid` calls the view callable |
| | | to obtain a response. If it returns ``False``, it raises a |
| | | :class:`~pyramid.response.HTTPForbidden` exception, which is meant to be |
| | | called by a surrounding exception handler. |
| | | :class:`~pyramid.httpexceptions.HTTPForbidden` exception, which is meant |
| | | to be called by a surrounding :term:`exception view`. |
| | | |
| | | #. If any exception was raised within a :term:`root factory`, by |
| | | :term:`traversal`, by a :term:`view callable` or by :app:`Pyramid` itself |
| | | (such as when it raises :class:`~pyramid.response.HTTPNotFound` or |
| | | :class:`~pyramid.response.HTTPForbidden`), the router catches the |
| | | (such as when it raises :class:`~pyramid.httpexceptions.HTTPNotFound` or |
| | | :class:`~pyramid.httpexceptions.HTTPForbidden`), the router catches the |
| | | exception, and attaches it to the request as the ``exception`` attribute. |
| | | It then attempts to find a :term:`exception view` for the exception that |
| | | was caught. If it finds an exception view callable, that callable is |
| | |
| | | :linenos: |
| | | |
| | | from pyramid.security import has_permission |
| | | from pyramid.response import HTTPForbidden |
| | | from pyramid.httpexceptions import HTTPForbidden |
| | | |
| | | def view_fn(request): |
| | | if not has_permission('edit', request.context, request): |
| | |
| | | testing.tearDown() |
| | | |
| | | def test_view_fn_forbidden(self): |
| | | from pyramid.response import HTTPForbidden |
| | | from pyramid.httpexceptions import HTTPForbidden |
| | | from my.package import view_fn |
| | | self.config.testing_securitypolicy(userid='hank', |
| | | permissive=False) |
| | |
| | | :linenos: |
| | | |
| | | config.add_view('pyramid.view.append_slash_notfound_view', |
| | | context='pyramid.response.HTTPNotFound') |
| | | context='pyramid.httpexceptions.HTTPNotFound') |
| | | |
| | | See :ref:`view_module` and :ref:`changing_the_notfound_view` for more |
| | | information about the slash-appending not found view and for a more general |
| | |
| | | .. code-block:: python |
| | | :linenos: |
| | | |
| | | from pyramid.response import HTTPNotFound |
| | | from pyramid.httpexceptions import HTTPNotFound |
| | | from pyramid.view import AppendSlashNotFoundViewFactory |
| | | |
| | | def notfound_view(context, request): |
| | |
| | | def view(request): |
| | | return Response('OK') |
| | | |
| | | You don't need to always use :class:`~pyramid.response.Response` to represent |
| | | a response. :app:`Pyramid` provides a range of different "exception" classes |
| | | which can act as response objects too. For example, an instance of the class |
| | | :class:`pyramid.response.HTTPFound` is also a valid response object |
| | | (see :ref:`http_exceptions` and ref:`http_redirect`). A view can actually |
| | | return any object that has the following attributes. |
| | | You don't need to use :class:`~pyramid.response.Response` to represent a |
| | | response. A view can actually return any object that has a ``__call__`` |
| | | method that implements the :term:`WSGI` application call interface. For |
| | | example, an instance of the following class could be successfully returned by |
| | | a view callable as a response object: |
| | | |
| | | status |
| | | The HTTP status code (including the name) for the response as a string. |
| | | E.g. ``200 OK`` or ``401 Unauthorized``. |
| | | .. code-block:: python |
| | | :linenos: |
| | | |
| | | headerlist |
| | | A sequence of tuples representing the list of headers that should be |
| | | set in the response. E.g. ``[('Content-Type', 'text/html'), |
| | | ('Content-Length', '412')]`` |
| | | class SimpleResponse(object): |
| | | def __call__(self, environ, start_response): |
| | | """ Call the ``start_response`` callback and return |
| | | an iterable """ |
| | | body = 'Hello World!' |
| | | headers = [('Content-Type', 'text/plain'), |
| | | ('Content-Length', str(len(body)))] |
| | | start_response('200 OK', headers) |
| | | return [body] |
| | | |
| | | app_iter |
| | | An iterable representing the body of the response. This can be a |
| | | list, e.g. ``['<html><head></head><body>Hello |
| | | world!</body></html>']`` or it can be a file-like object, or any |
| | | other sort of iterable. |
| | | |
| | | These attributes form the structure of the "Pyramid Response interface". |
| | | :app:`Pyramid` provides a range of different "exception" classes which can |
| | | act as response objects too. For example, an instance of the class |
| | | :class:`pyramid.httpexceptions.HTTPFound` is also a valid response object |
| | | (see :ref:`http_exceptions` and ref:`http_redirect`). |
| | | |
| | | .. index:: |
| | | single: view exceptions |
| | |
| | | |
| | | However, for convenience, a special set of exceptions exists. When one of |
| | | these exceptions is raised within a view callable, it will always cause |
| | | :app:`Pyramid` to generate a response. Two categories of special exceptions |
| | | exist: internal exceptions and HTTP exceptions. |
| | | |
| | | Internal Exceptions |
| | | ~~~~~~~~~~~~~~~~~~~ |
| | | |
| | | :exc:`pyramid.response.HTTPNotFound` and |
| | | :exc:`pyramid.response.HTTPForbidden` are exceptions often raised by Pyramid |
| | | itself when it (respectively) cannot find a view to service a request or when |
| | | authorization was forbidden by a security policy. However, they can also be |
| | | raised by application developers. |
| | | |
| | | If :exc:`~pyramid.response.HTTPNotFound` is raised within view code, the |
| | | result of the :term:`Not Found View` will be returned to the user agent which |
| | | performed the request. |
| | | |
| | | If :exc:`~pyramid.response.HTTPForbidden` is raised within view code, the |
| | | result of the :term:`Forbidden View` will be returned to the user agent which |
| | | performed the request. |
| | | |
| | | Both are exception classes which accept a single positional constructor |
| | | argument: a ``message``. In all cases, the message provided to the exception |
| | | constructor is made available to the view which :app:`Pyramid` invokes as |
| | | ``request.exception.args[0]``. |
| | | |
| | | An example: |
| | | |
| | | .. code-block:: python |
| | | :linenos: |
| | | |
| | | from pyramid.response import HTTPNotFound |
| | | |
| | | def aview(request): |
| | | raise HTTPNotFound('not found!') |
| | | :app:`Pyramid` to generate a response. These are known as :term:`HTTP |
| | | exception` objects. |
| | | |
| | | .. index:: |
| | | single: HTTP exceptions |
| | |
| | | HTTP Exceptions |
| | | ~~~~~~~~~~~~~~~ |
| | | |
| | | All classes documented in the :mod:`pyramid.response` module as inheriting |
| | | from the :class:`pryamid.response.Response` object implement the |
| | | :term:`Response` interface; an instance of any of these classes can be |
| | | returned or raised from within a view. The instance will be used as as the |
| | | view's response. |
| | | All classes documented in the :mod:`pyramid.httpexceptions` module documented |
| | | as inheriting from the :class:`pryamid.httpexceptions.HTTPException` are |
| | | :term:`http exception` objects. An instances of an HTTP exception object may |
| | | either be *returned* or *raised* from within view code. In either case |
| | | (return or raise) the instance will be used as as the view's response. |
| | | |
| | | For example, the :class:`pyramid.response.HTTPUnauthorized` exception |
| | | For example, the :class:`pyramid.httpexceptions.HTTPUnauthorized` exception |
| | | can be raised. This will cause a response to be generated with a ``401 |
| | | Unauthorized`` status: |
| | | |
| | | .. code-block:: python |
| | | :linenos: |
| | | |
| | | from pyramid.response import HTTPUnauthorized |
| | | from pyramid.httpexceptions import HTTPUnauthorized |
| | | |
| | | def aview(request): |
| | | raise HTTPUnauthorized() |
| | | |
| | | A shortcut for importing and raising an HTTP exception is the |
| | | :func:`pyramid.response.abort` function. This function accepts an HTTP |
| | | status code and raises the corresponding HTTP exception. For example, to |
| | | raise HTTPUnauthorized, instead of the above, you could do: |
| | | |
| | | .. code-block:: python |
| | | :linenos: |
| | | |
| | | from pyramid.response import abort |
| | | |
| | | def aview(request): |
| | | abort(401) |
| | | |
| | | This is the case because ``401`` is the HTTP status code for "HTTP |
| | | Unauthorized". Therefore, ``abort(401)`` is functionally equivalent to |
| | | ``raise HTTPUnauthorized()``. Other exceptions in |
| | | :mod:`pyramid.response` can be raised via |
| | | :func:`pyramid.response.abort` as well, as long as the status code |
| | | associated with the exception is provided to the function. |
| | | |
| | | An HTTP exception, instead of being raised, can alternately be *returned* |
| | | (HTTP exceptions are also valid response objects): |
| | |
| | | .. code-block:: python |
| | | :linenos: |
| | | |
| | | from pyramid.response import HTTPUnauthorized |
| | | from pyramid.httpexceptions import HTTPUnauthorized |
| | | |
| | | def aview(request): |
| | | return HTTPUnauthorized() |
| | | |
| | | A shortcut for creating an HTTP exception is the |
| | | :func:`pyramid.httpexceptions.responsecode` function. This function accepts |
| | | an HTTP status code and returns the corresponding HTTP exception. For |
| | | example, instead of importing and constructing a |
| | | :class:`~pyramid.httpexceptions.HTTPUnauthorized` response object, you can |
| | | use the :func:`~pyramid.httpexceptions.responsecode` function to construct |
| | | and return the same object. |
| | | |
| | | .. code-block:: python |
| | | :linenos: |
| | | |
| | | from pyramid.httpexceptions import responsecode |
| | | |
| | | def aview(request): |
| | | raise responsecode(401) |
| | | |
| | | This is the case because ``401`` is the HTTP status code for "HTTP |
| | | Unauthorized". Therefore, ``raise responsecode(401)`` is functionally |
| | | equivalent to ``raise HTTPUnauthorized()``. Documentation which maps each |
| | | HTTP response code to its purpose and its associated HTTP exception object is |
| | | provided within :mod:`pyramid.httpexceptions`. |
| | | |
| | | How Pyramid Uses HTTP Exceptions |
| | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| | | |
| | | HTTP exceptions are meant to be used directly by application application |
| | | developers. However, Pyramid itself will raise two HTTP exceptions at |
| | | various points during normal operations: |
| | | :exc:`pyramid.httpexceptions.HTTPNotFound` and |
| | | :exc:`pyramid.httpexceptions.HTTPForbidden`. Pyramid will raise the |
| | | :exc:`~pyramid.httpexceptions.HTTPNotFound` exception are raised when it |
| | | cannot find a view to service a request. Pyramid will raise the |
| | | :exc:`~pyramid.httpexceptions.Forbidden` exception or when authorization was |
| | | forbidden by a security policy. |
| | | |
| | | If :exc:`~pyramid.httpexceptions.HTTPNotFound` is raised by Pyramid itself or |
| | | within view code, the result of the :term:`Not Found View` will be returned |
| | | to the user agent which performed the request. |
| | | |
| | | If :exc:`~pyramid.httpexceptions.HTTPForbidden` is raised by Pyramid itself |
| | | within view code, the result of the :term:`Forbidden View` will be returned |
| | | to the user agent which performed the request. |
| | | |
| | | .. index:: |
| | | single: exception views |
| | |
| | | Custom Exception Views |
| | | ---------------------- |
| | | |
| | | The machinery which allows :exc:`~pyramid.response.HTTPNotFound`, |
| | | :exc:`~pyramid.response.HTTPForbidden` and other responses to be used as |
| | | exceptions and caught by specialized views as described in |
| | | :ref:`special_exceptions_in_callables` can also be used by application |
| | | developers to convert arbitrary exceptions to responses. |
| | | The machinery which allows HTTP exceptions to be raised and caught by |
| | | specialized views as described in :ref:`special_exceptions_in_callables` can |
| | | also be used by application developers to convert arbitrary exceptions to |
| | | responses. |
| | | |
| | | To register a view that should be called whenever a particular exception is |
| | | raised from with :app:`Pyramid` view code, use the exception class or one of |
| | |
| | | Assuming that a :term:`scan` was run to pick up this view registration, this |
| | | view callable will be invoked whenever a |
| | | ``helloworld.exceptions.ValidationFailure`` is raised by your application's |
| | | view code. The same exception raised by a custom root factory or a custom |
| | | traverser is also caught and hooked. |
| | | view code. The same exception raised by a custom root factory, a custom |
| | | traverser, or a custom view or route predicate is also caught and hooked. |
| | | |
| | | Other normal view predicates can also be used in combination with an |
| | | exception view registration: |
| | |
| | | Using a View Callable to Do an HTTP Redirect |
| | | -------------------------------------------- |
| | | |
| | | Two methods exist to redirect to another URL from within a view callable: a |
| | | short form and a long form. The short form should be preferred when |
| | | possible. |
| | | You can issue an HTTP redirect by using the |
| | | :class:`pyramid.httpexceptions.HTTPFound` class. Raising or returning an |
| | | instance of this class will cause the client to receive a "302 Found" |
| | | response. |
| | | |
| | | Short Form |
| | | ~~~~~~~~~~ |
| | | |
| | | You can issue an HTTP redirect from within a view callable by using the |
| | | :func:`pyramid.response.redirect` function. This function raises an |
| | | :class:`pyramid.response.HTTPFound` exception (a "302"), which is caught by |
| | | the default exception response handler and turned into a response. |
| | | |
| | | .. code-block:: python |
| | | :linenos: |
| | | |
| | | from pyramid.response import redirect |
| | | |
| | | def myview(request): |
| | | redirect('http://example.com') |
| | | |
| | | Long Form |
| | | ~~~~~~~~~ |
| | | |
| | | You can issue an HTTP redirect from within a view "by hand" instead of |
| | | relying on the :func:`pyramid.response.redirect` function to do it for |
| | | you. |
| | | |
| | | To do so, you can *return* a :class:`pyramid.response.HTTPFound` |
| | | To do so, you can *return* a :class:`pyramid.httpexceptions.HTTPFound` |
| | | instance. |
| | | |
| | | .. code-block:: python |
| | | :linenos: |
| | | |
| | | from pyramid.response import HTTPFound |
| | | from pyramid.httpexceptions import HTTPFound |
| | | |
| | | def myview(request): |
| | | return HTTPFound(location='http://example.com') |
| | | |
| | | Or, alternately, you can *raise* an HTTPFound exception instead of returning |
| | | one. |
| | | Alternately, you can *raise* an HTTPFound exception instead of returning one. |
| | | |
| | | .. code-block:: python |
| | | :linenos: |
| | | |
| | | from pyramid.response import HTTPFound |
| | | from pyramid.httpexceptions import HTTPFound |
| | | |
| | | def myview(request): |
| | | raise HTTPFound(location='http://example.com') |
| | | |
| | | The above form of generating a response by raising HTTPFound is completely |
| | | equivalent to ``redirect('http://example.com')``. |
| | | When the instance is raised, it is caught by the default :term:`exception |
| | | response` handler and turned into a response. |
| | | |
| | | .. index:: |
| | | single: unicode, views, and forms |
| | |
| | | :mod:`webob.exc` contains classes for each kind of error response. These |
| | | include boring, but appropriate error bodies. The exceptions exposed by this |
| | | module, when used under :app:`Pyramid`, should be imported from the |
| | | :mod:`pyramid.response` module. This import location contains subclasses and |
| | | replacements that mirror those in the original ``webob.exc``. |
| | | :mod:`pyramid.httpexceptions` module. This import location contains |
| | | subclasses and replacements that mirror those in the original ``webob.exc``. |
| | | |
| | | Each class is named ``pyramid.response.HTTP*``, where ``*`` is the reason for |
| | | the error. For instance, :class:`pyramid.response.HTTPNotFound`. It |
| | | subclasses :class:`pyramid.Response`, so you can manipulate the instances in |
| | | the same way. A typical example is: |
| | | Each class is named ``pyramid.httpexceptions.HTTP*``, where ``*`` is the |
| | | reason for the error. For instance, |
| | | :class:`pyramid.httpexceptions.HTTPNotFound` subclasses |
| | | :class:`pyramid.Response`, so you can manipulate the instances in the same |
| | | way. A typical example is: |
| | | |
| | | .. ignore-next-block |
| | | .. code-block:: python |
| | | :linenos: |
| | | |
| | | from pyramid.response import HTTPNotFound |
| | | from pyramid.response import HTTPMovedPermanently |
| | | from pyramid.httpexceptions import HTTPNotFound |
| | | from pyramid.httpexceptions import HTTPMovedPermanently |
| | | |
| | | response = HTTPNotFound('There is no such resource') |
| | | # or: |
| | |
| | | ++++++++++++ |
| | | |
| | | More details about the response object API are available in the |
| | | :mod:`pyramid.response` documentation. More details about exception responses |
| | | are in the :mod:`pyramid.response` API documentation. The `WebOb |
| | | documentation <http://pythonpaste.org/webob>`_ is also useful. |
| | | :mod:`pyramid.response` documentation. More details about exception |
| | | responses are in the :mod:`pyramid.httpexceptions` API documentation. The |
| | | `WebOb documentation <http://pythonpaste.org/webob>`_ is also useful. |
| | | |
| | |
| | | The first view configuration decorator configures the ``login`` view callable |
| | | so it will be invoked when someone visits ``/login`` (when the context is a |
| | | Wiki and the view name is ``login``). The second decorator (with context of |
| | | ``pyramid.response.HTTPForbidden``) specifies a :term:`forbidden view`. This |
| | | configures our login view to be presented to the user when :app:`Pyramid` |
| | | detects that a view invocation can not be authorized. Because we've |
| | | configured a forbidden view, the ``login`` view callable will be invoked |
| | | whenever one of our users tries to execute a view callable that they are not |
| | | allowed to invoke as determined by the :term:`authorization policy` in use. |
| | | In our application, for example, this means that if a user has not logged in, |
| | | and he tries to add or edit a Wiki page, he will be shown the login form. |
| | | Before being allowed to continue on to the add or edit form, he will have to |
| | | provide credentials that give him permission to add or edit via this login |
| | | form. |
| | | ``pyramid.httpexceptions.HTTPForbidden``) specifies a :term:`forbidden view`. |
| | | This configures our login view to be presented to the user when |
| | | :app:`Pyramid` detects that a view invocation can not be authorized. Because |
| | | we've configured a forbidden view, the ``login`` view callable will be |
| | | invoked whenever one of our users tries to execute a view callable that they |
| | | are not allowed to invoke as determined by the :term:`authorization policy` |
| | | in use. In our application, for example, this means that if a user has not |
| | | logged in, and he tries to add or edit a Wiki page, he will be shown the |
| | | login form. Before being allowed to continue on to the add or edit form, he |
| | | will have to provide credentials that give him permission to add or edit via |
| | | this login form. |
| | | |
| | | Changing Existing Views |
| | | ~~~~~~~~~~~~~~~~~~~~~~~ |
| | |
| | | |
| | | The ``view_wiki`` view callable always redirects to the URL of a Page |
| | | resource named "FrontPage". To do so, it returns an instance of the |
| | | :class:`pyramid.response.HTTPFound` class (instances of which implement the |
| | | WebOb :term:`response` interface). The :func:`pyramid.url.resource_url` API. |
| | | :func:`pyramid.url.resource_url` constructs a URL to the ``FrontPage`` page |
| | | resource (e.g. ``http://localhost:6543/FrontPage``), and uses it as the |
| | | :class:`pyramid.httpexceptions.HTTPFound` class (instances of which implement |
| | | the WebOb :term:`response` interface). The :func:`pyramid.url.resource_url` |
| | | API. :func:`pyramid.url.resource_url` constructs a URL to the ``FrontPage`` |
| | | page resource (e.g. ``http://localhost:6543/FrontPage``), and uses it as the |
| | | "location" of the HTTPFound response, forming an HTTP redirect. |
| | | |
| | | The ``view_page`` view function |
| | |
| | | from pyramid.response import HTTPFound |
| | | from pyramid.httpexceptions import HTTPFound |
| | | |
| | | from pyramid.security import remember |
| | | from pyramid.security import forget |
| | |
| | | |
| | | @view_config(context='tutorial.models.Wiki', name='login', |
| | | renderer='templates/login.pt') |
| | | @view_config(context='pyramid.response.HTTPForbidden', |
| | | @view_config(context='pyramid.httpexceptions.HTTPForbidden', |
| | | renderer='templates/login.pt') |
| | | def login(request): |
| | | login_url = resource_url(request.context, request, 'login') |
| | |
| | | from docutils.core import publish_parts |
| | | import re |
| | | |
| | | from pyramid.response import HTTPFound |
| | | from pyramid.httpexceptions import HTTPFound |
| | | from pyramid.url import resource_url |
| | | from pyramid.view import view_config |
| | | from pyramid.security import authenticated_userid |
| | |
| | | from docutils.core import publish_parts |
| | | import re |
| | | |
| | | from pyramid.response import HTTPFound |
| | | from pyramid.httpexceptions import HTTPFound |
| | | from pyramid.url import resource_url |
| | | from pyramid.view import view_config |
| | | |
| | |
| | | :language: python |
| | | |
| | | The ``view_wiki`` function returns an instance of the |
| | | :class:`pyramid.response.HTTPFound` class (instances of which implement the |
| | | WebOb :term:`response` interface), It will use the |
| | | :class:`pyramid.httpexceptions.HTTPFound` class (instances of which implement |
| | | the WebOb :term:`response` interface), It will use the |
| | | :func:`pyramid.url.route_url` API to construct a URL to the ``FrontPage`` |
| | | page (e.g. ``http://localhost:6543/FrontPage``), and will use it as the |
| | | "location" of the HTTPFound response, forming an HTTP redirect. |
| | |
| | | config.add_view('tutorial.views.edit_page', route_name='edit_page', |
| | | renderer='tutorial:templates/edit.pt', permission='edit') |
| | | config.add_view('tutorial.login.login', |
| | | context='pyramid.response.HTTPForbidden', |
| | | context='pyramid.httpexceptions.HTTPForbidden', |
| | | renderer='tutorial:templates/login.pt') |
| | | return config.make_wsgi_app() |
| | | |
| | |
| | | from pyramid.response import HTTPFound |
| | | from pyramid.httpexceptions import HTTPFound |
| | | from pyramid.security import remember |
| | | from pyramid.security import forget |
| | | from pyramid.url import route_url |
| | |
| | | |
| | | from docutils.core import publish_parts |
| | | |
| | | from pyramid.response import HTTPFound |
| | | from pyramid.httpexceptions import HTTPFound |
| | | from pyramid.security import authenticated_userid |
| | | from pyramid.url import route_url |
| | | |
| | |
| | | |
| | | from docutils.core import publish_parts |
| | | |
| | | from pyramid.response import HTTPFound |
| | | from pyramid.httpexceptions import HTTPFound |
| | | from pyramid.url import route_url |
| | | |
| | | from tutorial.models import DBSession |
| | |
| | | from within view code; when raised, this exception view will render the |
| | | exception to a response. |
| | | |
| | | New convenience functions named :func:`pyramid.httpexceptions.abort` and |
| | | :func:`pyramid.httpexceptions.redirect` perform the equivalent of their |
| | | Pylons brethren when an HTTP exception handler is registered. These |
| | | functions take advantage of the newly registered exception view for |
| | | :exc:`webob.exc.HTTPException`. |
| | | |
| | | To allow for configuration of this feature, the :term:`Configurator` now |
| | | accepts an additional keyword argument named ``httpexception_view``. By |
| | | default, this argument is populated with a default exception view function |
| | |
| | | |
| | | Minor Feature Additions |
| | | ----------------------- |
| | | |
| | | - A function named :func:`pyramid.httpexceptions.responsecode` is a shortcut |
| | | that can be used to create HTTP exception response objects using an HTTP |
| | | integer status code. |
| | | |
| | | - Integers and longs passed as ``elements`` to |
| | | :func:`pyramid.url.resource_url` or |
| | |
| | | expected an environ object in BFG 1.0 and before). In a future version, |
| | | these methods will be removed entirely. |
| | | |
| | | - A custom request factory is now required to return a response object that |
| | | - A custom request factory is now required to return a request object that |
| | | has a ``response`` attribute (or "reified"/lazy property) if they the |
| | | request is meant to be used in a view that uses a renderer. This |
| | | ``response`` attribute should be an instance of the class |
| | |
| | | from pyramid.compat import any |
| | | from pyramid.events import ApplicationCreated |
| | | from pyramid.exceptions import ConfigurationError |
| | | from pyramid.response import default_exceptionresponse_view |
| | | from pyramid.response import HTTPForbidden |
| | | from pyramid.response import HTTPNotFound |
| | | from pyramid.exceptions import PredicateMismatch |
| | | from pyramid.httpexceptions import default_exceptionresponse_view |
| | | from pyramid.httpexceptions import HTTPForbidden |
| | | from pyramid.httpexceptions import HTTPNotFound |
| | | from pyramid.i18n import get_localizer |
| | | from pyramid.log import make_stream_logger |
| | | from pyramid.mako_templating import renderer_factory as mako_renderer_factory |
| | |
| | | from zope.configuration.exceptions import ConfigurationError as ZCE |
| | | |
| | | from pyramid.response import HTTPNotFound |
| | | from pyramid.response import HTTPForbidden |
| | | from pyramid.httpexceptions import HTTPNotFound |
| | | from pyramid.httpexceptions import HTTPForbidden |
| | | |
| | | NotFound = HTTPNotFound # bw compat |
| | | Forbidden = HTTPForbidden # bw compat |
| | | |
| | | class PredicateMismatch(NotFound): |
| | | class PredicateMismatch(HTTPNotFound): |
| | | """ |
| | | Internal exception (not an API) raised by multiviews when no |
| | | view matches. This exception subclasses the ``NotFound`` |
| | |
| | | ``location``, which indicates the location to which to redirect. |
| | | """ |
| | | |
| | | from pyramid.response import * # API |
| | | import types |
| | | from string import Template |
| | | |
| | | from zope.interface import implements |
| | | |
| | | from webob import html_escape as _html_escape |
| | | |
| | | from pyramid.interfaces import IExceptionResponse |
| | | from pyramid.response import Response |
| | | |
| | | def _no_escape(value): |
| | | if value is None: |
| | | return '' |
| | | if not isinstance(value, basestring): |
| | | if hasattr(value, '__unicode__'): |
| | | value = unicode(value) |
| | | else: |
| | | value = str(value) |
| | | return value |
| | | |
| | | class HTTPException(Exception): # bw compat |
| | | pass |
| | | |
| | | class WSGIHTTPException(Response, HTTPException): |
| | | implements(IExceptionResponse) |
| | | |
| | | ## You should set in subclasses: |
| | | # code = 200 |
| | | # title = 'OK' |
| | | # explanation = 'why this happens' |
| | | # body_template_obj = Template('response template') |
| | | |
| | | # differences from webob.exc.WSGIHTTPException: |
| | | # - not a WSGI application (just a response) |
| | | # |
| | | # as a result: |
| | | # |
| | | # - bases plaintext vs. html result on self.content_type rather than |
| | | # on request accept header |
| | | # |
| | | # - doesn't add request.environ keys to template substitutions unless |
| | | # 'request' is passed as a constructor keyword argument. |
| | | # |
| | | # - doesn't use "strip_tags" (${br} placeholder for <br/>, no other html |
| | | # in default body template) |
| | | # |
| | | # - sets a default app_iter if no body, app_iter, or unicode_body is |
| | | # passed using a template (ala the replaced version's "generate_response") |
| | | # |
| | | # - explicitly sets self.message = detail to prevent whining by Python |
| | | # 2.6.5+ access of Exception.message |
| | | # |
| | | # - its base class of HTTPException is no longer a Python 2.4 compatibility |
| | | # shim; it's purely a base class that inherits from Exception. This |
| | | # implies that this class' ``exception`` property always returns |
| | | # ``self`` (only for bw compat at this point). |
| | | # |
| | | # - documentation improvements (Pyramid-specific docstrings where necessary) |
| | | # |
| | | code = None |
| | | title = None |
| | | explanation = '' |
| | | body_template_obj = Template('''\ |
| | | ${explanation}${br}${br} |
| | | ${detail} |
| | | ${html_comment} |
| | | ''') |
| | | |
| | | plain_template_obj = Template('''\ |
| | | ${status} |
| | | |
| | | ${body}''') |
| | | |
| | | html_template_obj = Template('''\ |
| | | <html> |
| | | <head> |
| | | <title>${status}</title> |
| | | </head> |
| | | <body> |
| | | <h1>${status}</h1> |
| | | ${body} |
| | | </body> |
| | | </html>''') |
| | | |
| | | ## Set this to True for responses that should have no request body |
| | | empty_body = False |
| | | |
| | | def __init__(self, detail=None, headers=None, comment=None, |
| | | body_template=None, **kw): |
| | | status = '%s %s' % (self.code, self.title) |
| | | Response.__init__(self, status=status, **kw) |
| | | Exception.__init__(self, detail) |
| | | self.detail = self.message = detail |
| | | if headers: |
| | | self.headers.extend(headers) |
| | | self.comment = comment |
| | | if body_template is not None: |
| | | self.body_template = body_template |
| | | self.body_template_obj = Template(body_template) |
| | | |
| | | if self.empty_body: |
| | | del self.content_type |
| | | del self.content_length |
| | | elif not ('unicode_body' in kw or 'body' in kw or 'app_iter' in kw): |
| | | self.app_iter = self._default_app_iter() |
| | | |
| | | def __str__(self): |
| | | return self.detail or self.explanation |
| | | |
| | | def _default_app_iter(self): |
| | | # This is a generator which defers the creation of the response page |
| | | # body; we use a generator because we want to ensure that if |
| | | # attributes of this response are changed after it is constructed, we |
| | | # use the changed values rather than the values at time of construction |
| | | # (e.g. self.content_type or self.charset). |
| | | html_comment = '' |
| | | comment = self.comment or '' |
| | | content_type = self.content_type or '' |
| | | if 'html' in content_type: |
| | | escape = _html_escape |
| | | page_template = self.html_template_obj |
| | | br = '<br/>' |
| | | if comment: |
| | | html_comment = '<!-- %s -->' % escape(comment) |
| | | else: |
| | | escape = _no_escape |
| | | page_template = self.plain_template_obj |
| | | br = '\n' |
| | | if comment: |
| | | html_comment = escape(comment) |
| | | args = { |
| | | 'br':br, |
| | | 'explanation': escape(self.explanation), |
| | | 'detail': escape(self.detail or ''), |
| | | 'comment': escape(comment), |
| | | 'html_comment':html_comment, |
| | | } |
| | | body_tmpl = self.body_template_obj |
| | | if WSGIHTTPException.body_template_obj is not body_tmpl: |
| | | # Custom template; add headers to args |
| | | environ = self.environ |
| | | if environ is not None: |
| | | for k, v in environ.items(): |
| | | args[k] = escape(v) |
| | | for k, v in self.headers.items(): |
| | | args[k.lower()] = escape(v) |
| | | body = body_tmpl.substitute(args) |
| | | page = page_template.substitute(status=self.status, body=body) |
| | | if isinstance(page, unicode): |
| | | page = page.encode(self.charset) |
| | | yield page |
| | | raise StopIteration |
| | | |
| | | @property |
| | | def exception(self): |
| | | # bw compat only |
| | | return self |
| | | wsgi_response = exception # bw compat only |
| | | |
| | | class HTTPError(WSGIHTTPException): |
| | | """ |
| | | base class for status codes in the 400's and 500's |
| | | |
| | | This is an exception which indicates that an error has occurred, |
| | | and that any work in progress should not be committed. These are |
| | | typically results in the 400's and 500's. |
| | | """ |
| | | |
| | | class HTTPRedirection(WSGIHTTPException): |
| | | """ |
| | | base class for 300's status code (redirections) |
| | | |
| | | This is an abstract base class for 3xx redirection. It indicates |
| | | that further action needs to be taken by the user agent in order |
| | | to fulfill the request. It does not necessarly signal an error |
| | | condition. |
| | | """ |
| | | |
| | | class HTTPOk(WSGIHTTPException): |
| | | """ |
| | | Base class for the 200's status code (successful responses) |
| | | |
| | | code: 200, title: OK |
| | | """ |
| | | code = 200 |
| | | title = 'OK' |
| | | |
| | | ############################################################ |
| | | ## 2xx success |
| | | ############################################################ |
| | | |
| | | class HTTPCreated(HTTPOk): |
| | | """ |
| | | subclass of :class:`~HTTPOk` |
| | | |
| | | This indicates that request has been fulfilled and resulted in a new |
| | | resource being created. |
| | | |
| | | code: 201, title: Created |
| | | """ |
| | | code = 201 |
| | | title = 'Created' |
| | | |
| | | class HTTPAccepted(HTTPOk): |
| | | """ |
| | | subclass of :class:`~HTTPOk` |
| | | |
| | | This indicates that the request has been accepted for processing, but the |
| | | processing has not been completed. |
| | | |
| | | code: 202, title: Accepted |
| | | """ |
| | | code = 202 |
| | | title = 'Accepted' |
| | | explanation = 'The request is accepted for processing.' |
| | | |
| | | class HTTPNonAuthoritativeInformation(HTTPOk): |
| | | """ |
| | | subclass of :class:`~HTTPOk` |
| | | |
| | | This indicates that the returned metainformation in the entity-header is |
| | | not the definitive set as available from the origin server, but is |
| | | gathered from a local or a third-party copy. |
| | | |
| | | code: 203, title: Non-Authoritative Information |
| | | """ |
| | | code = 203 |
| | | title = 'Non-Authoritative Information' |
| | | |
| | | class HTTPNoContent(HTTPOk): |
| | | """ |
| | | subclass of :class:`~HTTPOk` |
| | | |
| | | This indicates that the server has fulfilled the request but does |
| | | not need to return an entity-body, and might want to return updated |
| | | metainformation. |
| | | |
| | | code: 204, title: No Content |
| | | """ |
| | | code = 204 |
| | | title = 'No Content' |
| | | empty_body = True |
| | | |
| | | class HTTPResetContent(HTTPOk): |
| | | """ |
| | | subclass of :class:`~HTTPOk` |
| | | |
| | | This indicates that the the server has fulfilled the request and |
| | | the user agent SHOULD reset the document view which caused the |
| | | request to be sent. |
| | | |
| | | code: 205, title: Reset Content |
| | | """ |
| | | code = 205 |
| | | title = 'Reset Content' |
| | | empty_body = True |
| | | |
| | | class HTTPPartialContent(HTTPOk): |
| | | """ |
| | | subclass of :class:`~HTTPOk` |
| | | |
| | | This indicates that the server has fulfilled the partial GET |
| | | request for the resource. |
| | | |
| | | code: 206, title: Partial Content |
| | | """ |
| | | code = 206 |
| | | title = 'Partial Content' |
| | | |
| | | ## FIXME: add 207 Multi-Status (but it's complicated) |
| | | |
| | | ############################################################ |
| | | ## 3xx redirection |
| | | ############################################################ |
| | | |
| | | class _HTTPMove(HTTPRedirection): |
| | | """ |
| | | redirections which require a Location field |
| | | |
| | | Since a 'Location' header is a required attribute of 301, 302, 303, |
| | | 305 and 307 (but not 304), this base class provides the mechanics to |
| | | make this easy. |
| | | |
| | | You must provide a ``location`` keyword argument. |
| | | """ |
| | | # differences from webob.exc._HTTPMove: |
| | | # |
| | | # - not a wsgi app |
| | | # |
| | | # - ${location} isn't wrapped in an <a> tag in body |
| | | # |
| | | # - location keyword arg defaults to '' |
| | | # |
| | | # - ``add_slash`` argument is no longer accepted: code that passes |
| | | # add_slash argument to the constructor will receive an exception. |
| | | explanation = 'The resource has been moved to' |
| | | body_template_obj = Template('''\ |
| | | ${explanation} ${location}; |
| | | you should be redirected automatically. |
| | | ${detail} |
| | | ${html_comment}''') |
| | | |
| | | def __init__(self, detail=None, headers=None, comment=None, |
| | | body_template=None, location='', **kw): |
| | | super(_HTTPMove, self).__init__( |
| | | detail=detail, headers=headers, comment=comment, |
| | | body_template=body_template, location=location, **kw) |
| | | |
| | | class HTTPMultipleChoices(_HTTPMove): |
| | | """ |
| | | subclass of :class:`~_HTTPMove` |
| | | |
| | | This indicates that the requested resource corresponds to any one |
| | | of a set of representations, each with its own specific location, |
| | | and agent-driven negotiation information is being provided so that |
| | | the user can select a preferred representation and redirect its |
| | | request to that location. |
| | | |
| | | code: 300, title: Multiple Choices |
| | | """ |
| | | code = 300 |
| | | title = 'Multiple Choices' |
| | | |
| | | class HTTPMovedPermanently(_HTTPMove): |
| | | """ |
| | | subclass of :class:`~_HTTPMove` |
| | | |
| | | This indicates that the requested resource has been assigned a new |
| | | permanent URI and any future references to this resource SHOULD use |
| | | one of the returned URIs. |
| | | |
| | | code: 301, title: Moved Permanently |
| | | """ |
| | | code = 301 |
| | | title = 'Moved Permanently' |
| | | |
| | | class HTTPFound(_HTTPMove): |
| | | """ |
| | | subclass of :class:`~_HTTPMove` |
| | | |
| | | This indicates that the requested resource resides temporarily under |
| | | a different URI. |
| | | |
| | | code: 302, title: Found |
| | | """ |
| | | code = 302 |
| | | title = 'Found' |
| | | explanation = 'The resource was found at' |
| | | |
| | | # This one is safe after a POST (the redirected location will be |
| | | # retrieved with GET): |
| | | class HTTPSeeOther(_HTTPMove): |
| | | """ |
| | | subclass of :class:`~_HTTPMove` |
| | | |
| | | This indicates that the response to the request can be found under |
| | | a different URI and SHOULD be retrieved using a GET method on that |
| | | resource. |
| | | |
| | | code: 303, title: See Other |
| | | """ |
| | | code = 303 |
| | | title = 'See Other' |
| | | |
| | | class HTTPNotModified(HTTPRedirection): |
| | | """ |
| | | subclass of :class:`~HTTPRedirection` |
| | | |
| | | This indicates that if the client has performed a conditional GET |
| | | request and access is allowed, but the document has not been |
| | | modified, the server SHOULD respond with this status code. |
| | | |
| | | code: 304, title: Not Modified |
| | | """ |
| | | # FIXME: this should include a date or etag header |
| | | code = 304 |
| | | title = 'Not Modified' |
| | | empty_body = True |
| | | |
| | | class HTTPUseProxy(_HTTPMove): |
| | | """ |
| | | subclass of :class:`~_HTTPMove` |
| | | |
| | | This indicates that the requested resource MUST be accessed through |
| | | the proxy given by the Location field. |
| | | |
| | | code: 305, title: Use Proxy |
| | | """ |
| | | # Not a move, but looks a little like one |
| | | code = 305 |
| | | title = 'Use Proxy' |
| | | explanation = ( |
| | | 'The resource must be accessed through a proxy located at') |
| | | |
| | | class HTTPTemporaryRedirect(_HTTPMove): |
| | | """ |
| | | subclass of :class:`~_HTTPMove` |
| | | |
| | | This indicates that the requested resource resides temporarily |
| | | under a different URI. |
| | | |
| | | code: 307, title: Temporary Redirect |
| | | """ |
| | | code = 307 |
| | | title = 'Temporary Redirect' |
| | | |
| | | ############################################################ |
| | | ## 4xx client error |
| | | ############################################################ |
| | | |
| | | class HTTPClientError(HTTPError): |
| | | """ |
| | | base class for the 400's, where the client is in error |
| | | |
| | | This is an error condition in which the client is presumed to be |
| | | in-error. This is an expected problem, and thus is not considered |
| | | a bug. A server-side traceback is not warranted. Unless specialized, |
| | | this is a '400 Bad Request' |
| | | """ |
| | | code = 400 |
| | | title = 'Bad Request' |
| | | explanation = ('The server could not comply with the request since ' |
| | | 'it is either malformed or otherwise incorrect.') |
| | | |
| | | class HTTPBadRequest(HTTPClientError): |
| | | pass |
| | | |
| | | class HTTPUnauthorized(HTTPClientError): |
| | | """ |
| | | subclass of :class:`~HTTPClientError` |
| | | |
| | | This indicates that the request requires user authentication. |
| | | |
| | | code: 401, title: Unauthorized |
| | | """ |
| | | code = 401 |
| | | title = 'Unauthorized' |
| | | explanation = ( |
| | | 'This server could not verify that you are authorized to ' |
| | | 'access the document you requested. Either you supplied the ' |
| | | 'wrong credentials (e.g., bad password), or your browser ' |
| | | 'does not understand how to supply the credentials required.') |
| | | |
| | | class HTTPPaymentRequired(HTTPClientError): |
| | | """ |
| | | subclass of :class:`~HTTPClientError` |
| | | |
| | | code: 402, title: Payment Required |
| | | """ |
| | | code = 402 |
| | | title = 'Payment Required' |
| | | explanation = ('Access was denied for financial reasons.') |
| | | |
| | | class HTTPForbidden(HTTPClientError): |
| | | """ |
| | | subclass of :class:`~HTTPClientError` |
| | | |
| | | This indicates that the server understood the request, but is |
| | | refusing to fulfill it. |
| | | |
| | | code: 403, title: Forbidden |
| | | |
| | | Raise this exception within :term:`view` code to immediately return the |
| | | :term:`forbidden view` to the invoking user. Usually this is a basic |
| | | ``403`` page, but the forbidden view can be customized as necessary. See |
| | | :ref:`changing_the_forbidden_view`. A ``Forbidden`` exception will be |
| | | the ``context`` of a :term:`Forbidden View`. |
| | | |
| | | This exception's constructor treats two arguments specially. The first |
| | | argument, ``detail``, should be a string. The value of this string will |
| | | be used as the ``message`` attribute of the exception object. The second |
| | | special keyword argument, ``result`` is usually an instance of |
| | | :class:`pyramid.security.Denied` or :class:`pyramid.security.ACLDenied` |
| | | each of which indicates a reason for the forbidden error. However, |
| | | ``result`` is also permitted to be just a plain boolean ``False`` object |
| | | or ``None``. The ``result`` value will be used as the ``result`` |
| | | attribute of the exception object. It defaults to ``None``. |
| | | |
| | | The :term:`Forbidden View` can use the attributes of a Forbidden |
| | | exception as necessary to provide extended information in an error |
| | | report shown to a user. |
| | | """ |
| | | # differences from webob.exc.HTTPForbidden: |
| | | # |
| | | # - accepts a ``result`` keyword argument |
| | | # |
| | | # - overrides constructor to set ``self.result`` |
| | | # |
| | | # differences from older ``pyramid.exceptions.Forbidden``: |
| | | # |
| | | # - ``result`` must be passed as a keyword argument. |
| | | # |
| | | code = 403 |
| | | title = 'Forbidden' |
| | | explanation = ('Access was denied to this resource.') |
| | | def __init__(self, detail=None, headers=None, comment=None, |
| | | body_template=None, result=None, **kw): |
| | | HTTPClientError.__init__(self, detail=detail, headers=headers, |
| | | comment=comment, body_template=body_template, |
| | | **kw) |
| | | self.result = result |
| | | |
| | | class HTTPNotFound(HTTPClientError): |
| | | """ |
| | | subclass of :class:`~HTTPClientError` |
| | | |
| | | This indicates that the server did not find anything matching the |
| | | Request-URI. |
| | | |
| | | code: 404, title: Not Found |
| | | |
| | | Raise this exception within :term:`view` code to immediately |
| | | return the :term:`Not Found view` to the invoking user. Usually |
| | | this is a basic ``404`` page, but the Not Found view can be |
| | | customized as necessary. See :ref:`changing_the_notfound_view`. |
| | | |
| | | This exception's constructor accepts a ``detail`` argument |
| | | (the first argument), which should be a string. The value of this |
| | | string will be available as the ``message`` attribute of this exception, |
| | | for availability to the :term:`Not Found View`. |
| | | """ |
| | | code = 404 |
| | | title = 'Not Found' |
| | | explanation = ('The resource could not be found.') |
| | | |
| | | class HTTPMethodNotAllowed(HTTPClientError): |
| | | """ |
| | | subclass of :class:`~HTTPClientError` |
| | | |
| | | This indicates that the method specified in the Request-Line is |
| | | not allowed for the resource identified by the Request-URI. |
| | | |
| | | code: 405, title: Method Not Allowed |
| | | """ |
| | | # differences from webob.exc.HTTPMethodNotAllowed: |
| | | # |
| | | # - body_template_obj not overridden (it tried to use request environ's |
| | | # REQUEST_METHOD) |
| | | code = 405 |
| | | title = 'Method Not Allowed' |
| | | |
| | | class HTTPNotAcceptable(HTTPClientError): |
| | | """ |
| | | subclass of :class:`~HTTPClientError` |
| | | |
| | | This indicates the resource identified by the request is only |
| | | capable of generating response entities which have content |
| | | characteristics not acceptable according to the accept headers |
| | | sent in the request. |
| | | |
| | | code: 406, title: Not Acceptable |
| | | """ |
| | | # differences from webob.exc.HTTPNotAcceptable: |
| | | # |
| | | # - body_template_obj not overridden (it tried to use request environ's |
| | | # HTTP_ACCEPT) |
| | | code = 406 |
| | | title = 'Not Acceptable' |
| | | |
| | | class HTTPProxyAuthenticationRequired(HTTPClientError): |
| | | """ |
| | | subclass of :class:`~HTTPClientError` |
| | | |
| | | This is similar to 401, but indicates that the client must first |
| | | authenticate itself with the proxy. |
| | | |
| | | code: 407, title: Proxy Authentication Required |
| | | """ |
| | | code = 407 |
| | | title = 'Proxy Authentication Required' |
| | | explanation = ('Authentication with a local proxy is needed.') |
| | | |
| | | class HTTPRequestTimeout(HTTPClientError): |
| | | """ |
| | | subclass of :class:`~HTTPClientError` |
| | | |
| | | This indicates that the client did not produce a request within |
| | | the time that the server was prepared to wait. |
| | | |
| | | code: 408, title: Request Timeout |
| | | """ |
| | | code = 408 |
| | | title = 'Request Timeout' |
| | | explanation = ('The server has waited too long for the request to ' |
| | | 'be sent by the client.') |
| | | |
| | | class HTTPConflict(HTTPClientError): |
| | | """ |
| | | subclass of :class:`~HTTPClientError` |
| | | |
| | | This indicates that the request could not be completed due to a |
| | | conflict with the current state of the resource. |
| | | |
| | | code: 409, title: Conflict |
| | | """ |
| | | code = 409 |
| | | title = 'Conflict' |
| | | explanation = ('There was a conflict when trying to complete ' |
| | | 'your request.') |
| | | |
| | | class HTTPGone(HTTPClientError): |
| | | """ |
| | | subclass of :class:`~HTTPClientError` |
| | | |
| | | This indicates that the requested resource is no longer available |
| | | at the server and no forwarding address is known. |
| | | |
| | | code: 410, title: Gone |
| | | """ |
| | | code = 410 |
| | | title = 'Gone' |
| | | explanation = ('This resource is no longer available. No forwarding ' |
| | | 'address is given.') |
| | | |
| | | class HTTPLengthRequired(HTTPClientError): |
| | | """ |
| | | subclass of :class:`~HTTPClientError` |
| | | |
| | | This indicates that the the server refuses to accept the request |
| | | without a defined Content-Length. |
| | | |
| | | code: 411, title: Length Required |
| | | """ |
| | | code = 411 |
| | | title = 'Length Required' |
| | | explanation = ('Content-Length header required.') |
| | | |
| | | class HTTPPreconditionFailed(HTTPClientError): |
| | | """ |
| | | subclass of :class:`~HTTPClientError` |
| | | |
| | | This indicates that the precondition given in one or more of the |
| | | request-header fields evaluated to false when it was tested on the |
| | | server. |
| | | |
| | | code: 412, title: Precondition Failed |
| | | """ |
| | | code = 412 |
| | | title = 'Precondition Failed' |
| | | explanation = ('Request precondition failed.') |
| | | |
| | | class HTTPRequestEntityTooLarge(HTTPClientError): |
| | | """ |
| | | subclass of :class:`~HTTPClientError` |
| | | |
| | | This indicates that the server is refusing to process a request |
| | | because the request entity is larger than the server is willing or |
| | | able to process. |
| | | |
| | | code: 413, title: Request Entity Too Large |
| | | """ |
| | | code = 413 |
| | | title = 'Request Entity Too Large' |
| | | explanation = ('The body of your request was too large for this server.') |
| | | |
| | | class HTTPRequestURITooLong(HTTPClientError): |
| | | """ |
| | | subclass of :class:`~HTTPClientError` |
| | | |
| | | This indicates that the server is refusing to service the request |
| | | because the Request-URI is longer than the server is willing to |
| | | interpret. |
| | | |
| | | code: 414, title: Request-URI Too Long |
| | | """ |
| | | code = 414 |
| | | title = 'Request-URI Too Long' |
| | | explanation = ('The request URI was too long for this server.') |
| | | |
| | | class HTTPUnsupportedMediaType(HTTPClientError): |
| | | """ |
| | | subclass of :class:`~HTTPClientError` |
| | | |
| | | This indicates that the server is refusing to service the request |
| | | because the entity of the request is in a format not supported by |
| | | the requested resource for the requested method. |
| | | |
| | | code: 415, title: Unsupported Media Type |
| | | """ |
| | | # differences from webob.exc.HTTPUnsupportedMediaType: |
| | | # |
| | | # - body_template_obj not overridden (it tried to use request environ's |
| | | # CONTENT_TYPE) |
| | | code = 415 |
| | | title = 'Unsupported Media Type' |
| | | |
| | | class HTTPRequestRangeNotSatisfiable(HTTPClientError): |
| | | """ |
| | | subclass of :class:`~HTTPClientError` |
| | | |
| | | The server SHOULD return a response with this status code if a |
| | | request included a Range request-header field, and none of the |
| | | range-specifier values in this field overlap the current extent |
| | | of the selected resource, and the request did not include an |
| | | If-Range request-header field. |
| | | |
| | | code: 416, title: Request Range Not Satisfiable |
| | | """ |
| | | code = 416 |
| | | title = 'Request Range Not Satisfiable' |
| | | explanation = ('The Range requested is not available.') |
| | | |
| | | class HTTPExpectationFailed(HTTPClientError): |
| | | """ |
| | | subclass of :class:`~HTTPClientError` |
| | | |
| | | This indidcates that the expectation given in an Expect |
| | | request-header field could not be met by this server. |
| | | |
| | | code: 417, title: Expectation Failed |
| | | """ |
| | | code = 417 |
| | | title = 'Expectation Failed' |
| | | explanation = ('Expectation failed.') |
| | | |
| | | class HTTPUnprocessableEntity(HTTPClientError): |
| | | """ |
| | | subclass of :class:`~HTTPClientError` |
| | | |
| | | This indicates that the server is unable to process the contained |
| | | instructions. Only for WebDAV. |
| | | |
| | | code: 422, title: Unprocessable Entity |
| | | """ |
| | | ## Note: from WebDAV |
| | | code = 422 |
| | | title = 'Unprocessable Entity' |
| | | explanation = 'Unable to process the contained instructions' |
| | | |
| | | class HTTPLocked(HTTPClientError): |
| | | """ |
| | | subclass of :class:`~HTTPClientError` |
| | | |
| | | This indicates that the resource is locked. Only for WebDAV |
| | | |
| | | code: 423, title: Locked |
| | | """ |
| | | ## Note: from WebDAV |
| | | code = 423 |
| | | title = 'Locked' |
| | | explanation = ('The resource is locked') |
| | | |
| | | class HTTPFailedDependency(HTTPClientError): |
| | | """ |
| | | subclass of :class:`~HTTPClientError` |
| | | |
| | | This indicates that the method could not be performed because the |
| | | requested action depended on another action and that action failed. |
| | | Only for WebDAV. |
| | | |
| | | code: 424, title: Failed Dependency |
| | | """ |
| | | ## Note: from WebDAV |
| | | code = 424 |
| | | title = 'Failed Dependency' |
| | | explanation = ( |
| | | 'The method could not be performed because the requested ' |
| | | 'action dependended on another action and that action failed') |
| | | |
| | | ############################################################ |
| | | ## 5xx Server Error |
| | | ############################################################ |
| | | # Response status codes beginning with the digit "5" indicate cases in |
| | | # which the server is aware that it has erred or is incapable of |
| | | # performing the request. Except when responding to a HEAD request, the |
| | | # server SHOULD include an entity containing an explanation of the error |
| | | # situation, and whether it is a temporary or permanent condition. User |
| | | # agents SHOULD display any included entity to the user. These response |
| | | # codes are applicable to any request method. |
| | | |
| | | class HTTPServerError(HTTPError): |
| | | """ |
| | | base class for the 500's, where the server is in-error |
| | | |
| | | This is an error condition in which the server is presumed to be |
| | | in-error. This is usually unexpected, and thus requires a traceback; |
| | | ideally, opening a support ticket for the customer. Unless specialized, |
| | | this is a '500 Internal Server Error' |
| | | """ |
| | | code = 500 |
| | | title = 'Internal Server Error' |
| | | explanation = ( |
| | | 'The server has either erred or is incapable of performing ' |
| | | 'the requested operation.') |
| | | |
| | | class HTTPInternalServerError(HTTPServerError): |
| | | pass |
| | | |
| | | class HTTPNotImplemented(HTTPServerError): |
| | | """ |
| | | subclass of :class:`~HTTPServerError` |
| | | |
| | | This indicates that the server does not support the functionality |
| | | required to fulfill the request. |
| | | |
| | | code: 501, title: Not Implemented |
| | | """ |
| | | # differences from webob.exc.HTTPNotAcceptable: |
| | | # |
| | | # - body_template_obj not overridden (it tried to use request environ's |
| | | # REQUEST_METHOD) |
| | | code = 501 |
| | | title = 'Not Implemented' |
| | | |
| | | class HTTPBadGateway(HTTPServerError): |
| | | """ |
| | | subclass of :class:`~HTTPServerError` |
| | | |
| | | This indicates that the server, while acting as a gateway or proxy, |
| | | received an invalid response from the upstream server it accessed |
| | | in attempting to fulfill the request. |
| | | |
| | | code: 502, title: Bad Gateway |
| | | """ |
| | | code = 502 |
| | | title = 'Bad Gateway' |
| | | explanation = ('Bad gateway.') |
| | | |
| | | class HTTPServiceUnavailable(HTTPServerError): |
| | | """ |
| | | subclass of :class:`~HTTPServerError` |
| | | |
| | | This indicates that the server is currently unable to handle the |
| | | request due to a temporary overloading or maintenance of the server. |
| | | |
| | | code: 503, title: Service Unavailable |
| | | """ |
| | | code = 503 |
| | | title = 'Service Unavailable' |
| | | explanation = ('The server is currently unavailable. ' |
| | | 'Please try again at a later time.') |
| | | |
| | | class HTTPGatewayTimeout(HTTPServerError): |
| | | """ |
| | | subclass of :class:`~HTTPServerError` |
| | | |
| | | This indicates that the server, while acting as a gateway or proxy, |
| | | did not receive a timely response from the upstream server specified |
| | | by the URI (e.g. HTTP, FTP, LDAP) or some other auxiliary server |
| | | (e.g. DNS) it needed to access in attempting to complete the request. |
| | | |
| | | code: 504, title: Gateway Timeout |
| | | """ |
| | | code = 504 |
| | | title = 'Gateway Timeout' |
| | | explanation = ('The gateway has timed out.') |
| | | |
| | | class HTTPVersionNotSupported(HTTPServerError): |
| | | """ |
| | | subclass of :class:`~HTTPServerError` |
| | | |
| | | This indicates that the server does not support, or refuses to |
| | | support, the HTTP protocol version that was used in the request |
| | | message. |
| | | |
| | | code: 505, title: HTTP Version Not Supported |
| | | """ |
| | | code = 505 |
| | | title = 'HTTP Version Not Supported' |
| | | explanation = ('The HTTP version is not supported.') |
| | | |
| | | class HTTPInsufficientStorage(HTTPServerError): |
| | | """ |
| | | subclass of :class:`~HTTPServerError` |
| | | |
| | | This indicates that the server does not have enough space to save |
| | | the resource. |
| | | |
| | | code: 507, title: Insufficient Storage |
| | | """ |
| | | code = 507 |
| | | title = 'Insufficient Storage' |
| | | explanation = ('There was not enough space to save the resource') |
| | | |
| | | def responsecode(status_code, **kw): |
| | | """Creates an HTTP exception based on a status code. Example:: |
| | | |
| | | raise responsecode(404) # raises an HTTPNotFound exception. |
| | | |
| | | The values passed as ``kw`` are provided to the exception's constructor. |
| | | """ |
| | | exc = status_map[status_code](**kw) |
| | | return exc |
| | | |
| | | def default_exceptionresponse_view(context, request): |
| | | if not isinstance(context, Exception): |
| | | # backwards compat for an exception response view registered via |
| | | # config.set_notfound_view or config.set_forbidden_view |
| | | # instead of as a proper exception view |
| | | context = request.exception or context |
| | | return context |
| | | |
| | | status_map={} |
| | | for name, value in globals().items(): |
| | | if (isinstance(value, (type, types.ClassType)) and |
| | | issubclass(value, HTTPException) |
| | | and not name.startswith('_')): |
| | | code = getattr(value, 'code', None) |
| | | if code: |
| | | status_map[code] = value |
| | | del name, value |
| | | |
| | | |
| | | |
| | |
| | | |
| | | IWSGIApplicationCreatedEvent = IApplicationCreated # b /c |
| | | |
| | | class IResponse(Interface): # not an API |
| | | class IResponse(Interface): |
| | | status = Attribute('WSGI status code of response') |
| | | headerlist = Attribute('List of response headers') |
| | | app_iter = Attribute('Iterable representing the response body') |
| | | |
| | | def __call__(environ, start_response): |
| | | """ WSGI call interface, should call the start_response callback |
| | | and should return an iterable """ |
| | | |
| | | class IException(Interface): # not an API |
| | | """ An interface representing a generic exception """ |
| | |
| | | to apply the registered view for all exception types raised by |
| | | :app:`Pyramid` internally (any exception that inherits from |
| | | :class:`pyramid.response.Response`, including |
| | | :class:`pyramid.response.HTTPNotFound` and |
| | | :class:`pyramid.response.HTTPForbidden`).""" |
| | | :class:`pyramid.httpexceptions.HTTPNotFound` and |
| | | :class:`pyramid.httpexceptions.HTTPForbidden`).""" |
| | | |
| | | class IBeforeRender(Interface): |
| | | """ |
| | |
| | | |
| | | class IView(Interface): |
| | | def __call__(context, request): |
| | | """ Must return an object that implements IResponse. May |
| | | optionally raise ``pyramid.response.HTTPForbidden`` if an |
| | | authorization failure is detected during view execution or |
| | | ``pyramid.response.HTTPNotFound`` if the not found page is |
| | | meant to be returned.""" |
| | | """ Must return an object that implements IResponse. """ |
| | | |
| | | class ISecuredView(IView): |
| | | """ *Internal only* interface. Not an API. """ |
| | |
| | | import types |
| | | from string import Template |
| | | |
| | | from webob import Response as _Response |
| | | from webob import html_escape as _html_escape |
| | | from zope.interface import implements |
| | | from zope.configuration.exceptions import ConfigurationError as ZCE |
| | | from pyramid.interfaces import IResponse |
| | | |
| | | from pyramid.interfaces import IExceptionResponse |
| | | |
| | | class Response(_Response, Exception): |
| | | implements(IExceptionResponse) |
| | | class Response(_Response): |
| | | implements(IResponse) |
| | | |
| | | def _no_escape(value): |
| | | if value is None: |
| | | return '' |
| | | if not isinstance(value, basestring): |
| | | if hasattr(value, '__unicode__'): |
| | | value = unicode(value) |
| | | else: |
| | | value = str(value) |
| | | return value |
| | | |
| | | class HTTPException(Exception): # bw compat |
| | | pass |
| | | |
| | | class WSGIHTTPException(Response, HTTPException): |
| | | implements(IExceptionResponse) |
| | | |
| | | ## You should set in subclasses: |
| | | # code = 200 |
| | | # title = 'OK' |
| | | # explanation = 'why this happens' |
| | | # body_template_obj = Template('response template') |
| | | |
| | | # differences from webob.exc.WSGIHTTPException: |
| | | # - not a WSGI application (just a response) |
| | | # |
| | | # as a result: |
| | | # |
| | | # - bases plaintext vs. html result on self.content_type rather than |
| | | # on request accept header |
| | | # |
| | | # - doesn't add request.environ keys to template substitutions unless |
| | | # 'request' is passed as a constructor keyword argument. |
| | | # |
| | | # - doesn't use "strip_tags" (${br} placeholder for <br/>, no other html |
| | | # in default body template) |
| | | # |
| | | # - sets a default app_iter if no body, app_iter, or unicode_body is |
| | | # passed using a template (ala the replaced version's "generate_response") |
| | | # |
| | | # - explicitly sets self.message = detail to prevent whining by Python |
| | | # 2.6.5+ access of Exception.message |
| | | # |
| | | # - its base class of HTTPException is no longer a Python 2.4 compatibility |
| | | # shim; it's purely a base class that inherits from Exception. This |
| | | # implies that this class' ``exception`` property always returns |
| | | # ``self`` (only for bw compat at this point). |
| | | code = None |
| | | title = None |
| | | explanation = '' |
| | | body_template_obj = Template('''\ |
| | | ${explanation}${br}${br} |
| | | ${detail} |
| | | ${html_comment} |
| | | ''') |
| | | |
| | | plain_template_obj = Template('''\ |
| | | ${status} |
| | | |
| | | ${body}''') |
| | | |
| | | html_template_obj = Template('''\ |
| | | <html> |
| | | <head> |
| | | <title>${status}</title> |
| | | </head> |
| | | <body> |
| | | <h1>${status}</h1> |
| | | ${body} |
| | | </body> |
| | | </html>''') |
| | | |
| | | ## Set this to True for responses that should have no request body |
| | | empty_body = False |
| | | |
| | | def __init__(self, detail=None, headers=None, comment=None, |
| | | body_template=None, **kw): |
| | | status = '%s %s' % (self.code, self.title) |
| | | Response.__init__(self, status=status, **kw) |
| | | Exception.__init__(self, detail) |
| | | self.detail = self.message = detail |
| | | if headers: |
| | | self.headers.extend(headers) |
| | | self.comment = comment |
| | | if body_template is not None: |
| | | self.body_template = body_template |
| | | self.body_template_obj = Template(body_template) |
| | | |
| | | if self.empty_body: |
| | | del self.content_type |
| | | del self.content_length |
| | | elif not ('unicode_body' in kw or 'body' in kw or 'app_iter' in kw): |
| | | self.app_iter = self._default_app_iter() |
| | | |
| | | def __str__(self): |
| | | return self.detail or self.explanation |
| | | |
| | | def _default_app_iter(self): |
| | | # This is a generator which defers the creation of the response page |
| | | # body; we use a generator because we want to ensure that if |
| | | # attributes of this response are changed after it is constructed, we |
| | | # use the changed values rather than the values at time of construction |
| | | # (e.g. self.content_type or self.charset). |
| | | html_comment = '' |
| | | comment = self.comment or '' |
| | | content_type = self.content_type or '' |
| | | if 'html' in content_type: |
| | | escape = _html_escape |
| | | page_template = self.html_template_obj |
| | | br = '<br/>' |
| | | if comment: |
| | | html_comment = '<!-- %s -->' % escape(comment) |
| | | else: |
| | | escape = _no_escape |
| | | page_template = self.plain_template_obj |
| | | br = '\n' |
| | | if comment: |
| | | html_comment = escape(comment) |
| | | args = { |
| | | 'br':br, |
| | | 'explanation': escape(self.explanation), |
| | | 'detail': escape(self.detail or ''), |
| | | 'comment': escape(comment), |
| | | 'html_comment':html_comment, |
| | | } |
| | | body_tmpl = self.body_template_obj |
| | | if WSGIHTTPException.body_template_obj is not body_tmpl: |
| | | # Custom template; add headers to args |
| | | environ = self.environ |
| | | if environ is not None: |
| | | for k, v in environ.items(): |
| | | args[k] = escape(v) |
| | | for k, v in self.headers.items(): |
| | | args[k.lower()] = escape(v) |
| | | body = body_tmpl.substitute(args) |
| | | page = page_template.substitute(status=self.status, body=body) |
| | | if isinstance(page, unicode): |
| | | page = page.encode(self.charset) |
| | | yield page |
| | | raise StopIteration |
| | | |
| | | @property |
| | | def exception(self): |
| | | # bw compat only |
| | | return self |
| | | wsgi_response = exception # bw compat only |
| | | |
| | | class HTTPError(WSGIHTTPException): |
| | | """ |
| | | base class for status codes in the 400's and 500's |
| | | |
| | | This is an exception which indicates that an error has occurred, |
| | | and that any work in progress should not be committed. These are |
| | | typically results in the 400's and 500's. |
| | | """ |
| | | |
| | | class HTTPRedirection(WSGIHTTPException): |
| | | """ |
| | | base class for 300's status code (redirections) |
| | | |
| | | This is an abstract base class for 3xx redirection. It indicates |
| | | that further action needs to be taken by the user agent in order |
| | | to fulfill the request. It does not necessarly signal an error |
| | | condition. |
| | | """ |
| | | |
| | | class HTTPOk(WSGIHTTPException): |
| | | """ |
| | | Base class for the 200's status code (successful responses) |
| | | |
| | | code: 200, title: OK |
| | | """ |
| | | code = 200 |
| | | title = 'OK' |
| | | |
| | | ############################################################ |
| | | ## 2xx success |
| | | ############################################################ |
| | | |
| | | class HTTPCreated(HTTPOk): |
| | | """ |
| | | subclass of :class:`~HTTPOk` |
| | | |
| | | This indicates that request has been fulfilled and resulted in a new |
| | | resource being created. |
| | | |
| | | code: 201, title: Created |
| | | """ |
| | | code = 201 |
| | | title = 'Created' |
| | | |
| | | class HTTPAccepted(HTTPOk): |
| | | """ |
| | | subclass of :class:`~HTTPOk` |
| | | |
| | | This indicates that the request has been accepted for processing, but the |
| | | processing has not been completed. |
| | | |
| | | code: 202, title: Accepted |
| | | """ |
| | | code = 202 |
| | | title = 'Accepted' |
| | | explanation = 'The request is accepted for processing.' |
| | | |
| | | class HTTPNonAuthoritativeInformation(HTTPOk): |
| | | """ |
| | | subclass of :class:`~HTTPOk` |
| | | |
| | | This indicates that the returned metainformation in the entity-header is |
| | | not the definitive set as available from the origin server, but is |
| | | gathered from a local or a third-party copy. |
| | | |
| | | code: 203, title: Non-Authoritative Information |
| | | """ |
| | | code = 203 |
| | | title = 'Non-Authoritative Information' |
| | | |
| | | class HTTPNoContent(HTTPOk): |
| | | """ |
| | | subclass of :class:`~HTTPOk` |
| | | |
| | | This indicates that the server has fulfilled the request but does |
| | | not need to return an entity-body, and might want to return updated |
| | | metainformation. |
| | | |
| | | code: 204, title: No Content |
| | | """ |
| | | code = 204 |
| | | title = 'No Content' |
| | | empty_body = True |
| | | |
| | | class HTTPResetContent(HTTPOk): |
| | | """ |
| | | subclass of :class:`~HTTPOk` |
| | | |
| | | This indicates that the the server has fulfilled the request and |
| | | the user agent SHOULD reset the document view which caused the |
| | | request to be sent. |
| | | |
| | | code: 205, title: Reset Content |
| | | """ |
| | | code = 205 |
| | | title = 'Reset Content' |
| | | empty_body = True |
| | | |
| | | class HTTPPartialContent(HTTPOk): |
| | | """ |
| | | subclass of :class:`~HTTPOk` |
| | | |
| | | This indicates that the server has fulfilled the partial GET |
| | | request for the resource. |
| | | |
| | | code: 206, title: Partial Content |
| | | """ |
| | | code = 206 |
| | | title = 'Partial Content' |
| | | |
| | | ## FIXME: add 207 Multi-Status (but it's complicated) |
| | | |
| | | ############################################################ |
| | | ## 3xx redirection |
| | | ############################################################ |
| | | |
| | | class _HTTPMove(HTTPRedirection): |
| | | """ |
| | | redirections which require a Location field |
| | | |
| | | Since a 'Location' header is a required attribute of 301, 302, 303, |
| | | 305 and 307 (but not 304), this base class provides the mechanics to |
| | | make this easy. |
| | | |
| | | You must provide a ``location`` keyword argument. |
| | | """ |
| | | # differences from webob.exc._HTTPMove: |
| | | # |
| | | # - not a wsgi app |
| | | # |
| | | # - ${location} isn't wrapped in an <a> tag in body |
| | | # |
| | | # - location keyword arg defaults to '' |
| | | # |
| | | # - ``add_slash`` argument is no longer accepted: code that passes |
| | | # add_slash argument to the constructor will receive an exception. |
| | | explanation = 'The resource has been moved to' |
| | | body_template_obj = Template('''\ |
| | | ${explanation} ${location}; |
| | | you should be redirected automatically. |
| | | ${detail} |
| | | ${html_comment}''') |
| | | |
| | | def __init__(self, detail=None, headers=None, comment=None, |
| | | body_template=None, location='', **kw): |
| | | super(_HTTPMove, self).__init__( |
| | | detail=detail, headers=headers, comment=comment, |
| | | body_template=body_template, location=location, **kw) |
| | | |
| | | class HTTPMultipleChoices(_HTTPMove): |
| | | """ |
| | | subclass of :class:`~_HTTPMove` |
| | | |
| | | This indicates that the requested resource corresponds to any one |
| | | of a set of representations, each with its own specific location, |
| | | and agent-driven negotiation information is being provided so that |
| | | the user can select a preferred representation and redirect its |
| | | request to that location. |
| | | |
| | | code: 300, title: Multiple Choices |
| | | """ |
| | | code = 300 |
| | | title = 'Multiple Choices' |
| | | |
| | | class HTTPMovedPermanently(_HTTPMove): |
| | | """ |
| | | subclass of :class:`~_HTTPMove` |
| | | |
| | | This indicates that the requested resource has been assigned a new |
| | | permanent URI and any future references to this resource SHOULD use |
| | | one of the returned URIs. |
| | | |
| | | code: 301, title: Moved Permanently |
| | | """ |
| | | code = 301 |
| | | title = 'Moved Permanently' |
| | | |
| | | class HTTPFound(_HTTPMove): |
| | | """ |
| | | subclass of :class:`~_HTTPMove` |
| | | |
| | | This indicates that the requested resource resides temporarily under |
| | | a different URI. |
| | | |
| | | code: 302, title: Found |
| | | """ |
| | | code = 302 |
| | | title = 'Found' |
| | | explanation = 'The resource was found at' |
| | | |
| | | # This one is safe after a POST (the redirected location will be |
| | | # retrieved with GET): |
| | | class HTTPSeeOther(_HTTPMove): |
| | | """ |
| | | subclass of :class:`~_HTTPMove` |
| | | |
| | | This indicates that the response to the request can be found under |
| | | a different URI and SHOULD be retrieved using a GET method on that |
| | | resource. |
| | | |
| | | code: 303, title: See Other |
| | | """ |
| | | code = 303 |
| | | title = 'See Other' |
| | | |
| | | class HTTPNotModified(HTTPRedirection): |
| | | """ |
| | | subclass of :class:`~HTTPRedirection` |
| | | |
| | | This indicates that if the client has performed a conditional GET |
| | | request and access is allowed, but the document has not been |
| | | modified, the server SHOULD respond with this status code. |
| | | |
| | | code: 304, title: Not Modified |
| | | """ |
| | | # FIXME: this should include a date or etag header |
| | | code = 304 |
| | | title = 'Not Modified' |
| | | empty_body = True |
| | | |
| | | class HTTPUseProxy(_HTTPMove): |
| | | """ |
| | | subclass of :class:`~_HTTPMove` |
| | | |
| | | This indicates that the requested resource MUST be accessed through |
| | | the proxy given by the Location field. |
| | | |
| | | code: 305, title: Use Proxy |
| | | """ |
| | | # Not a move, but looks a little like one |
| | | code = 305 |
| | | title = 'Use Proxy' |
| | | explanation = ( |
| | | 'The resource must be accessed through a proxy located at') |
| | | |
| | | class HTTPTemporaryRedirect(_HTTPMove): |
| | | """ |
| | | subclass of :class:`~_HTTPMove` |
| | | |
| | | This indicates that the requested resource resides temporarily |
| | | under a different URI. |
| | | |
| | | code: 307, title: Temporary Redirect |
| | | """ |
| | | code = 307 |
| | | title = 'Temporary Redirect' |
| | | |
| | | ############################################################ |
| | | ## 4xx client error |
| | | ############################################################ |
| | | |
| | | class HTTPClientError(HTTPError): |
| | | """ |
| | | base class for the 400's, where the client is in error |
| | | |
| | | This is an error condition in which the client is presumed to be |
| | | in-error. This is an expected problem, and thus is not considered |
| | | a bug. A server-side traceback is not warranted. Unless specialized, |
| | | this is a '400 Bad Request' |
| | | """ |
| | | code = 400 |
| | | title = 'Bad Request' |
| | | explanation = ('The server could not comply with the request since ' |
| | | 'it is either malformed or otherwise incorrect.') |
| | | |
| | | class HTTPBadRequest(HTTPClientError): |
| | | pass |
| | | |
| | | class HTTPUnauthorized(HTTPClientError): |
| | | """ |
| | | subclass of :class:`~HTTPClientError` |
| | | |
| | | This indicates that the request requires user authentication. |
| | | |
| | | code: 401, title: Unauthorized |
| | | """ |
| | | code = 401 |
| | | title = 'Unauthorized' |
| | | explanation = ( |
| | | 'This server could not verify that you are authorized to ' |
| | | 'access the document you requested. Either you supplied the ' |
| | | 'wrong credentials (e.g., bad password), or your browser ' |
| | | 'does not understand how to supply the credentials required.') |
| | | |
| | | class HTTPPaymentRequired(HTTPClientError): |
| | | """ |
| | | subclass of :class:`~HTTPClientError` |
| | | |
| | | code: 402, title: Payment Required |
| | | """ |
| | | code = 402 |
| | | title = 'Payment Required' |
| | | explanation = ('Access was denied for financial reasons.') |
| | | |
| | | class HTTPForbidden(HTTPClientError): |
| | | """ |
| | | subclass of :class:`~HTTPClientError` |
| | | |
| | | This indicates that the server understood the request, but is |
| | | refusing to fulfill it. |
| | | |
| | | code: 403, title: Forbidden |
| | | |
| | | Raise this exception within :term:`view` code to immediately return the |
| | | :term:`forbidden view` to the invoking user. Usually this is a basic |
| | | ``403`` page, but the forbidden view can be customized as necessary. See |
| | | :ref:`changing_the_forbidden_view`. A ``Forbidden`` exception will be |
| | | the ``context`` of a :term:`Forbidden View`. |
| | | |
| | | This exception's constructor treats two arguments specially. The first |
| | | argument, ``detail``, should be a string. The value of this string will |
| | | be used as the ``message`` attribute of the exception object. The second |
| | | special keyword argument, ``result`` is usually an instance of |
| | | :class:`pyramid.security.Denied` or :class:`pyramid.security.ACLDenied` |
| | | each of which indicates a reason for the forbidden error. However, |
| | | ``result`` is also permitted to be just a plain boolean ``False`` object |
| | | or ``None``. The ``result`` value will be used as the ``result`` |
| | | attribute of the exception object. It defaults to ``None``. |
| | | |
| | | The :term:`Forbidden View` can use the attributes of a Forbidden |
| | | exception as necessary to provide extended information in an error |
| | | report shown to a user. |
| | | """ |
| | | # differences from webob.exc.HTTPForbidden: |
| | | # |
| | | # - accepts a ``result`` keyword argument |
| | | # |
| | | # - overrides constructor to set ``self.result`` |
| | | # |
| | | # differences from older ``pyramid.exceptions.Forbidden``: |
| | | # |
| | | # - ``result`` must be passed as a keyword argument. |
| | | # |
| | | code = 403 |
| | | title = 'Forbidden' |
| | | explanation = ('Access was denied to this resource.') |
| | | def __init__(self, detail=None, headers=None, comment=None, |
| | | body_template=None, result=None, **kw): |
| | | HTTPClientError.__init__(self, detail=detail, headers=headers, |
| | | comment=comment, body_template=body_template, |
| | | **kw) |
| | | self.result = result |
| | | |
| | | class HTTPNotFound(HTTPClientError): |
| | | """ |
| | | subclass of :class:`~HTTPClientError` |
| | | |
| | | This indicates that the server did not find anything matching the |
| | | Request-URI. |
| | | |
| | | code: 404, title: Not Found |
| | | |
| | | Raise this exception within :term:`view` code to immediately |
| | | return the :term:`Not Found view` to the invoking user. Usually |
| | | this is a basic ``404`` page, but the Not Found view can be |
| | | customized as necessary. See :ref:`changing_the_notfound_view`. |
| | | |
| | | This exception's constructor accepts a ``detail`` argument |
| | | (the first argument), which should be a string. The value of this |
| | | string will be available as the ``message`` attribute of this exception, |
| | | for availability to the :term:`Not Found View`. |
| | | """ |
| | | code = 404 |
| | | title = 'Not Found' |
| | | explanation = ('The resource could not be found.') |
| | | |
| | | class HTTPMethodNotAllowed(HTTPClientError): |
| | | """ |
| | | subclass of :class:`~HTTPClientError` |
| | | |
| | | This indicates that the method specified in the Request-Line is |
| | | not allowed for the resource identified by the Request-URI. |
| | | |
| | | code: 405, title: Method Not Allowed |
| | | """ |
| | | # differences from webob.exc.HTTPMethodNotAllowed: |
| | | # |
| | | # - body_template_obj not overridden (it tried to use request environ's |
| | | # REQUEST_METHOD) |
| | | code = 405 |
| | | title = 'Method Not Allowed' |
| | | |
| | | class HTTPNotAcceptable(HTTPClientError): |
| | | """ |
| | | subclass of :class:`~HTTPClientError` |
| | | |
| | | This indicates the resource identified by the request is only |
| | | capable of generating response entities which have content |
| | | characteristics not acceptable according to the accept headers |
| | | sent in the request. |
| | | |
| | | code: 406, title: Not Acceptable |
| | | """ |
| | | # differences from webob.exc.HTTPNotAcceptable: |
| | | # |
| | | # - body_template_obj not overridden (it tried to use request environ's |
| | | # HTTP_ACCEPT) |
| | | code = 406 |
| | | title = 'Not Acceptable' |
| | | |
| | | class HTTPProxyAuthenticationRequired(HTTPClientError): |
| | | """ |
| | | subclass of :class:`~HTTPClientError` |
| | | |
| | | This is similar to 401, but indicates that the client must first |
| | | authenticate itself with the proxy. |
| | | |
| | | code: 407, title: Proxy Authentication Required |
| | | """ |
| | | code = 407 |
| | | title = 'Proxy Authentication Required' |
| | | explanation = ('Authentication with a local proxy is needed.') |
| | | |
| | | class HTTPRequestTimeout(HTTPClientError): |
| | | """ |
| | | subclass of :class:`~HTTPClientError` |
| | | |
| | | This indicates that the client did not produce a request within |
| | | the time that the server was prepared to wait. |
| | | |
| | | code: 408, title: Request Timeout |
| | | """ |
| | | code = 408 |
| | | title = 'Request Timeout' |
| | | explanation = ('The server has waited too long for the request to ' |
| | | 'be sent by the client.') |
| | | |
| | | class HTTPConflict(HTTPClientError): |
| | | """ |
| | | subclass of :class:`~HTTPClientError` |
| | | |
| | | This indicates that the request could not be completed due to a |
| | | conflict with the current state of the resource. |
| | | |
| | | code: 409, title: Conflict |
| | | """ |
| | | code = 409 |
| | | title = 'Conflict' |
| | | explanation = ('There was a conflict when trying to complete ' |
| | | 'your request.') |
| | | |
| | | class HTTPGone(HTTPClientError): |
| | | """ |
| | | subclass of :class:`~HTTPClientError` |
| | | |
| | | This indicates that the requested resource is no longer available |
| | | at the server and no forwarding address is known. |
| | | |
| | | code: 410, title: Gone |
| | | """ |
| | | code = 410 |
| | | title = 'Gone' |
| | | explanation = ('This resource is no longer available. No forwarding ' |
| | | 'address is given.') |
| | | |
| | | class HTTPLengthRequired(HTTPClientError): |
| | | """ |
| | | subclass of :class:`~HTTPClientError` |
| | | |
| | | This indicates that the the server refuses to accept the request |
| | | without a defined Content-Length. |
| | | |
| | | code: 411, title: Length Required |
| | | """ |
| | | code = 411 |
| | | title = 'Length Required' |
| | | explanation = ('Content-Length header required.') |
| | | |
| | | class HTTPPreconditionFailed(HTTPClientError): |
| | | """ |
| | | subclass of :class:`~HTTPClientError` |
| | | |
| | | This indicates that the precondition given in one or more of the |
| | | request-header fields evaluated to false when it was tested on the |
| | | server. |
| | | |
| | | code: 412, title: Precondition Failed |
| | | """ |
| | | code = 412 |
| | | title = 'Precondition Failed' |
| | | explanation = ('Request precondition failed.') |
| | | |
| | | class HTTPRequestEntityTooLarge(HTTPClientError): |
| | | """ |
| | | subclass of :class:`~HTTPClientError` |
| | | |
| | | This indicates that the server is refusing to process a request |
| | | because the request entity is larger than the server is willing or |
| | | able to process. |
| | | |
| | | code: 413, title: Request Entity Too Large |
| | | """ |
| | | code = 413 |
| | | title = 'Request Entity Too Large' |
| | | explanation = ('The body of your request was too large for this server.') |
| | | |
| | | class HTTPRequestURITooLong(HTTPClientError): |
| | | """ |
| | | subclass of :class:`~HTTPClientError` |
| | | |
| | | This indicates that the server is refusing to service the request |
| | | because the Request-URI is longer than the server is willing to |
| | | interpret. |
| | | |
| | | code: 414, title: Request-URI Too Long |
| | | """ |
| | | code = 414 |
| | | title = 'Request-URI Too Long' |
| | | explanation = ('The request URI was too long for this server.') |
| | | |
| | | class HTTPUnsupportedMediaType(HTTPClientError): |
| | | """ |
| | | subclass of :class:`~HTTPClientError` |
| | | |
| | | This indicates that the server is refusing to service the request |
| | | because the entity of the request is in a format not supported by |
| | | the requested resource for the requested method. |
| | | |
| | | code: 415, title: Unsupported Media Type |
| | | """ |
| | | # differences from webob.exc.HTTPUnsupportedMediaType: |
| | | # |
| | | # - body_template_obj not overridden (it tried to use request environ's |
| | | # CONTENT_TYPE) |
| | | code = 415 |
| | | title = 'Unsupported Media Type' |
| | | |
| | | class HTTPRequestRangeNotSatisfiable(HTTPClientError): |
| | | """ |
| | | subclass of :class:`~HTTPClientError` |
| | | |
| | | The server SHOULD return a response with this status code if a |
| | | request included a Range request-header field, and none of the |
| | | range-specifier values in this field overlap the current extent |
| | | of the selected resource, and the request did not include an |
| | | If-Range request-header field. |
| | | |
| | | code: 416, title: Request Range Not Satisfiable |
| | | """ |
| | | code = 416 |
| | | title = 'Request Range Not Satisfiable' |
| | | explanation = ('The Range requested is not available.') |
| | | |
| | | class HTTPExpectationFailed(HTTPClientError): |
| | | """ |
| | | subclass of :class:`~HTTPClientError` |
| | | |
| | | This indidcates that the expectation given in an Expect |
| | | request-header field could not be met by this server. |
| | | |
| | | code: 417, title: Expectation Failed |
| | | """ |
| | | code = 417 |
| | | title = 'Expectation Failed' |
| | | explanation = ('Expectation failed.') |
| | | |
| | | class HTTPUnprocessableEntity(HTTPClientError): |
| | | """ |
| | | subclass of :class:`~HTTPClientError` |
| | | |
| | | This indicates that the server is unable to process the contained |
| | | instructions. Only for WebDAV. |
| | | |
| | | code: 422, title: Unprocessable Entity |
| | | """ |
| | | ## Note: from WebDAV |
| | | code = 422 |
| | | title = 'Unprocessable Entity' |
| | | explanation = 'Unable to process the contained instructions' |
| | | |
| | | class HTTPLocked(HTTPClientError): |
| | | """ |
| | | subclass of :class:`~HTTPClientError` |
| | | |
| | | This indicates that the resource is locked. Only for WebDAV |
| | | |
| | | code: 423, title: Locked |
| | | """ |
| | | ## Note: from WebDAV |
| | | code = 423 |
| | | title = 'Locked' |
| | | explanation = ('The resource is locked') |
| | | |
| | | class HTTPFailedDependency(HTTPClientError): |
| | | """ |
| | | subclass of :class:`~HTTPClientError` |
| | | |
| | | This indicates that the method could not be performed because the |
| | | requested action depended on another action and that action failed. |
| | | Only for WebDAV. |
| | | |
| | | code: 424, title: Failed Dependency |
| | | """ |
| | | ## Note: from WebDAV |
| | | code = 424 |
| | | title = 'Failed Dependency' |
| | | explanation = ( |
| | | 'The method could not be performed because the requested ' |
| | | 'action dependended on another action and that action failed') |
| | | |
| | | ############################################################ |
| | | ## 5xx Server Error |
| | | ############################################################ |
| | | # Response status codes beginning with the digit "5" indicate cases in |
| | | # which the server is aware that it has erred or is incapable of |
| | | # performing the request. Except when responding to a HEAD request, the |
| | | # server SHOULD include an entity containing an explanation of the error |
| | | # situation, and whether it is a temporary or permanent condition. User |
| | | # agents SHOULD display any included entity to the user. These response |
| | | # codes are applicable to any request method. |
| | | |
| | | class HTTPServerError(HTTPError): |
| | | """ |
| | | base class for the 500's, where the server is in-error |
| | | |
| | | This is an error condition in which the server is presumed to be |
| | | in-error. This is usually unexpected, and thus requires a traceback; |
| | | ideally, opening a support ticket for the customer. Unless specialized, |
| | | this is a '500 Internal Server Error' |
| | | """ |
| | | code = 500 |
| | | title = 'Internal Server Error' |
| | | explanation = ( |
| | | 'The server has either erred or is incapable of performing ' |
| | | 'the requested operation.') |
| | | |
| | | class HTTPInternalServerError(HTTPServerError): |
| | | pass |
| | | |
| | | class HTTPNotImplemented(HTTPServerError): |
| | | """ |
| | | subclass of :class:`~HTTPServerError` |
| | | |
| | | This indicates that the server does not support the functionality |
| | | required to fulfill the request. |
| | | |
| | | code: 501, title: Not Implemented |
| | | """ |
| | | # differences from webob.exc.HTTPNotAcceptable: |
| | | # |
| | | # - body_template_obj not overridden (it tried to use request environ's |
| | | # REQUEST_METHOD) |
| | | code = 501 |
| | | title = 'Not Implemented' |
| | | |
| | | class HTTPBadGateway(HTTPServerError): |
| | | """ |
| | | subclass of :class:`~HTTPServerError` |
| | | |
| | | This indicates that the server, while acting as a gateway or proxy, |
| | | received an invalid response from the upstream server it accessed |
| | | in attempting to fulfill the request. |
| | | |
| | | code: 502, title: Bad Gateway |
| | | """ |
| | | code = 502 |
| | | title = 'Bad Gateway' |
| | | explanation = ('Bad gateway.') |
| | | |
| | | class HTTPServiceUnavailable(HTTPServerError): |
| | | """ |
| | | subclass of :class:`~HTTPServerError` |
| | | |
| | | This indicates that the server is currently unable to handle the |
| | | request due to a temporary overloading or maintenance of the server. |
| | | |
| | | code: 503, title: Service Unavailable |
| | | """ |
| | | code = 503 |
| | | title = 'Service Unavailable' |
| | | explanation = ('The server is currently unavailable. ' |
| | | 'Please try again at a later time.') |
| | | |
| | | class HTTPGatewayTimeout(HTTPServerError): |
| | | """ |
| | | subclass of :class:`~HTTPServerError` |
| | | |
| | | This indicates that the server, while acting as a gateway or proxy, |
| | | did not receive a timely response from the upstream server specified |
| | | by the URI (e.g. HTTP, FTP, LDAP) or some other auxiliary server |
| | | (e.g. DNS) it needed to access in attempting to complete the request. |
| | | |
| | | code: 504, title: Gateway Timeout |
| | | """ |
| | | code = 504 |
| | | title = 'Gateway Timeout' |
| | | explanation = ('The gateway has timed out.') |
| | | |
| | | class HTTPVersionNotSupported(HTTPServerError): |
| | | """ |
| | | subclass of :class:`~HTTPServerError` |
| | | |
| | | This indicates that the server does not support, or refuses to |
| | | support, the HTTP protocol version that was used in the request |
| | | message. |
| | | |
| | | code: 505, title: HTTP Version Not Supported |
| | | """ |
| | | code = 505 |
| | | title = 'HTTP Version Not Supported' |
| | | explanation = ('The HTTP version is not supported.') |
| | | |
| | | class HTTPInsufficientStorage(HTTPServerError): |
| | | """ |
| | | subclass of :class:`~HTTPServerError` |
| | | |
| | | This indicates that the server does not have enough space to save |
| | | the resource. |
| | | |
| | | code: 507, title: Insufficient Storage |
| | | """ |
| | | code = 507 |
| | | title = 'Insufficient Storage' |
| | | explanation = ('There was not enough space to save the resource') |
| | | |
| | | NotFound = HTTPNotFound # bw compat |
| | | Forbidden = HTTPForbidden # bw compat |
| | | |
| | | class PredicateMismatch(NotFound): |
| | | """ |
| | | Internal exception (not an API) raised by multiviews when no |
| | | view matches. This exception subclasses the ``NotFound`` |
| | | exception only one reason: if it reaches the main exception |
| | | handler, it should be treated like a ``NotFound`` by any exception |
| | | view registrations. |
| | | """ |
| | | |
| | | class URLDecodeError(UnicodeDecodeError): |
| | | """ |
| | | This exception is raised when :app:`Pyramid` cannot |
| | | successfully decode a URL or a URL path segment. This exception |
| | | it behaves just like the Python builtin |
| | | :exc:`UnicodeDecodeError`. It is a subclass of the builtin |
| | | :exc:`UnicodeDecodeError` exception only for identity purposes, |
| | | mostly so an exception view can be registered when a URL cannot be |
| | | decoded. |
| | | """ |
| | | |
| | | class ConfigurationError(ZCE): |
| | | """ Raised when inappropriate input values are supplied to an API |
| | | method of a :term:`Configurator`""" |
| | | |
| | | |
| | | def abort(status_code, **kw): |
| | | """Aborts the request immediately by raising an HTTP exception based on a |
| | | status code. Example:: |
| | | |
| | | abort(404) # raises an HTTPNotFound exception. |
| | | |
| | | The values passed as ``kw`` are provided to the exception's constructor. |
| | | """ |
| | | exc = status_map[status_code](**kw) |
| | | raise exc |
| | | |
| | | |
| | | def redirect(url, code=302, **kw): |
| | | """Raises an :class:`~HTTPFound` (302) redirect exception to the |
| | | URL specified by ``url``. |
| | | |
| | | Optionally, a code variable may be passed with the status code of |
| | | the redirect, ie:: |
| | | |
| | | redirect(route_url('foo', request), code=303) |
| | | |
| | | The values passed as ``kw`` are provided to the exception constructor. |
| | | |
| | | """ |
| | | exc = status_map[code] |
| | | raise exc(location=url, **kw) |
| | | |
| | | def default_exceptionresponse_view(context, request): |
| | | if not isinstance(context, Exception): |
| | | # backwards compat for an exception response view registered via |
| | | # config.set_notfound_view or config.set_forbidden_view |
| | | # instead of as a proper exception view |
| | | context = request.exception or context |
| | | return context |
| | | |
| | | status_map={} |
| | | for name, value in globals().items(): |
| | | if (isinstance(value, (type, types.ClassType)) and |
| | | issubclass(value, HTTPException) |
| | | and not name.startswith('_')): |
| | | code = getattr(value, 'code', None) |
| | | if code: |
| | | status_map[code] = value |
| | | del name, value |
| | | |
| | |
| | | import warnings |
| | | |
| | | from zope.interface import implements |
| | | from zope.interface import providedBy |
| | | |
| | |
| | | from pyramid.events import ContextFound |
| | | from pyramid.events import NewRequest |
| | | from pyramid.events import NewResponse |
| | | from pyramid.response import HTTPNotFound |
| | | from pyramid.httpexceptions import HTTPNotFound |
| | | from pyramid.request import Request |
| | | from pyramid.threadlocal import manager |
| | | from pyramid.traversal import DefaultRootFactory |
| | |
| | | |
| | | def default_responder(response): |
| | | def inner(request, start_response): |
| | | # __call__ is default 1.1 response API |
| | | call = getattr(response, '__call__', None) |
| | | if call is not None: |
| | | return call(request.environ, start_response) |
| | | # start 1.0 bw compat (use headerlist, app_iter, status) |
| | | try: |
| | | headers = response.headerlist |
| | | app_iter = response.app_iter |
| | |
| | | 'Non-response object returned from view ' |
| | | '(and no renderer): %r' % (response)) |
| | | start_response(status, headers) |
| | | warnings.warn( |
| | | 'As of Pyramid 1.1, an object used as a response object is ' |
| | | 'required to have a "__call__" method if an IResponder adapter is ' |
| | | 'not registered for its type. See "Deprecations" in "What\'s New ' |
| | | 'in Pyramid 1.1" within the general Pyramid documentation for ' |
| | | 'further details.', |
| | | DeprecationWarning, |
| | | 3) |
| | | return app_iter |
| | | return inner |
| | | |
| | |
| | | |
| | | from pyramid.config import Configurator |
| | | from pyramid.decorator import reify |
| | | from pyramid.response import HTTPForbidden |
| | | from pyramid.httpexceptions import HTTPForbidden |
| | | from pyramid.response import Response |
| | | from pyramid.registry import Registry |
| | | from pyramid.security import Authenticated |
| | |
| | | from zope.interface import Interface |
| | | from webob import Response |
| | | from pyramid.response import HTTPForbidden |
| | | from pyramid.httpexceptions import HTTPForbidden |
| | | |
| | | def fixture_view(context, request): |
| | | """ """ |
| | |
| | | from webob import Response |
| | | from pyramid.response import HTTPForbidden |
| | | from pyramid.httpexceptions import HTTPForbidden |
| | | |
| | | def x_view(request): # pragma: no cover |
| | | return Response('this is private!') |
| | |
| | | return iface |
| | | |
| | | def _assertNotFound(self, wrapper, *arg): |
| | | from pyramid.response import HTTPNotFound |
| | | from pyramid.httpexceptions import HTTPNotFound |
| | | self.assertRaises(HTTPNotFound, wrapper, *arg) |
| | | |
| | | def _registerEventListener(self, config, event_iface=None): |
| | |
| | | |
| | | def test_ctor_httpexception_view_default(self): |
| | | from pyramid.interfaces import IExceptionResponse |
| | | from pyramid.response import default_exceptionresponse_view |
| | | from pyramid.httpexceptions import default_exceptionresponse_view |
| | | from pyramid.interfaces import IRequest |
| | | config = self._makeOne() |
| | | view = self._getViewCallable(config, |
| | |
| | | def test_setup_registry_explicit_notfound_trumps_iexceptionresponse(self): |
| | | from zope.interface import implementedBy |
| | | from pyramid.interfaces import IRequest |
| | | from pyramid.response import HTTPNotFound |
| | | from pyramid.httpexceptions import HTTPNotFound |
| | | from pyramid.registry import Registry |
| | | reg = Registry() |
| | | config = self._makeOne(reg, autocommit=True) |
| | |
| | | self._assertNotFound(wrapper, None, request) |
| | | |
| | | def test_add_view_with_header_val_missing(self): |
| | | from pyramid.response import HTTPNotFound |
| | | from pyramid.httpexceptions import HTTPNotFound |
| | | view = lambda *arg: 'OK' |
| | | config = self._makeOne(autocommit=True) |
| | | config.add_view(view=view, header=r'Host:\d') |
| | |
| | | def test_set_notfound_view(self): |
| | | from zope.interface import implementedBy |
| | | from pyramid.interfaces import IRequest |
| | | from pyramid.response import HTTPNotFound |
| | | from pyramid.httpexceptions import HTTPNotFound |
| | | config = self._makeOne(autocommit=True) |
| | | view = lambda *arg: arg |
| | | config.set_notfound_view(view) |
| | |
| | | def test_set_notfound_view_request_has_context(self): |
| | | from zope.interface import implementedBy |
| | | from pyramid.interfaces import IRequest |
| | | from pyramid.response import HTTPNotFound |
| | | from pyramid.httpexceptions import HTTPNotFound |
| | | config = self._makeOne(autocommit=True) |
| | | view = lambda *arg: arg |
| | | config.set_notfound_view(view) |
| | |
| | | def test_set_notfound_view_with_renderer(self): |
| | | from zope.interface import implementedBy |
| | | from pyramid.interfaces import IRequest |
| | | from pyramid.response import HTTPNotFound |
| | | from pyramid.httpexceptions import HTTPNotFound |
| | | config = self._makeOne(autocommit=True) |
| | | view = lambda *arg: {} |
| | | config.set_notfound_view(view, |
| | |
| | | def test_set_forbidden_view(self): |
| | | from zope.interface import implementedBy |
| | | from pyramid.interfaces import IRequest |
| | | from pyramid.response import Forbidden |
| | | from pyramid.httpexceptions import HTTPForbidden |
| | | config = self._makeOne(autocommit=True) |
| | | view = lambda *arg: 'OK' |
| | | config.set_forbidden_view(view) |
| | | request = self._makeRequest(config) |
| | | view = self._getViewCallable(config, ctx_iface=implementedBy(Forbidden), |
| | | view = self._getViewCallable(config, |
| | | ctx_iface=implementedBy(HTTPForbidden), |
| | | request_iface=IRequest) |
| | | result = view(None, request) |
| | | self.assertEqual(result, 'OK') |
| | |
| | | def test_set_forbidden_view_request_has_context(self): |
| | | from zope.interface import implementedBy |
| | | from pyramid.interfaces import IRequest |
| | | from pyramid.response import Forbidden |
| | | from pyramid.httpexceptions import HTTPForbidden |
| | | config = self._makeOne(autocommit=True) |
| | | view = lambda *arg: arg |
| | | config.set_forbidden_view(view) |
| | | request = self._makeRequest(config) |
| | | request.context = 'abc' |
| | | view = self._getViewCallable(config, ctx_iface=implementedBy(Forbidden), |
| | | view = self._getViewCallable(config, |
| | | ctx_iface=implementedBy(HTTPForbidden), |
| | | request_iface=IRequest) |
| | | result = view(None, request) |
| | | self.assertEqual(result, ('abc', request)) |
| | |
| | | def test_set_forbidden_view_with_renderer(self): |
| | | from zope.interface import implementedBy |
| | | from pyramid.interfaces import IRequest |
| | | from pyramid.response import Forbidden |
| | | from pyramid.httpexceptions import HTTPForbidden |
| | | config = self._makeOne(autocommit=True) |
| | | view = lambda *arg: {} |
| | | config.set_forbidden_view(view, |
| | |
| | | try: # chameleon requires a threadlocal registry |
| | | request = self._makeRequest(config) |
| | | view = self._getViewCallable(config, |
| | | ctx_iface=implementedBy(Forbidden), |
| | | ctx_iface=implementedBy(HTTPForbidden), |
| | | request_iface=IRequest) |
| | | result = view(None, request) |
| | | finally: |
| | |
| | | "None against context None): True") |
| | | |
| | | def test_debug_auth_permission_authpol_denied(self): |
| | | from pyramid.response import Forbidden |
| | | from pyramid.httpexceptions import HTTPForbidden |
| | | view = lambda *arg: 'OK' |
| | | self.config.registry.settings = dict( |
| | | debug_authorization=True, reload_templates=True) |
| | |
| | | request = self._makeRequest() |
| | | request.view_name = 'view_name' |
| | | request.url = 'url' |
| | | self.assertRaises(Forbidden, result, None, request) |
| | | self.assertRaises(HTTPForbidden, result, None, request) |
| | | self.assertEqual(len(logger.messages), 1) |
| | | self.assertEqual(logger.messages[0], |
| | | "debug_authorization of url url (view name " |
| | |
| | | self.assertEqual(predicates, [True, True]) |
| | | |
| | | def test_with_predicates_notall(self): |
| | | from pyramid.response import HTTPNotFound |
| | | from pyramid.httpexceptions import HTTPNotFound |
| | | view = lambda *arg: 'OK' |
| | | predicates = [] |
| | | def predicate1(context, request): |
| | |
| | | self.assertEqual(mv.get_views(request), mv.views) |
| | | |
| | | def test_match_not_found(self): |
| | | from pyramid.response import HTTPNotFound |
| | | from pyramid.httpexceptions import HTTPNotFound |
| | | mv = self._makeOne() |
| | | context = DummyContext() |
| | | request = DummyRequest() |
| | | self.assertRaises(HTTPNotFound, mv.match, context, request) |
| | | |
| | | def test_match_predicate_fails(self): |
| | | from pyramid.response import HTTPNotFound |
| | | from pyramid.httpexceptions import HTTPNotFound |
| | | mv = self._makeOne() |
| | | def view(context, request): |
| | | """ """ |
| | |
| | | self.assertEqual(result, view) |
| | | |
| | | def test_permitted_no_views(self): |
| | | from pyramid.response import HTTPNotFound |
| | | from pyramid.httpexceptions import HTTPNotFound |
| | | mv = self._makeOne() |
| | | context = DummyContext() |
| | | request = DummyRequest() |
| | |
| | | self.assertEqual(result, False) |
| | | |
| | | def test__call__not_found(self): |
| | | from pyramid.response import HTTPNotFound |
| | | from pyramid.httpexceptions import HTTPNotFound |
| | | mv = self._makeOne() |
| | | context = DummyContext() |
| | | request = DummyRequest() |
| | |
| | | self.assertEqual(response, expected_response) |
| | | |
| | | def test___call__raise_not_found_isnt_interpreted_as_pred_mismatch(self): |
| | | from pyramid.response import HTTPNotFound |
| | | from pyramid.httpexceptions import HTTPNotFound |
| | | mv = self._makeOne() |
| | | context = DummyContext() |
| | | request = DummyRequest() |
| | |
| | | self.assertEqual(response, expected_response) |
| | | |
| | | def test__call_permissive__not_found(self): |
| | | from pyramid.response import HTTPNotFound |
| | | from pyramid.httpexceptions import HTTPNotFound |
| | | mv = self._makeOne() |
| | | context = DummyContext() |
| | | request = DummyRequest() |
| | |
| | | import unittest |
| | | |
| | | class TestBWCompat(unittest.TestCase): |
| | | def test_bwcompat_notfound(self): |
| | | from pyramid.exceptions import NotFound as one |
| | | from pyramid.httpexceptions import HTTPNotFound as two |
| | | self.assertTrue(one is two) |
| | | |
| | | def test_bwcompat_forbidden(self): |
| | | from pyramid.exceptions import Forbidden as one |
| | | from pyramid.httpexceptions import HTTPForbidden as two |
| | | self.assertTrue(one is two) |
| | | |
| | | class TestNotFound(unittest.TestCase): |
| | | def _makeOne(self, message): |
| | | from pyramid.exceptions import NotFound |
| | |
| | | |
| | | def test_response_equivalence(self): |
| | | from pyramid.exceptions import NotFound |
| | | from pyramid.response import HTTPNotFound |
| | | from pyramid.httpexceptions import HTTPNotFound |
| | | self.assertTrue(NotFound is HTTPNotFound) |
| | | |
| | | class TestForbidden(unittest.TestCase): |
| | |
| | | |
| | | def test_response_equivalence(self): |
| | | from pyramid.exceptions import Forbidden |
| | | from pyramid.response import HTTPForbidden |
| | | from pyramid.httpexceptions import HTTPForbidden |
| | | self.assertTrue(Forbidden is HTTPForbidden) |
| | | |
| | |
| | | import unittest |
| | | |
| | | class TestIt(unittest.TestCase): |
| | | def test_bwcompat_imports(self): |
| | | from pyramid.httpexceptions import HTTPNotFound as one |
| | | from pyramid.response import HTTPNotFound as two |
| | | self.assertTrue(one is two) |
| | | class Test_responsecode(unittest.TestCase): |
| | | def _callFUT(self, *arg, **kw): |
| | | from pyramid.httpexceptions import responsecode |
| | | return responsecode(*arg, **kw) |
| | | |
| | | def test_status_404(self): |
| | | from pyramid.httpexceptions import HTTPNotFound |
| | | self.assertEqual(self._callFUT(404).__class__, HTTPNotFound) |
| | | |
| | | def test_status_201(self): |
| | | from pyramid.httpexceptions import HTTPCreated |
| | | self.assertEqual(self._callFUT(201).__class__, HTTPCreated) |
| | | |
| | | def test_extra_kw(self): |
| | | resp = self._callFUT(404, headers=[('abc', 'def')]) |
| | | self.assertEqual(resp.headers['abc'], 'def') |
| | | |
| | | class Test_default_exceptionresponse_view(unittest.TestCase): |
| | | def _callFUT(self, context, request): |
| | | from pyramid.httpexceptions import default_exceptionresponse_view |
| | | return default_exceptionresponse_view(context, request) |
| | | |
| | | def test_call_with_exception(self): |
| | | context = Exception() |
| | | result = self._callFUT(context, None) |
| | | self.assertEqual(result, context) |
| | | |
| | | def test_call_with_nonexception(self): |
| | | request = DummyRequest() |
| | | context = Exception() |
| | | request.exception = context |
| | | result = self._callFUT(None, request) |
| | | self.assertEqual(result, context) |
| | | |
| | | class Test__no_escape(unittest.TestCase): |
| | | def _callFUT(self, val): |
| | | from pyramid.httpexceptions import _no_escape |
| | | return _no_escape(val) |
| | | |
| | | def test_null(self): |
| | | self.assertEqual(self._callFUT(None), '') |
| | | |
| | | def test_not_basestring(self): |
| | | self.assertEqual(self._callFUT(42), '42') |
| | | |
| | | def test_unicode(self): |
| | | class DummyUnicodeObject(object): |
| | | def __unicode__(self): |
| | | return u'42' |
| | | duo = DummyUnicodeObject() |
| | | self.assertEqual(self._callFUT(duo), u'42') |
| | | |
| | | class TestWSGIHTTPException(unittest.TestCase): |
| | | def _getTargetClass(self): |
| | | from pyramid.httpexceptions import WSGIHTTPException |
| | | return WSGIHTTPException |
| | | |
| | | def _getTargetSubclass(self, code='200', title='OK', |
| | | explanation='explanation', empty_body=False): |
| | | cls = self._getTargetClass() |
| | | class Subclass(cls): |
| | | pass |
| | | Subclass.empty_body = empty_body |
| | | Subclass.code = code |
| | | Subclass.title = title |
| | | Subclass.explanation = explanation |
| | | return Subclass |
| | | |
| | | def _makeOne(self, *arg, **kw): |
| | | cls = self._getTargetClass() |
| | | return cls(*arg, **kw) |
| | | |
| | | def test_implements_IResponse(self): |
| | | from pyramid.interfaces import IResponse |
| | | cls = self._getTargetClass() |
| | | self.failUnless(IResponse.implementedBy(cls)) |
| | | |
| | | def test_provides_IResponse(self): |
| | | from pyramid.interfaces import IResponse |
| | | inst = self._getTargetClass()() |
| | | self.failUnless(IResponse.providedBy(inst)) |
| | | |
| | | def test_implements_IExceptionResponse(self): |
| | | from pyramid.interfaces import IExceptionResponse |
| | | cls = self._getTargetClass() |
| | | self.failUnless(IExceptionResponse.implementedBy(cls)) |
| | | |
| | | def test_provides_IExceptionResponse(self): |
| | | from pyramid.interfaces import IExceptionResponse |
| | | inst = self._getTargetClass()() |
| | | self.failUnless(IExceptionResponse.providedBy(inst)) |
| | | |
| | | def test_ctor_sets_detail(self): |
| | | exc = self._makeOne('message') |
| | | self.assertEqual(exc.detail, 'message') |
| | | |
| | | def test_ctor_sets_comment(self): |
| | | exc = self._makeOne(comment='comment') |
| | | self.assertEqual(exc.comment, 'comment') |
| | | |
| | | def test_ctor_calls_Exception_ctor(self): |
| | | exc = self._makeOne('message') |
| | | self.assertEqual(exc.message, 'message') |
| | | |
| | | def test_ctor_calls_Response_ctor(self): |
| | | exc = self._makeOne('message') |
| | | self.assertEqual(exc.status, 'None None') |
| | | |
| | | def test_ctor_extends_headers(self): |
| | | exc = self._makeOne(headers=[('X-Foo', 'foo')]) |
| | | self.assertEqual(exc.headers.get('X-Foo'), 'foo') |
| | | |
| | | def test_ctor_sets_body_template_obj(self): |
| | | exc = self._makeOne(body_template='${foo}') |
| | | self.assertEqual( |
| | | exc.body_template_obj.substitute({'foo':'foo'}), 'foo') |
| | | |
| | | def test_ctor_with_empty_body(self): |
| | | cls = self._getTargetSubclass(empty_body=True) |
| | | exc = cls() |
| | | self.assertEqual(exc.content_type, None) |
| | | self.assertEqual(exc.content_length, None) |
| | | |
| | | def test_ctor_with_body_doesnt_set_default_app_iter(self): |
| | | exc = self._makeOne(body='123') |
| | | self.assertEqual(exc.app_iter, ['123']) |
| | | |
| | | def test_ctor_with_unicode_body_doesnt_set_default_app_iter(self): |
| | | exc = self._makeOne(unicode_body=u'123') |
| | | self.assertEqual(exc.app_iter, ['123']) |
| | | |
| | | def test_ctor_with_app_iter_doesnt_set_default_app_iter(self): |
| | | exc = self._makeOne(app_iter=['123']) |
| | | self.assertEqual(exc.app_iter, ['123']) |
| | | |
| | | def test_ctor_with_body_sets_default_app_iter_html(self): |
| | | cls = self._getTargetSubclass() |
| | | exc = cls('detail') |
| | | body = list(exc.app_iter)[0] |
| | | self.assertTrue(body.startswith('<html')) |
| | | self.assertTrue('200 OK' in body) |
| | | self.assertTrue('explanation' in body) |
| | | self.assertTrue('detail' in body) |
| | | |
| | | def test_ctor_with_body_sets_default_app_iter_text(self): |
| | | cls = self._getTargetSubclass() |
| | | exc = cls('detail') |
| | | exc.content_type = 'text/plain' |
| | | body = list(exc.app_iter)[0] |
| | | self.assertEqual(body, '200 OK\n\nexplanation\n\n\ndetail\n\n') |
| | | |
| | | def test__str__detail(self): |
| | | exc = self._makeOne() |
| | | exc.detail = 'abc' |
| | | self.assertEqual(str(exc), 'abc') |
| | | |
| | | def test__str__explanation(self): |
| | | exc = self._makeOne() |
| | | exc.explanation = 'def' |
| | | self.assertEqual(str(exc), 'def') |
| | | |
| | | def test_wsgi_response(self): |
| | | exc = self._makeOne() |
| | | self.assertTrue(exc is exc.wsgi_response) |
| | | |
| | | def test_exception(self): |
| | | exc = self._makeOne() |
| | | self.assertTrue(exc is exc.exception) |
| | | |
| | | def test__default_app_iter_no_comment_plain(self): |
| | | cls = self._getTargetSubclass() |
| | | exc = cls() |
| | | exc.content_type = 'text/plain' |
| | | body = list(exc._default_app_iter())[0] |
| | | self.assertEqual(body, '200 OK\n\nexplanation\n\n\n\n\n') |
| | | |
| | | def test__default_app_iter_with_comment_plain(self): |
| | | cls = self._getTargetSubclass() |
| | | exc = cls(comment='comment') |
| | | exc.content_type = 'text/plain' |
| | | body = list(exc._default_app_iter())[0] |
| | | self.assertEqual(body, '200 OK\n\nexplanation\n\n\n\ncomment\n') |
| | | |
| | | def test__default_app_iter_no_comment_html(self): |
| | | cls = self._getTargetSubclass() |
| | | exc = cls() |
| | | exc.content_type = 'text/html' |
| | | body = list(exc._default_app_iter())[0] |
| | | self.assertFalse('<!-- ' in body) |
| | | |
| | | def test__default_app_iter_with_comment_html(self): |
| | | cls = self._getTargetSubclass() |
| | | exc = cls(comment='comment & comment') |
| | | exc.content_type = 'text/html' |
| | | body = list(exc._default_app_iter())[0] |
| | | self.assertTrue('<!-- comment & comment -->' in body) |
| | | |
| | | def test_custom_body_template_no_environ(self): |
| | | cls = self._getTargetSubclass() |
| | | exc = cls(body_template='${location}', location='foo') |
| | | exc.content_type = 'text/plain' |
| | | body = list(exc._default_app_iter())[0] |
| | | self.assertEqual(body, '200 OK\n\nfoo') |
| | | |
| | | def test_custom_body_template_with_environ(self): |
| | | cls = self._getTargetSubclass() |
| | | from pyramid.request import Request |
| | | request = Request.blank('/') |
| | | exc = cls(body_template='${REQUEST_METHOD}', request=request) |
| | | exc.content_type = 'text/plain' |
| | | body = list(exc._default_app_iter())[0] |
| | | self.assertEqual(body, '200 OK\n\nGET') |
| | | |
| | | def test_body_template_unicode(self): |
| | | from pyramid.request import Request |
| | | cls = self._getTargetSubclass() |
| | | la = unicode('/La Pe\xc3\xb1a', 'utf-8') |
| | | request = Request.blank('/') |
| | | request.environ['unicodeval'] = la |
| | | exc = cls(body_template='${unicodeval}', request=request) |
| | | exc.content_type = 'text/plain' |
| | | body = list(exc._default_app_iter())[0] |
| | | self.assertEqual(body, '200 OK\n\n/La Pe\xc3\xb1a') |
| | | |
| | | class TestRenderAllExceptionsWithoutArguments(unittest.TestCase): |
| | | def _doit(self, content_type): |
| | | from pyramid.httpexceptions import status_map |
| | | L = [] |
| | | self.assertTrue(status_map) |
| | | for v in status_map.values(): |
| | | exc = v() |
| | | exc.content_type = content_type |
| | | result = list(exc.app_iter)[0] |
| | | if exc.empty_body: |
| | | self.assertEqual(result, '') |
| | | else: |
| | | self.assertTrue(exc.status in result) |
| | | L.append(result) |
| | | self.assertEqual(len(L), len(status_map)) |
| | | |
| | | def test_it_plain(self): |
| | | self._doit('text/plain') |
| | | |
| | | def test_it_html(self): |
| | | self._doit('text/html') |
| | | |
| | | class Test_HTTPMove(unittest.TestCase): |
| | | def _makeOne(self, *arg, **kw): |
| | | from pyramid.httpexceptions import _HTTPMove |
| | | return _HTTPMove(*arg, **kw) |
| | | |
| | | def test_it_location_not_passed(self): |
| | | exc = self._makeOne() |
| | | self.assertEqual(exc.location, '') |
| | | |
| | | def test_it_location_passed(self): |
| | | exc = self._makeOne(location='foo') |
| | | self.assertEqual(exc.location, 'foo') |
| | | |
| | | class TestHTTPForbidden(unittest.TestCase): |
| | | def _makeOne(self, *arg, **kw): |
| | | from pyramid.httpexceptions import HTTPForbidden |
| | | return HTTPForbidden(*arg, **kw) |
| | | |
| | | def test_it_result_not_passed(self): |
| | | exc = self._makeOne() |
| | | self.assertEqual(exc.result, None) |
| | | |
| | | def test_it_result_passed(self): |
| | | exc = self._makeOne(result='foo') |
| | | self.assertEqual(exc.result, 'foo') |
| | | |
| | | class DummyRequest(object): |
| | | exception = None |
| | | |
| | |
| | | from pyramid.response import Response |
| | | return Response |
| | | |
| | | def test_implements_IExceptionResponse(self): |
| | | from pyramid.interfaces import IExceptionResponse |
| | | Response = self._getTargetClass() |
| | | self.failUnless(IExceptionResponse.implementedBy(Response)) |
| | | |
| | | def test_provides_IExceptionResponse(self): |
| | | from pyramid.interfaces import IExceptionResponse |
| | | response = self._getTargetClass()() |
| | | self.failUnless(IExceptionResponse.providedBy(response)) |
| | | |
| | | class Test_abort(unittest.TestCase): |
| | | def _callFUT(self, *arg, **kw): |
| | | from pyramid.response import abort |
| | | return abort(*arg, **kw) |
| | | |
| | | def test_status_404(self): |
| | | from pyramid.response import HTTPNotFound |
| | | self.assertRaises(HTTPNotFound, self._callFUT, 404) |
| | | |
| | | def test_status_201(self): |
| | | from pyramid.response import HTTPCreated |
| | | self.assertRaises(HTTPCreated, self._callFUT, 201) |
| | | |
| | | def test_extra_kw(self): |
| | | from pyramid.response import HTTPNotFound |
| | | try: |
| | | self._callFUT(404, headers=[('abc', 'def')]) |
| | | except HTTPNotFound, exc: |
| | | self.assertEqual(exc.headers['abc'], 'def') |
| | | else: # pragma: no cover |
| | | raise AssertionError |
| | | |
| | | class Test_redirect(unittest.TestCase): |
| | | def _callFUT(self, *arg, **kw): |
| | | from pyramid.response import redirect |
| | | return redirect(*arg, **kw) |
| | | |
| | | def test_default(self): |
| | | from pyramid.response import HTTPFound |
| | | try: |
| | | self._callFUT('http://example.com') |
| | | except HTTPFound, exc: |
| | | self.assertEqual(exc.location, 'http://example.com') |
| | | self.assertEqual(exc.status, '302 Found') |
| | | |
| | | def test_custom_code(self): |
| | | from pyramid.response import HTTPMovedPermanently |
| | | try: |
| | | self._callFUT('http://example.com', 301) |
| | | except HTTPMovedPermanently, exc: |
| | | self.assertEqual(exc.location, 'http://example.com') |
| | | self.assertEqual(exc.status, '301 Moved Permanently') |
| | | |
| | | def test_extra_kw(self): |
| | | from pyramid.response import HTTPFound |
| | | try: |
| | | self._callFUT('http://example.com', headers=[('abc', 'def')]) |
| | | except HTTPFound, exc: |
| | | self.assertEqual(exc.location, 'http://example.com') |
| | | self.assertEqual(exc.status, '302 Found') |
| | | self.assertEqual(exc.headers['abc'], 'def') |
| | | |
| | | |
| | | class Test_default_exceptionresponse_view(unittest.TestCase): |
| | | def _callFUT(self, context, request): |
| | | from pyramid.response import default_exceptionresponse_view |
| | | return default_exceptionresponse_view(context, request) |
| | | |
| | | def test_call_with_exception(self): |
| | | context = Exception() |
| | | result = self._callFUT(context, None) |
| | | self.assertEqual(result, context) |
| | | |
| | | def test_call_with_nonexception(self): |
| | | request = DummyRequest() |
| | | context = Exception() |
| | | request.exception = context |
| | | result = self._callFUT(None, request) |
| | | self.assertEqual(result, context) |
| | | |
| | | class Test__no_escape(unittest.TestCase): |
| | | def _callFUT(self, val): |
| | | from pyramid.response import _no_escape |
| | | return _no_escape(val) |
| | | |
| | | def test_null(self): |
| | | self.assertEqual(self._callFUT(None), '') |
| | | |
| | | def test_not_basestring(self): |
| | | self.assertEqual(self._callFUT(42), '42') |
| | | |
| | | def test_unicode(self): |
| | | class DummyUnicodeObject(object): |
| | | def __unicode__(self): |
| | | return u'42' |
| | | duo = DummyUnicodeObject() |
| | | self.assertEqual(self._callFUT(duo), u'42') |
| | | |
| | | class TestWSGIHTTPException(unittest.TestCase): |
| | | def _getTargetClass(self): |
| | | from pyramid.response import WSGIHTTPException |
| | | return WSGIHTTPException |
| | | |
| | | def _getTargetSubclass(self, code='200', title='OK', |
| | | explanation='explanation', empty_body=False): |
| | | def test_implements_IResponse(self): |
| | | from pyramid.interfaces import IResponse |
| | | cls = self._getTargetClass() |
| | | class Subclass(cls): |
| | | pass |
| | | Subclass.empty_body = empty_body |
| | | Subclass.code = code |
| | | Subclass.title = title |
| | | Subclass.explanation = explanation |
| | | return Subclass |
| | | self.failUnless(IResponse.implementedBy(cls)) |
| | | |
| | | def _makeOne(self, *arg, **kw): |
| | | cls = self._getTargetClass() |
| | | return cls(*arg, **kw) |
| | | |
| | | def test_ctor_sets_detail(self): |
| | | exc = self._makeOne('message') |
| | | self.assertEqual(exc.detail, 'message') |
| | | |
| | | def test_ctor_sets_comment(self): |
| | | exc = self._makeOne(comment='comment') |
| | | self.assertEqual(exc.comment, 'comment') |
| | | |
| | | def test_ctor_calls_Exception_ctor(self): |
| | | exc = self._makeOne('message') |
| | | self.assertEqual(exc.message, 'message') |
| | | |
| | | def test_ctor_calls_Response_ctor(self): |
| | | exc = self._makeOne('message') |
| | | self.assertEqual(exc.status, 'None None') |
| | | |
| | | def test_ctor_extends_headers(self): |
| | | exc = self._makeOne(headers=[('X-Foo', 'foo')]) |
| | | self.assertEqual(exc.headers.get('X-Foo'), 'foo') |
| | | |
| | | def test_ctor_sets_body_template_obj(self): |
| | | exc = self._makeOne(body_template='${foo}') |
| | | self.assertEqual( |
| | | exc.body_template_obj.substitute({'foo':'foo'}), 'foo') |
| | | |
| | | def test_ctor_with_empty_body(self): |
| | | cls = self._getTargetSubclass(empty_body=True) |
| | | exc = cls() |
| | | self.assertEqual(exc.content_type, None) |
| | | self.assertEqual(exc.content_length, None) |
| | | |
| | | def test_ctor_with_body_doesnt_set_default_app_iter(self): |
| | | exc = self._makeOne(body='123') |
| | | self.assertEqual(exc.app_iter, ['123']) |
| | | |
| | | def test_ctor_with_unicode_body_doesnt_set_default_app_iter(self): |
| | | exc = self._makeOne(unicode_body=u'123') |
| | | self.assertEqual(exc.app_iter, ['123']) |
| | | |
| | | def test_ctor_with_app_iter_doesnt_set_default_app_iter(self): |
| | | exc = self._makeOne(app_iter=['123']) |
| | | self.assertEqual(exc.app_iter, ['123']) |
| | | |
| | | def test_ctor_with_body_sets_default_app_iter_html(self): |
| | | cls = self._getTargetSubclass() |
| | | exc = cls('detail') |
| | | body = list(exc.app_iter)[0] |
| | | self.assertTrue(body.startswith('<html')) |
| | | self.assertTrue('200 OK' in body) |
| | | self.assertTrue('explanation' in body) |
| | | self.assertTrue('detail' in body) |
| | | |
| | | def test_ctor_with_body_sets_default_app_iter_text(self): |
| | | cls = self._getTargetSubclass() |
| | | exc = cls('detail') |
| | | exc.content_type = 'text/plain' |
| | | body = list(exc.app_iter)[0] |
| | | self.assertEqual(body, '200 OK\n\nexplanation\n\n\ndetail\n\n') |
| | | |
| | | def test__str__detail(self): |
| | | exc = self._makeOne() |
| | | exc.detail = 'abc' |
| | | self.assertEqual(str(exc), 'abc') |
| | | |
| | | def test__str__explanation(self): |
| | | exc = self._makeOne() |
| | | exc.explanation = 'def' |
| | | self.assertEqual(str(exc), 'def') |
| | | |
| | | def test_wsgi_response(self): |
| | | exc = self._makeOne() |
| | | self.assertTrue(exc is exc.wsgi_response) |
| | | |
| | | def test_exception(self): |
| | | exc = self._makeOne() |
| | | self.assertTrue(exc is exc.exception) |
| | | |
| | | def test__default_app_iter_no_comment_plain(self): |
| | | cls = self._getTargetSubclass() |
| | | exc = cls() |
| | | exc.content_type = 'text/plain' |
| | | body = list(exc._default_app_iter())[0] |
| | | self.assertEqual(body, '200 OK\n\nexplanation\n\n\n\n\n') |
| | | |
| | | def test__default_app_iter_with_comment_plain(self): |
| | | cls = self._getTargetSubclass() |
| | | exc = cls(comment='comment') |
| | | exc.content_type = 'text/plain' |
| | | body = list(exc._default_app_iter())[0] |
| | | self.assertEqual(body, '200 OK\n\nexplanation\n\n\n\ncomment\n') |
| | | |
| | | def test__default_app_iter_no_comment_html(self): |
| | | cls = self._getTargetSubclass() |
| | | exc = cls() |
| | | exc.content_type = 'text/html' |
| | | body = list(exc._default_app_iter())[0] |
| | | self.assertFalse('<!-- ' in body) |
| | | |
| | | def test__default_app_iter_with_comment_html(self): |
| | | cls = self._getTargetSubclass() |
| | | exc = cls(comment='comment & comment') |
| | | exc.content_type = 'text/html' |
| | | body = list(exc._default_app_iter())[0] |
| | | self.assertTrue('<!-- comment & comment -->' in body) |
| | | |
| | | def test_custom_body_template_no_environ(self): |
| | | cls = self._getTargetSubclass() |
| | | exc = cls(body_template='${location}', location='foo') |
| | | exc.content_type = 'text/plain' |
| | | body = list(exc._default_app_iter())[0] |
| | | self.assertEqual(body, '200 OK\n\nfoo') |
| | | |
| | | def test_custom_body_template_with_environ(self): |
| | | cls = self._getTargetSubclass() |
| | | from pyramid.request import Request |
| | | request = Request.blank('/') |
| | | exc = cls(body_template='${REQUEST_METHOD}', request=request) |
| | | exc.content_type = 'text/plain' |
| | | body = list(exc._default_app_iter())[0] |
| | | self.assertEqual(body, '200 OK\n\nGET') |
| | | |
| | | def test_body_template_unicode(self): |
| | | from pyramid.request import Request |
| | | cls = self._getTargetSubclass() |
| | | la = unicode('/La Pe\xc3\xb1a', 'utf-8') |
| | | request = Request.blank('/') |
| | | request.environ['unicodeval'] = la |
| | | exc = cls(body_template='${unicodeval}', request=request) |
| | | exc.content_type = 'text/plain' |
| | | body = list(exc._default_app_iter())[0] |
| | | self.assertEqual(body, '200 OK\n\n/La Pe\xc3\xb1a') |
| | | |
| | | class TestRenderAllExceptionsWithoutArguments(unittest.TestCase): |
| | | def _doit(self, content_type): |
| | | from pyramid.response import status_map |
| | | L = [] |
| | | self.assertTrue(status_map) |
| | | for v in status_map.values(): |
| | | exc = v() |
| | | exc.content_type = content_type |
| | | result = list(exc.app_iter)[0] |
| | | if exc.empty_body: |
| | | self.assertEqual(result, '') |
| | | else: |
| | | self.assertTrue(exc.status in result) |
| | | L.append(result) |
| | | self.assertEqual(len(L), len(status_map)) |
| | | |
| | | def test_it_plain(self): |
| | | self._doit('text/plain') |
| | | |
| | | def test_it_html(self): |
| | | self._doit('text/html') |
| | | |
| | | class Test_HTTPMove(unittest.TestCase): |
| | | def _makeOne(self, *arg, **kw): |
| | | from pyramid.response import _HTTPMove |
| | | return _HTTPMove(*arg, **kw) |
| | | |
| | | def test_it_location_not_passed(self): |
| | | exc = self._makeOne() |
| | | self.assertEqual(exc.location, '') |
| | | |
| | | def test_it_location_passed(self): |
| | | exc = self._makeOne(location='foo') |
| | | self.assertEqual(exc.location, 'foo') |
| | | |
| | | class TestHTTPForbidden(unittest.TestCase): |
| | | def _makeOne(self, *arg, **kw): |
| | | from pyramid.response import HTTPForbidden |
| | | return HTTPForbidden(*arg, **kw) |
| | | |
| | | def test_it_result_not_passed(self): |
| | | exc = self._makeOne() |
| | | self.assertEqual(exc.result, None) |
| | | |
| | | def test_it_result_passed(self): |
| | | exc = self._makeOne(result='foo') |
| | | self.assertEqual(exc.result, 'foo') |
| | | |
| | | class DummyRequest(object): |
| | | exception = None |
| | | def test_provides_IResponse(self): |
| | | from pyramid.interfaces import IResponse |
| | | inst = self._getTargetClass()() |
| | | self.failUnless(IResponse.providedBy(inst)) |
| | | |
| | |
| | | |
| | | from pyramid import testing |
| | | |
| | | def hide_warnings(wrapped): |
| | | import warnings |
| | | def wrapper(*arg, **kw): |
| | | warnings.filterwarnings('ignore') |
| | | try: |
| | | wrapped(*arg, **kw) |
| | | finally: |
| | | warnings.resetwarnings() |
| | | wrapper.__name__ = wrapped.__name__ |
| | | wrapper.__doc__ = wrapped.__doc__ |
| | | return wrapper |
| | | |
| | | |
| | | class TestRouter(unittest.TestCase): |
| | | def setUp(self): |
| | | testing.setUp() |
| | |
| | | self.assertEqual(router.request_factory, DummyRequestFactory) |
| | | |
| | | def test_call_traverser_default(self): |
| | | from pyramid.response import HTTPNotFound |
| | | from pyramid.httpexceptions import HTTPNotFound |
| | | environ = self._makeEnviron() |
| | | logger = self._registerLogger() |
| | | router = self._makeOne() |
| | |
| | | self.assertEqual(len(logger.messages), 0) |
| | | |
| | | def test_traverser_raises_notfound_class(self): |
| | | from pyramid.response import HTTPNotFound |
| | | from pyramid.httpexceptions import HTTPNotFound |
| | | environ = self._makeEnviron() |
| | | context = DummyContext() |
| | | self._registerTraverserFactory(context, raise_error=HTTPNotFound) |
| | |
| | | self.assertRaises(HTTPNotFound, router, environ, start_response) |
| | | |
| | | def test_traverser_raises_notfound_instance(self): |
| | | from pyramid.response import HTTPNotFound |
| | | from pyramid.httpexceptions import HTTPNotFound |
| | | environ = self._makeEnviron() |
| | | context = DummyContext() |
| | | self._registerTraverserFactory(context, raise_error=HTTPNotFound('foo')) |
| | |
| | | self.assertTrue('foo' in why[0], why) |
| | | |
| | | def test_traverser_raises_forbidden_class(self): |
| | | from pyramid.response import Forbidden |
| | | from pyramid.httpexceptions import HTTPForbidden |
| | | environ = self._makeEnviron() |
| | | context = DummyContext() |
| | | self._registerTraverserFactory(context, raise_error=Forbidden) |
| | | self._registerTraverserFactory(context, raise_error=HTTPForbidden) |
| | | router = self._makeOne() |
| | | start_response = DummyStartResponse() |
| | | self.assertRaises(Forbidden, router, environ, start_response) |
| | | self.assertRaises(HTTPForbidden, router, environ, start_response) |
| | | |
| | | def test_traverser_raises_forbidden_instance(self): |
| | | from pyramid.response import Forbidden |
| | | from pyramid.httpexceptions import HTTPForbidden |
| | | environ = self._makeEnviron() |
| | | context = DummyContext() |
| | | self._registerTraverserFactory(context, raise_error=Forbidden('foo')) |
| | | self._registerTraverserFactory(context, |
| | | raise_error=HTTPForbidden('foo')) |
| | | router = self._makeOne() |
| | | start_response = DummyStartResponse() |
| | | why = exc_raised(Forbidden, router, environ, start_response) |
| | | why = exc_raised(HTTPForbidden, router, environ, start_response) |
| | | self.assertTrue('foo' in why[0], why) |
| | | |
| | | def test_call_no_view_registered_no_isettings(self): |
| | | from pyramid.response import HTTPNotFound |
| | | from pyramid.httpexceptions import HTTPNotFound |
| | | environ = self._makeEnviron() |
| | | context = DummyContext() |
| | | self._registerTraverserFactory(context) |
| | |
| | | self.assertEqual(len(logger.messages), 0) |
| | | |
| | | def test_call_no_view_registered_debug_notfound_false(self): |
| | | from pyramid.response import HTTPNotFound |
| | | from pyramid.httpexceptions import HTTPNotFound |
| | | environ = self._makeEnviron() |
| | | context = DummyContext() |
| | | self._registerTraverserFactory(context) |
| | |
| | | self.assertEqual(len(logger.messages), 0) |
| | | |
| | | def test_call_no_view_registered_debug_notfound_true(self): |
| | | from pyramid.response import HTTPNotFound |
| | | from pyramid.httpexceptions import HTTPNotFound |
| | | environ = self._makeEnviron() |
| | | context = DummyContext() |
| | | self._registerTraverserFactory(context) |
| | |
| | | def test_call_view_registered_specific_fail(self): |
| | | from zope.interface import Interface |
| | | from zope.interface import directlyProvides |
| | | from pyramid.response import HTTPNotFound |
| | | from pyramid.httpexceptions import HTTPNotFound |
| | | from pyramid.interfaces import IViewClassifier |
| | | class IContext(Interface): |
| | | pass |
| | |
| | | def test_call_view_raises_forbidden(self): |
| | | from zope.interface import Interface |
| | | from zope.interface import directlyProvides |
| | | from pyramid.response import Forbidden |
| | | from pyramid.httpexceptions import HTTPForbidden |
| | | class IContext(Interface): |
| | | pass |
| | | from pyramid.interfaces import IRequest |
| | |
| | | directlyProvides(context, IContext) |
| | | self._registerTraverserFactory(context, subpath=['']) |
| | | response = DummyResponse() |
| | | view = DummyView(response, raise_exception=Forbidden("unauthorized")) |
| | | view = DummyView(response, |
| | | raise_exception=HTTPForbidden("unauthorized")) |
| | | environ = self._makeEnviron() |
| | | self._registerView(view, '', IViewClassifier, IRequest, IContext) |
| | | router = self._makeOne() |
| | | start_response = DummyStartResponse() |
| | | why = exc_raised(Forbidden, router, environ, start_response) |
| | | why = exc_raised(HTTPForbidden, router, environ, start_response) |
| | | self.assertEqual(why[0], 'unauthorized') |
| | | |
| | | def test_call_view_raises_notfound(self): |
| | |
| | | pass |
| | | from pyramid.interfaces import IRequest |
| | | from pyramid.interfaces import IViewClassifier |
| | | from pyramid.response import HTTPNotFound |
| | | from pyramid.httpexceptions import HTTPNotFound |
| | | context = DummyContext() |
| | | directlyProvides(context, IContext) |
| | | self._registerTraverserFactory(context, subpath=['']) |
| | |
| | | "pattern: 'archives/:action/:article', ")) |
| | | |
| | | def test_call_route_match_miss_debug_routematch(self): |
| | | from pyramid.response import HTTPNotFound |
| | | from pyramid.httpexceptions import HTTPNotFound |
| | | logger = self._registerLogger() |
| | | self._registerSettings(debug_routematch=True) |
| | | self._registerRouteRequest('foo') |
| | |
| | | |
| | | def test_root_factory_raises_notfound(self): |
| | | from pyramid.interfaces import IRootFactory |
| | | from pyramid.response import HTTPNotFound |
| | | from pyramid.httpexceptions import HTTPNotFound |
| | | from zope.interface import Interface |
| | | from zope.interface import directlyProvides |
| | | def rootfactory(request): |
| | |
| | | |
| | | def test_root_factory_raises_forbidden(self): |
| | | from pyramid.interfaces import IRootFactory |
| | | from pyramid.response import Forbidden |
| | | from pyramid.httpexceptions import HTTPForbidden |
| | | from zope.interface import Interface |
| | | from zope.interface import directlyProvides |
| | | def rootfactory(request): |
| | | raise Forbidden('from root factory') |
| | | raise HTTPForbidden('from root factory') |
| | | self.registry.registerUtility(rootfactory, IRootFactory) |
| | | class IContext(Interface): |
| | | pass |
| | |
| | | environ = self._makeEnviron() |
| | | router = self._makeOne() |
| | | start_response = DummyStartResponse() |
| | | why = exc_raised(Forbidden, router, environ, start_response) |
| | | why = exc_raised(HTTPForbidden, router, environ, start_response) |
| | | self.assertTrue('from root factory' in why[0]) |
| | | |
| | | def test_root_factory_exception_propagating(self): |
| | |
| | | start_response = DummyStartResponse() |
| | | self.assertRaises(RuntimeError, router, environ, start_response) |
| | | |
| | | class Test_default_responder(unittest.TestCase): |
| | | def _makeOne(self, response): |
| | | from pyramid.router import default_responder |
| | | return default_responder(response) |
| | | |
| | | def test_has_call(self): |
| | | response = DummyResponse() |
| | | response.app_iter = ['123'] |
| | | response.headerlist = [('a', '1')] |
| | | responder = self._makeOne(response) |
| | | request = DummyRequest({'a':'1'}) |
| | | start_response = DummyStartResponse() |
| | | app_iter = responder(request, start_response) |
| | | self.assertEqual(app_iter, response.app_iter) |
| | | self.assertEqual(start_response.status, response.status) |
| | | self.assertEqual(start_response.headers, response.headerlist) |
| | | self.assertEqual(response.environ, request.environ) |
| | | |
| | | @hide_warnings |
| | | def test_without_call_success(self): |
| | | response = DummyResponseWithoutCall() |
| | | response.app_iter = ['123'] |
| | | response.headerlist = [('a', '1')] |
| | | responder = self._makeOne(response) |
| | | request = DummyRequest({'a':'1'}) |
| | | start_response = DummyStartResponse() |
| | | app_iter = responder(request, start_response) |
| | | self.assertEqual(app_iter, response.app_iter) |
| | | self.assertEqual(start_response.status, response.status) |
| | | self.assertEqual(start_response.headers, response.headerlist) |
| | | |
| | | @hide_warnings |
| | | def test_without_call_exception(self): |
| | | response = DummyResponseWithoutCall() |
| | | del response.status |
| | | responder = self._makeOne(response) |
| | | request = DummyRequest({'a':'1'}) |
| | | start_response = DummyStartResponse() |
| | | self.assertRaises(ValueError, responder, request, start_response) |
| | | |
| | | |
| | | class DummyRequest(object): |
| | | def __init__(self, environ=None): |
| | | if environ is None: environ = {} |
| | | self.environ = environ |
| | | |
| | | class DummyContext: |
| | | pass |
| | | |
| | |
| | | def __call__(self, status, headers): |
| | | self.status = status |
| | | self.headers = headers |
| | | |
| | | class DummyResponse: |
| | | |
| | | class DummyResponseWithoutCall: |
| | | headerlist = () |
| | | app_iter = () |
| | | def __init__(self, status='200 OK'): |
| | | self.status = status |
| | | |
| | | class DummyResponse(DummyResponseWithoutCall): |
| | | environ = None |
| | | |
| | | def __call__(self, environ, start_response): |
| | | self.environ = environ |
| | | start_response(self.status, self.headerlist) |
| | | return self.app_iter |
| | | |
| | | class DummyThreadLocalManager: |
| | | def __init__(self): |
| | |
| | | |
| | | def test_registerView_with_permission_denying(self): |
| | | from pyramid import testing |
| | | from pyramid.response import HTTPForbidden |
| | | from pyramid.httpexceptions import HTTPForbidden |
| | | def view(context, request): |
| | | """ """ |
| | | view = testing.registerView('moo.html', view=view, permission='bar') |
| | |
| | | from pyramid.interfaces import IView |
| | | from pyramid.interfaces import IViewClassifier |
| | | |
| | | from pyramid.response import HTTPFound |
| | | from pyramid.response import default_exceptionresponse_view |
| | | from pyramid.httpexceptions import HTTPFound |
| | | from pyramid.httpexceptions import default_exceptionresponse_view |
| | | from pyramid.renderers import RendererHelper |
| | | from pyramid.static import static_view |
| | | from pyramid.threadlocal import get_current_registry |
| | |
| | | ``name`` / ``context`` / and ``request``). |
| | | |
| | | If `secure`` is ``True``, and the :term:`view callable` found is |
| | | protected by a permission, the permission will be checked before |
| | | calling the view function. If the permission check disallows view |
| | | execution (based on the current :term:`authorization policy`), a |
| | | :exc:`pyramid.response.HTTPForbidden` exception will be raised. |
| | | The exception's ``args`` attribute explains why the view access |
| | | was disallowed. |
| | | protected by a permission, the permission will be checked before calling |
| | | the view function. If the permission check disallows view execution |
| | | (based on the current :term:`authorization policy`), a |
| | | :exc:`pyramid.httpexceptions.HTTPForbidden` exception will be raised. |
| | | The exception's ``args`` attribute explains why the view access was |
| | | disallowed. |
| | | |
| | | If ``secure`` is ``False``, no permission checking is done.""" |
| | | provides = [IViewClassifier] + map(providedBy, (request, context)) |
| | |
| | | of this function by calling ``''.join(iterable)``, or just use |
| | | :func:`pyramid.view.render_view` instead. |
| | | |
| | | If ``secure`` is ``True``, and the view is protected by a |
| | | permission, the permission will be checked before the view |
| | | function is invoked. If the permission check disallows view |
| | | execution (based on the current :term:`authentication policy`), a |
| | | :exc:`pyramid.response.HTTPForbidden` exception will be raised; |
| | | its ``args`` attribute explains why the view access was |
| | | disallowed. |
| | | If ``secure`` is ``True``, and the view is protected by a permission, the |
| | | permission will be checked before the view function is invoked. If the |
| | | permission check disallows view execution (based on the current |
| | | :term:`authentication policy`), a |
| | | :exc:`pyramid.httpexceptions.HTTPForbidden` exception will be raised; its |
| | | ``args`` attribute explains why the view access was disallowed. |
| | | |
| | | If ``secure`` is ``False``, no permission checking is |
| | | done.""" |
| | |
| | | ``app_iter`` attribute. This function will return ``None`` if a |
| | | corresponding view cannot be found. |
| | | |
| | | If ``secure`` is ``True``, and the view is protected by a |
| | | permission, the permission will be checked before the view is |
| | | invoked. If the permission check disallows view execution (based |
| | | on the current :term:`authorization policy`), a |
| | | :exc:`pyramid.response.HTTPForbidden` exception will be raised; |
| | | its ``args`` attribute explains why the view access was |
| | | If ``secure`` is ``True``, and the view is protected by a permission, the |
| | | permission will be checked before the view is invoked. If the permission |
| | | check disallows view execution (based on the current :term:`authorization |
| | | policy`), a :exc:`pyramid.httpexceptions.HTTPForbidden` exception will be |
| | | raised; its ``args`` attribute explains why the view access was |
| | | disallowed. |
| | | |
| | | If ``secure`` is ``False``, no permission checking is done.""" |
| | |
| | | |
| | | .. code-block:: python |
| | | |
| | | from pyramid.response import HTTPNotFound |
| | | from pyramid.httpexceptions import HTTPNotFound |
| | | from pyramid.view import AppendSlashNotFoundViewFactory |
| | | |
| | | def notfound_view(context, request): return HTTPNotFound('nope') |
| | |
| | | Use the :meth:`pyramid.config.Configurator.add_view` method to configure this |
| | | view as the Not Found view:: |
| | | |
| | | from pyramid.response import HTTPNotFound |
| | | from pyramid.httpexceptions import HTTPNotFound |
| | | from pyramid.view import append_slash_notfound_view |
| | | config.add_view(append_slash_notfound_view, context=HTTPNotFound) |
| | | |