Content negotiation utilities for every web framework.
Nego Provides abstracted HTTP media type.
MediaType
class parses raw media type string and split it into main/sub
type.
>>> from nego import MediaType >>> MediaType('text/html') nego.MediaType('text/html') >>> MediaType('text/html').main_type 'text' >>> MediaType('text/html').sub_type 'html' >>> MediaType('application', 'json') nego.MediaType('application/json')
MediaType
class also parses parameters.
>>> MediaType('application/json; charset=utf-8') nego.MediaType('application/json; charset=utf-8') >>> MediaType('application/json; charset=utf-8').params {'charset': 'utf-8'} >>> MediaType('application', 'json', dict(charset='utf-8')) nego.MediaType('application/json; charset=utf-8') >>> MediaType('text/html; q=0.8').quality 0.8
You can use wildcard for media type.
>>> MediaType('text/html') in MediaType('text/*') True >>> MediaType('text/*') in MediaType('text/html') False >>> MediaType('text/html') in MediaType('text/html') True >>> MediaType('text/html') in MediaType('application/*') False >>> MediaType('text/*') in MediaType('*/*') True
Nego provides content negotiation by function nego.media_type.choose_acceptable_media_type.
>>> from nego.media_type import choose_acceptable_media_type >>> jpeg_type = MediaType('image/jpeg') >>> png_type = MediaType('image/png') >>> html_type = MediaType('text/html; q=0.9') >>> json_type = MediaType('application/json; q=0.8') >>> choose_acceptable_media_type( ... [png_type, jpeg_type], ... [MediaType('text/html'), MediaType('application/*'), ... MediaType('image/*')] ... ) nego.MediaType('image/png') >>> choose_acceptable_media_type( ... [json_type, html_type], ... [MediaType('text/html'), MediaType('application/*')] ... ) nego.MediaType('text/html; q=0.9')
Renderer renders a data into specific type of data. For example, you can make a renderer that renders a data into json like
import json from nego import Renderer class JSONRenderer(Renderer): __media_types__ = ['application/json'] def render(self, data): return json.dumps(data)
And also plain text renderer like
class TextRenderer(Renderer): __media_types__ = ['text/plain'] def render(self, data): return str(data)
Nego also provides content negotiation using renderer by function nego.renderer.best_renderer.
>>> json_renderer = JSONRenderer() >>> text_renderer = TextRenderer()) >>> renderers = [json_renderer, text_renderer] >>> accept = 'application/json;q=0.9, text/plain;q=0.7' >>> acceptable_types = acceptable_media_types(accept) >>> renderer, media_type = best_renderer(acceptable_types, renderers) >>> renderer json_renderer >>> media_type nego.MediaType('application/json') >>> renderer.render(dict(foo='bar')) '{"foo": "bar"}'
You can use Nego with tornado by making mixin.
class NegoMixin(object): renderers = [JSONRenderer(), TextRenderer()] def nego(self, obj): accept = self.request.headers.get('Accept', '*/*') acceptable_types = acceptable_media_types(accept) renderer, media_type = best_renderer(acceptable_types, renderers) body = renderer.render(obj) self.set_header('Content-Type', str(media_type)) self.write(body)