Accept header choose() function removed and replaced by a more versatile match().
This commit is contained in:
parent
b8ae4285a4
commit
ec25581262
|
@ -112,6 +112,18 @@ class MediaType:
|
||||||
return cls(type_.lstrip(), subtype.rstrip(), **params)
|
return cls(type_.lstrip(), subtype.rstrip(), **params)
|
||||||
|
|
||||||
|
|
||||||
|
class Matched(str):
|
||||||
|
"""A matching result of a MIME string against a MediaType."""
|
||||||
|
def __new__(cls, mime: str, m: Optional[MediaType]):
|
||||||
|
return super().__new__(cls, mime)
|
||||||
|
|
||||||
|
def __init__(self, mime: str, m: Optional[MediaType]):
|
||||||
|
self.m = m
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return f"<{self} matched {self.m}>" if self else "<no match>"
|
||||||
|
|
||||||
|
|
||||||
class AcceptList(list):
|
class AcceptList(list):
|
||||||
"""A list of media types, as used in the Accept header.
|
"""A list of media types, as used in the Accept header.
|
||||||
|
|
||||||
|
@ -119,58 +131,40 @@ class AcceptList(list):
|
||||||
with the most preferred. This class is a list of `MediaType` objects,
|
with the most preferred. This class is a list of `MediaType` objects,
|
||||||
that encapsulate also the q value or any other parameters.
|
that encapsulate also the q value or any other parameters.
|
||||||
|
|
||||||
Three separate methods are provided for searching the list, for
|
Two separate methods are provided for searching the list:
|
||||||
different use cases. The first two match wildcards with anything,
|
- 'match' for finding the most preferred match (wildcards supported)
|
||||||
while `in` and other operators handle wildcards as literal values.
|
- operator 'in' for checking explicit matches (wildcards as literals)
|
||||||
|
|
||||||
- `choose` for choosing one of its arguments to use in response.
|
|
||||||
- 'match' for the best MediaType of the accept header, or None.
|
|
||||||
- operator 'in' for checking explicit matches (wildcards as is).
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def match(self, *media_types: List[str]) -> Optional[MediaType]:
|
def match(self, *mimes: List[str]) -> Matched:
|
||||||
"""Find a media type accepted by the client.
|
"""Find a media type accepted by the client.
|
||||||
|
|
||||||
This method can be used to find which of the media types requested by
|
This method can be used to find which of the media types requested by
|
||||||
the client is most preferred while matching any of the arguments.
|
the client is most preferred against the ones given as arguments.
|
||||||
|
|
||||||
Wildcards are supported. Most clients include */* as the last item in
|
The ordering of preference is set by:
|
||||||
their Accept header, so this method will always return a match unless
|
1. The q values on the Accept header, and those being equal,
|
||||||
a custom header is used, but it may return a more specific match if
|
2. The order of the arguments (first is most preferred), and
|
||||||
the client has requested any suitable types explicitly.
|
3. The first matching entry on the Accept header.
|
||||||
|
|
||||||
@param media_types: Any type/subtype strings to find.
|
Wildcards are matched both ways. A match is usually found, as the
|
||||||
@return A matching `MediaType` or `None` if nothing matches.
|
Accept headers typically include `*/*`, in particular if the header
|
||||||
|
is missing, is not manually set, or if the client is a browser.
|
||||||
|
|
||||||
|
Note: the returned object behaves as a string of the mime argument
|
||||||
|
that matched, and is empty/falsy if no match was found. The matched
|
||||||
|
header entry `MediaType` or `None` is available as the `m` attribute.
|
||||||
|
|
||||||
|
@param mimes: Any MIME types to search for in order of preference.
|
||||||
|
@return A match object with the mime string and the MediaType object.
|
||||||
"""
|
"""
|
||||||
for accepted in self:
|
l = sorted([
|
||||||
if any(accepted.match(mt) for mt in media_types):
|
(-acc.q, i, j, mime, acc) # Sort by -q, i, j
|
||||||
return accepted
|
for j, acc in enumerate(self)
|
||||||
|
for i, mime in enumerate(mimes)
|
||||||
|
if acc.match(mime)
|
||||||
def choose(self, *media_types: List[str], omit_wildcard=True) -> str:
|
])
|
||||||
"""Choose a most suitable media type based on the Accept header.
|
return Matched(*(l[0][3:] if l else ("", None)))
|
||||||
|
|
||||||
This is the recommended way to choose a response format based on the
|
|
||||||
Accept header. The q values and the order of the Accept header are
|
|
||||||
respected, and if due to wildcards multiple arguments match the same
|
|
||||||
accept header entry, the first one matching is returned.
|
|
||||||
|
|
||||||
Should none of the arguments be acceptable, the first argument is
|
|
||||||
returned with the q value of 0.0 (i.e. the lowest possible).
|
|
||||||
|
|
||||||
@param media_types: Any type/subtype strings to find.
|
|
||||||
@param omit_wildcard: Ignore full wildcard */* in the Accept header.
|
|
||||||
@return A tuple of one of the arguments and the q value of the match.
|
|
||||||
"""
|
|
||||||
# Find the preferred MediaType if any match
|
|
||||||
for accepted in self:
|
|
||||||
if omit_wildcard and accepted.is_wildcard:
|
|
||||||
continue
|
|
||||||
for mt in media_types:
|
|
||||||
if accepted.match(mt):
|
|
||||||
return mt, accepted.q
|
|
||||||
# Fall back to the first argument
|
|
||||||
return media_types[0], 0.0
|
|
||||||
|
|
||||||
|
|
||||||
def parse_accept(accept: str) -> AcceptList:
|
def parse_accept(accept: str) -> AcceptList:
|
||||||
|
|
Loading…
Reference in New Issue
Block a user