Skip to content

Instantly share code, notes, and snippets.

@pcostesi
Created August 15, 2012 03:43
Show Gist options
  • Save pcostesi/3355525 to your computer and use it in GitHub Desktop.
Save pcostesi/3355525 to your computer and use it in GitHub Desktop.
Flask view decorator to dispatch a request into different handlers by mimetypes.
@split
@login_required
def hello():
return render_template('hello.html')
@hello.for_mimetype("application/json")
@login_required
def hello():
return jsonify({"hello":"flask"})
@hello.wrap
def hello(result):
logging.info("got a result %s", result)
return result
from functools import update_wrapper
from flask import redirect, request, url_for
import types
class split(object):
DEFAULT_MIMETYPE = '*/*'
def __init__(self, view):
""" Default render view """
default = type(self).DEFAULT_MIMETYPE
self.__dispatch_to = {default: view, None: view}
self.__targets = [default]
update_wrapper(self, view)
def for_mimetype(self, mimetype):
def deco(f):
self.__dispatch_to[mimetype] = f
self.__targets = [mimetype] + self.__targets
return self
return deco
def wrap(self, func):
self._wrap = func
return self
def __get__(self, obj, type=None):
if obj is None:
return self
# Let `func' be the method we're decorating. Return
# `self' bound to `obj', so it gets called as func(obj, ...)
# The bound method does something like this:
# def f(*args, **kwargs):
# return self(obj, *args, **kwargs)
# using functools.partial(self, obj) also does the trick.
# If we weren't wrapping this method, then it would be called
# by the wrapping class as an object and NOT as a method, so it
# would omit the `obj' argument.
# Returning a function or a partial works because Python would
# wrap them as bound methods.
# Yeah, it's a mess.
return types.MethodType(self, obj, type)
def __call__(self, *args, **kwargs):
best_match = request.accept_mimetypes.best_match(self.__targets)
target = self.__dispatch_to[best_match]
if not target:
return redirect(url_for("404.html")), 404
result = target(*args, **kwargs)
if getattr(self, "_wrap", None) and callable(self._wrap):
return self._wrap(*args, **kwargs)
return result
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment