Source code for flask_negotiation.media_type
""":mod:`media_type`
====================
HTTP media type
"""
[docs]def parse_header(s):
"""Parses parameter header
"""
params = _parse_header_params(';'+s)
key = params.pop(0).lower()
pdict = {}
for param in params:
i = param.find('=')
if i >= 0:
name = param[:i].strip().lower()
value = param[i+1:].strip()
if len(value) >= 2 and value[0] == value[-1] == '"':
value = value[1:-1]
value = value.replace(r'\\', '\\').replace(r'\"', '"')
pdict[name] = value
return key, pdict
def _parse_header_params(s):
li = []
while s[:1] == ';':
s = s[1:]
end = s.find(';')
while end > 0 and s.count('"', 0, end) % 2:
# For quote
end = s.find(';', end+1)
end = end if end >= 0 else len(s)
li.append(s[:end].strip())
s = s[end:]
return li
[docs]class MediaType(object):
"""Abstracted media type class.
"""
def __init__(self, raw):
raw = raw or ''
self.raw = raw
self.media_type, self.params = parse_header(raw)
self.main_type, sep, self.sub_type = self.media_type.partition('/')
def __contains__(self, other):
for k, v in self.params.iteritems():
if k != 'q' and other.params.get(k, None) != v:
return False
if self.main_type == '*' and self.sub_type == '*':
return True
if self.sub_type == '*' and self.main_type == other.main_type:
return True
if self.main_type == '*' and self.sub_type == other.sub_type:
return True
return self == other
def __eq__(self, other):
if isinstance(other, basestring):
return unicode(self) == other
return (self.main_type == other.main_type and
self.sub_type == other.sub_type)
def __repr__(self):
return '<media type:' + str(self) + '>'
def __str__(self):
return unicode(self).encode('utf-8')
def __unicode__(self):
return u'; '.join([u'%s/%s' % (self.main_type, self.sub_type)] +
[u'%s=%s' % (k, v)
for k, v in self.params.iteritems()])
def __cmp__(self, other):
return cmp(float(self.quality),
float(other.quality))
@property
def quality(self):
q = self.params.get('q', None)
if q is None:
return 1.0
return float(q)
[docs]def acceptable_media_types(request):
"""Extract acceptable media types from request
"""
if 'accept' in request.headers:
li = [x.strip() for x in request.headers['accept'].split(',')]
else:
li = ['*/*']
li = li or ['*/*']
return sorted(map(MediaType, li), reverse=True)
[docs]def best_renderer(renderers, media_types):
"""Choose best renderer and media type
"""
choosen_items = []
for media_type in media_types:
for renderer in renderers:
choosen = renderer.choose_media_type(media_type)
if not choosen is None:
choosen_items.append((renderer, choosen, media_type))
if not choosen_items:
return None, None
def cmp_types(first, second):
renderer1, choosen1, media_type1 = first
renderer2, choosen2, media_type2 = second
if media_type1 == media_type2:
return cmp(renderers.index(renderer2), renderers.index(renderer1))
if media_type1.quality == media_type2.quality:
return cmp(media_types.index(media_type2),
media_types.index(media_type1))
return cmp(media_type1.quality, media_type2.quality)
return tuple(sorted(choosen_items, cmp=cmp_types)[-1][:2])
[docs]def choose_media_type(acceptables, media_types):
"""Choose best acceptable media type.
:param acceptables: list of media type acceptable
:param media_types: list of media type supported
:returns: best acceptable media type or :const:`None` if cannot handle.
"""
choosen = []
for acceptable in acceptables:
for media_type in media_types:
if acceptable in media_type:
choosen.append((acceptable, media_type))
if not choosen:
return None
def cmp_types(first, second):
acceptable1, media_type1 = first
acceptable2, media_type2 = second
if acceptable.quality == acceptable2.quality:
return cmp(acceptables.index(acceptable2),
acceptables.index(acceptable1))
return cmp(acceptable.quality, acceptable.quality)
return sorted(choosen, cmp=cmp_types)[-1][0]
[docs]def can_accept(acceptables, media_types):
"""Determines acceptablility.
:param acceptables: list of media type acceptable
:param media_types: list of media type supported
"""
return choose_media_type(acceptables, media_types) is not None