Skip to content

Commit

Permalink
fix deprecated usage of request.accept in AcceptPredicate
Browse files Browse the repository at this point in the history
  • Loading branch information
mmerickel committed Aug 28, 2018
1 parent df62d60 commit 1754187
Show file tree
Hide file tree
Showing 8 changed files with 231 additions and 74 deletions.
1 change: 1 addition & 0 deletions docs/narr/extconfig.rst
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,7 @@ Pre-defined Phases

:const:`pyramid.config.PHASE1_CONFIG`

- :meth:`pyramid.config.Configurator.add_accept_view_option`
- :meth:`pyramid.config.Configurator.add_renderer`
- :meth:`pyramid.config.Configurator.add_route_predicate`
- :meth:`pyramid.config.Configurator.add_subscriber_predicate`
Expand Down
100 changes: 76 additions & 24 deletions docs/narr/viewconfig.rst
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,17 @@ Non-Predicate Arguments
are just developing stock Pyramid applications. Pay no attention to the man
behind the curtain.

``exception_only``

When this value is ``True``, the ``context`` argument must be a subclass of
``Exception``. This flag indicates that only an :term:`exception view` should
be created, and that this view should not match if the traversal
:term:`context` matches the ``context`` argument. If the ``context`` is a
subclass of ``Exception`` and this value is ``False`` (the default), then a
view will be registered to match the traversal :term:`context` as well.

.. versionadded:: 1.8

Predicate Arguments
+++++++++++++++++++

Expand Down Expand Up @@ -317,17 +328,6 @@ configured view.
If ``context`` is not supplied, the value ``None``, which matches any
resource, is used.

``exception_only``

When this value is ``True``, the ``context`` argument must be a subclass of
``Exception``. This flag indicates that only an :term:`exception view` should
be created, and that this view should not match if the traversal
:term:`context` matches the ``context`` argument. If the ``context`` is a
subclass of ``Exception`` and this value is ``False`` (the default), then a
view will be registered to match the traversal :term:`context` as well.

.. versionadded:: 1.8

``route_name``
If ``route_name`` is supplied, the view callable will be invoked only when
the named route has matched.
Expand All @@ -344,6 +344,20 @@ configured view.
request/context pair found via :term:`resource location` does not indicate it
matched any configured route.

``accept``
A :term:`media type` that will be matched against the ``Accept`` HTTP request header.
If this value is specified, it must be a specific media type, such as ``text/html``.
If the media type is acceptable by the ``Accept`` header of the request, or if the ``Accept`` header isn't set at all in the request, this predicate will match.
If this does not match the ``Accept`` header of the request, view matching continues.

If ``accept`` is not specified, the ``HTTP_ACCEPT`` HTTP header is not taken into consideration when deciding whether or not to invoke the associated view callable.

See :ref:`accept_content_negotation` for more information.

.. versionchanged:: 1.10
Media ranges such as ``text/*`` will now raise :class:`pyramid.exceptions.ConfigurationError`.
Previously these values had undefined behavior based on the version of WebOb being used and was never fully supported.

``request_type``
This value should be an :term:`interface` that the :term:`request` must
provide in order for this view to be found and called.
Expand Down Expand Up @@ -424,19 +438,6 @@ configured view.
taken into consideration when deciding whether or not to invoke the
associated view callable.

``accept``
The value of this argument represents a match query for one or more mimetypes
in the ``Accept`` HTTP request header. If this value is specified, it must
be in one of the following forms: a mimetype match token in the form
``text/plain``, a wildcard mimetype match token in the form ``text/*``, or a
match-all wildcard mimetype match token in the form ``*/*``. If any of the
forms matches the ``Accept`` header of the request, this predicate will be
true.

If ``accept`` is not specified, the ``HTTP_ACCEPT`` HTTP header is not taken
into consideration when deciding whether or not to invoke the associated view
callable.

``header``
This value represents an HTTP header name or a header name/value pair.

Expand Down Expand Up @@ -1028,6 +1029,57 @@ these values.
.. index::
single: HTTP caching

.. _accept_content_negotation:

Accept Header Content Negotiation
---------------------------------

