Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Flask - custom decorator breaks the routing

I have the following Flask routes and a custom helper:

from spots import app, db
from flask import Response
import simplejson as json


def json_response(action_func):
    def create_json_response(*args, **kwargs):
        ret = action_func(*args, **kwargs)
        code = 200
        if len(ret) == 2:
            code = ret[0]
            resp = ret[1]
        else:
            resp = ret[0]
        return Response(
            response=json.dumps(resp, indent=4),
            status=code,
            content_type='application/json'
        )

    return create_json_response


@app.route('/test')
@json_response
def test():
    return 400, dict(result="Test success")


@app.route('/')
@json_response
def home():
    return 200, dict(result="Home success")

I would expect a GET request to /test to return something like {"result":"Test success"} but that is not the case. Instead, any request seems to match the last route, i.e. home. Why?

I wonder if this is caused by some lack of insulation between the different calls to json_response?

Thanks in advance.

like image 740
phidah Avatar asked Jun 16 '12 14:06

phidah


1 Answers

As Видул Петров said the solution is to use functools.wraps:

import functools
def json_response(action_func):
    @functools.wraps(action_func)
    def create_json_response(*args, **kwargs):
        ...
return create_json_response

The reason is that Flask’s routing system maps URLs to "endpoints", and then endpoints to view functions. The endpoint defaults to the __name__ attribute of the view function. In this case the decorated function was passed to app.route so the endpoint was create_json_response for both rules and the last view defined for that endpoint was used in both cases.

functools.wraps takes the __name__ (and other attributes) from the original function and fixes this. It is always a good idea to use it in decorated wrappers.

like image 73
Simon Sapin Avatar answered Oct 29 '22 15:10

Simon Sapin