summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIra Lun <sammyrosajoe@gmail.com>2017-08-29 21:17:40 +0100
committerIra Lun <sammyrosajoe@gmail.com>2017-08-29 21:17:40 +0100
commit7dc36830c70d784690ac702e85f73600dc4db167 (patch)
tree12ed74dbf48ecbb9d167fb6c2574f7696681da68
parent1a89b120a4855de8d6ae641b6943f72a13ea0417 (diff)
downloadwebob-7dc36830c70d784690ac702e85f73600dc4db167.tar.gz
Add _AcceptInvalidOrNoHeader class.
-rw-r--r--src/webob/acceptparse.py202
1 files changed, 202 insertions, 0 deletions
diff --git a/src/webob/acceptparse.py b/src/webob/acceptparse.py
index b09c0aa..5430f64 100644
--- a/src/webob/acceptparse.py
+++ b/src/webob/acceptparse.py
@@ -1067,6 +1067,208 @@ class AcceptValidHeader(Accept):
return bestq or None
+class _AcceptInvalidOrNoHeader(Accept):
+ """
+ Represent when an ``Accept`` header is invalid or not in request.
+
+ This is the base class for the behaviour that :class:`.AcceptInvalidHeader`
+ and :class:`.AcceptNoHeader` have in common.
+
+ :rfc:`7231` does not provide any guidance on what should happen if the
+ ``Accept`` header has an invalid value. This implementation disregards the
+ header when the header is invalid, so :class:`.AcceptInvalidHeader` and
+ :class:`.AcceptNoHeader` have much behaviour in common.
+ """
+
+ def __bool__(self):
+ """
+ Return whether ``self`` represents a valid ``Accept`` header.
+
+ Return ``True`` if ``self`` represents a valid header, and ``False`` if
+ it represents an invalid header, or the header not being in the
+ request.
+
+ For this class, it always returns ``False``.
+ """
+ return False
+ __nonzero__ = __bool__ # Python 2
+
+ def __contains__(self, offer):
+ """
+ Return ``bool`` indicating whether `offer` is acceptable.
+
+ .. warning::
+
+ The behavior of ``.__contains__`` for the ``Accept`` classes is
+ currently being maintained for backward compatibility, but it will
+ change in the future to better conform to the RFC.
+
+ :param offer: (``str``) media type offer
+ :return: (``bool``) Whether ``offer`` is acceptable according to the
+ header.
+
+ For this class, either there is no ``Accept`` header in the request, or
+ the header is invalid, so any media type is acceptable, and this always
+ returns ``True``.
+ """
+ warnings.warn(
+ 'The behavior of .__contains__ for the Accept classes is '
+ 'currently being maintained for backward compatibility, but it '
+ 'will change in the future to better conform to the RFC.',
+ DeprecationWarning,
+ )
+ return True
+
+ def __iter__(self):
+ """
+ Return all the ranges with non-0 qvalues, in order of preference.
+
+ .. warning::
+
+ The behavior of this method is currently maintained for backward
+ compatibility, but will change in the future.
+
+ :return: iterator of all the media ranges in the header with non-0
+ qvalues, in descending order of qvalue. If two ranges have the
+ same qvalue, they are returned in the order of their positions
+ in the header, from left to right.
+
+ When there is no ``Accept`` header in the request or the header is
+ invalid, there are no media ranges, so this always returns an empty
+ iterator.
+ """
+ warnings.warn(
+ 'The behavior of AcceptValidHeader.__iter__ is currently '
+ 'maintained for backward compatibility, but will change in the '
+ 'future.',
+ DeprecationWarning,
+ )
+ return iter(())
+
+ def accept_html(self):
+ """
+ Return ``True`` if any HTML-like type is accepted.
+
+ The HTML-like types are 'text/html', 'application/xhtml+xml',
+ 'application/xml' and 'text/xml'.
+
+ When the header is invalid, or there is no `Accept` header in the
+ request, all `offers` are considered acceptable, so this always returns
+ ``True``.
+ """
+ return bool(
+ self.acceptable_offers(
+ offers=[
+ 'text/html',
+ 'application/xhtml+xml',
+ 'application/xml',
+ 'text/xml',
+ ],
+ )
+ )
+ accepts_html = property(fget=accept_html, doc=accept_html.__doc__)
+ # note the plural
+
+ def acceptable_offers(self, offers):
+ """
+ Return the offers that are acceptable according to the header.
+
+ :param offers: ``iterable`` of ``str`` media types (media types can
+ include media type parameters)
+ :return: When the header is invalid, or there is no ``Accept`` header
+ in the request, all `offers` are considered acceptable, so
+ this method returns a list of (media type, qvalue) tuples
+ where each offer in `offers` is paired with the qvalue of 1.0,
+ in the same order as in `offers`.
+ """
+ return [(offer, 1.0) for offer in offers]
+
+ def best_match(self, offers, default_match=None):
+ """
+ Return the best match from the sequence of language tag `offers`.
+
+ This is the ``.best_match()`` method for when the header is invalid or
+ not found in the request, corresponding to
+ :meth:`AcceptValidHeader.best_match`.
+
+ .. warning::
+
+ This is currently maintained for backward compatibility, and will be
+ deprecated in the future (see the documentation for
+ :meth:`AcceptValidHeader.best_match`).
+
+ When the header is invalid, or there is no `Accept` header in the
+ request, all `offers` are considered acceptable, so the best match is
+ the media type in `offers` with the highest server quality value (if
+ the server quality value is not supplied for a media type, it is 1).
+
+ If more than one media type in `offers` have the same highest server
+ quality value, then the one that shows up first in `offers` is the best
+ match.
+
+ :param offers: (iterable)
+
+ | Each item in the iterable may be a ``str`` media type,
+ or a (media type, server quality value) ``tuple`` or
+ ``list``. (The two may be mixed in the iterable.)
+
+ :param default_match: (optional, any type) the value to be returned if
+ `offers` is empty.
+
+ :return: (``str``, or the type of `default_match`)
+
+ | The offer that has the highest server quality value. If
+ `offers` is empty, the value of `default_match` is returned.
+ """
+ warnings.warn(
+ 'The behavior of .best_match for the Accept classes is currently '
+ 'being maintained for backward compatibility, but the method will'
+ ' be deprecated in the future, as its behavior is not specified '
+ 'in (and currently does not conform to) RFC 7231.',
+ DeprecationWarning,
+ )
+ best_quality = -1
+ best_offer = default_match
+ for offer in offers:
+ if isinstance(offer, (list, tuple)):
+ offer, quality = offer
+ else:
+ quality = 1
+ if quality > best_quality:
+ best_offer = offer
+ best_quality = quality
+ return best_offer
+
+ def quality(self, offer):
+ """
+ Return quality value of given offer, or ``None`` if there is no match.
+
+ This is the ``.quality()`` method for when the header is invalid or not
+ found in the request, corresponding to
+ :meth:`AcceptValidHeader.quality`.
+
+ .. warning::
+
+ This is currently maintained for backward compatibility, and will be
+ deprecated in the future (see the documentation for
+ :meth:`AcceptValidHeader.quality`).
+
+ :param offer: (``str``) media type offer
+ :return: (``float``) ``1.0``.
+
+ When the ``Accept`` header is invalid or not in the request, all offers
+ are equally acceptable, so 1.0 is always returned.
+ """
+ warnings.warn(
+ 'The behavior of .quality for the Accept classes is currently '
+ 'being maintained for backward compatibility, but the method will'
+ ' be deprecated in the future, as its behavior does not conform to'
+ 'RFC 7231.',
+ DeprecationWarning,
+ )
+ return 1.0
+
+
class NilAccept(object):
"""
Represents a generic ``Accept-*`` style header when it is not present in