The ``accept`` argument to :meth:`pyramid.config.Configurator.add_view` can be used to control :term:`view lookup` by dispatching to different views based on the HTTP ``Accept`` request header. Consider the below example in which there are two views, sharing the same view callable. Each view specifies uses the accept header to trigger the appropriate response renderer.

.. code-block:: python
from pyramid.view import view_config
@view_config(accept='application/json', renderer='json')
@view_config(accept='text/html', renderer='templates/hello.jinja2')
def myview(request):
return {
'name': request.GET.get('name', 'bob'),
}
Wildcard Accept header
++++++++++++++++++++++

The appropriate view is selected here when the client specifies an unambiguous header such as ``Accept: text/*`` or ``Accept: application/json``. However, by default, if a client specifies ``Accept: */*``, the ordering is undefined. This can be fixed by telling :app:`Pyramid` what the preferred relative ordering is between various accept mimetypes by using :meth:`pyramid.config.Configurator.add_accept_view_option`. For example:

.. code-block:: python
from pyramid.config import Configurator
def main(global_config, **settings):
config = Configurator(settings=settings)
config.add_accept_view_option('text/html')
config.add_accept_view_option(
'application/json',
weighs_more_than='text/html',
)
config.scan()
return config.make_wsgi_app()
Missing Accept header
+++++++++++++++++++++

The above example will not match any view if the ``Accept`` header is not specified by the client. This can be solved by adding a fallback view without an ``accept`` predicate, or by modifying one of the predicates to match ``*/*``. For example, below the html response will be returned in all cases unless ``application/json`` is requested specifically.

.. code-block:: python
@view_config(accept='application/json', renderer='json')
@view_config(accept='*/*', renderer='templates/hello.jinja2')
def myview(request):
return {
'name': request.GET.get('name', 'bob'),
}
.. _influencing_http_caching:

Influencing HTTP Caching
Expand Down
1 change: 1 addition & 0 deletions pyramid/config/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,7 @@ def setup_registry(self,

self.add_default_response_adapters()
self.add_default_renderers()
self.add_default_accept_view_order()
self.add_default_view_predicates()
self.add_default_view_derivers()
self.add_default_route_predicates()
Expand Down
37 changes: 25 additions & 12 deletions pyramid/config/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,18 +139,6 @@ def add_route(self,
.. versionadded:: 1.1
accept
This value represents a match query for one or more mimetypes in the
``Accept`` HTTP request header. If this value is specified, it must
be in one of the following forms: a mimetype match token in the form
``text/plain``, a wildcard mimetype match token in the form
``text/*`` or a match-all wildcard mimetype match token in the form
``*/*``. If any of the forms matches the ``Accept`` header of the
request, or if the ``Accept`` header isn't set at all in the request,
this will match the current route. If this does not match the
``Accept`` header of the request, route matching continues.
Predicate Arguments
pattern
Expand Down Expand Up @@ -233,6 +221,27 @@ def add_route(self,
case of the header name is not significant. If this
predicate returns ``False``, route matching continues.
accept
A media type that will be matched against the ``Accept`` HTTP
request header. If this value is specified, it must be a specific
media type, such as ``text/html``. If the media type is acceptable
by the ``Accept`` header of the request, or if the ``Accept`` header
isn't set at all in the request, this predicate will match. If this
does not match the ``Accept`` header of the request, route matching
continues.
If ``accept`` is not specified, the ``HTTP_ACCEPT`` HTTP header is
not taken into consideration when deciding whether or not to select
the route.
.. versionchanged:: 1.10
Media ranges such as ``text/*`` will now raise
:class:`pyramid.exceptions.ConfigurationError`. Previously,
these values had undefined behavior based on the version of
WebOb being used and was never fully supported.
effective_principals
If specified, this value should be a :term:`principal` identifier or
Expand Down Expand Up @@ -289,6 +298,10 @@ def add_route(self,
DeprecationWarning,
stacklevel=3
)

if accept is not None:
accept = accept.lower()

# these are route predicates; if they do not match, the next route
# in the routelist will be tried
if request_method is not None:
Expand Down
Loading

0 comments on commit 1754187

Please sign in to comment.