自定义Flask Decorator导致UnboundLocalError

时间:2018-04-27 14:41:27

标签: python-2.7 flask

我正在嘲笑开发环境的服务,并编写了一个自定义视图装饰器来检查授权令牌。在编写自定义装饰器时,我按照Flasks文档获取了类似的装饰器here。我遇到的问题是我现在得到一个UnboundLocalError。

Traceback (most recent call last):
  File "/Users/jgoodell/virtualenvs/mock-zoom-api/lib/python2.7/site-packages/flask/app.py", line 1997, in __call__
    return self.wsgi_app(environ, start_response)
  File "/Users/jgoodell/virtualenvs/mock-zoom-api/lib/python2.7/site-packages/flask/app.py", line 1985, in wsgi_app
    response = self.handle_exception(e)
  File "/Users/jgoodell/virtualenvs/mock-zoom-api/lib/python2.7/site-packages/flask/app.py", line 1540, in handle_exception
    reraise(exc_type, exc_value, tb)
  File "/Users/jgoodell/virtualenvs/mock-zoom-api/lib/python2.7/site-packages/flask/app.py", line 1982, in wsgi_app
    response = self.full_dispatch_request()
  File "/Users/jgoodell/virtualenvs/mock-zoom-api/lib/python2.7/site-packages/flask/app.py", line 1614, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "/Users/jgoodell/virtualenvs/mock-zoom-api/lib/python2.7/site-packages/flask/app.py", line 1517, in handle_user_exception
    reraise(exc_type, exc_value, tb)
  File "/Users/jgoodell/virtualenvs/mock-zoom-api/lib/python2.7/site-packages/flask/app.py", line 1612, in full_dispatch_request
    rv = self.dispatch_request()
  File "/Users/jgoodell/virtualenvs/mock-zoom-api/lib/python2.7/site-packages/flask/app.py", line 1598, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "/Users/jgoodell/code/python/mock-zoom-api/app.py", line 28, in decorated_function
    return f(*args, **kwargs)
  File "/Users/jgoodell/code/python/mock-zoom-api/app.py", line 35, in users
    if request.method == 'GET':
UnboundLocalError: local variable 'request' referenced before assignment

以下是错误引发的源代码。

from functools import wraps
import logging
import json

from flask import Flask
from flask import request
from flask import make_response

from mock_zoom_api.auth import check_token
from mock_zoom_api.auth import InvalidTokenError


app = Flask(__name__)

logging.basicConfig()
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)


def require_token(f):
    @wraps(f)
    def decorated_function(*args, **kwargs):
        logger.debug('%s', request.headers)
        try:
            token = request.headers['Authorization']
        except KeyError, InvalidTokenError:
            return make_response('Unauthorized', 401)
        return f(*args, **kwargs)
    return decorated_function


@app.route('/v2/users', methods=['GET', 'POST'])
@require_token
def users():
    if request.method == 'GET':
        json_dict = {
            "page_count": "integer",
            "page_number": "integer",
            "page_size": "integer",
            "total_records": "integer",
            "users": [
                {
                    "id": "string",
                    "first_name": "string",
                    "last_name": "string",
                    "email": "string",
                    "type": "integer",
                    "pmi": "string",
                    "timezone": "string",
                    "dept": "string",
                    "created_at": "string [date-time]",
                    "last_login_time": "string [date-time]",
                    "last_client_version": "string"
                    }
                ]
            }
        response = make_response(json.dumps(json_dict), 200)
        response.headers['Content Type'] = 'application/json'
    elif request.method == 'POST':
        response = make_response('Success', 201)
        response.headers['Content Type'] = 'text/plain'
    else:
        request = make_response('Method Not Allowed', 405)
        response.headers['Content Type'] = 'text/plain'
    return response

堆栈跟踪是明确的,从装饰器中可以预期将'request'传递给装饰的函数,如果我明确地传递'request',则错误消失。以下是重构的代码。

from functools import wraps
import logging
import json

from flask import Flask
from flask import request
from flask import make_response

from mock_zoom_api.auth import check_token
from mock_zoom_api.auth import InvalidTokenError


app = Flask(__name__)

logging.basicConfig()
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)


def require_token(f):
    @wraps(f)
    def decorated_function(*args, **kwargs):
        logger.debug('%s', request.headers)
        try:
            token = request.headers['Authorization']
        except KeyError, InvalidTokenError:
            return make_response('Unauthorized', 401)
        return f(request, *args, **kwargs)
    return decorated_function


@app.route('/v2/users', methods=['GET', 'POST'])
@require_token
def users(request):
    if request.method == 'GET':
        json_dict = {
            "page_count": "integer",
            "page_number": "integer",
            "page_size": "integer",
            "total_records": "integer",
            "users": [
                {
                    "id": "string",
                    "first_name": "string",
                    "last_name": "string",
                    "email": "string",
                    "type": "integer",
                    "pmi": "string",
                    "timezone": "string",
                    "dept": "string",
                    "created_at": "string [date-time]",
                    "last_login_time": "string [date-time]",
                    "last_client_version": "string"
                    }
                ]
            }
        response = make_response(json.dumps(json_dict), 200)
        response.headers['Content Type'] = 'application/json'
    elif request.method == 'POST':
        response = make_response('Success', 201)
        response.headers['Content Type'] = 'text/plain'
    else:
        request = make_response('Method Not Allowed', 405)
        response.headers['Content Type'] = 'text/plain'
    return response

以下是闻起来有趣的。为什么我必须从装饰器中将'request'传递给包装函数,但是我不必传递'json'?两者都在模块中导入并在我的视图中引用。但只有'request'会引发UnboundLocalError,而不是'json'。

以下是我的环境的版本信息。

(mock-zoom-api)[0]mock-zoom-api$ pip freeze
click==6.7
Flask==0.12.2
itsdangerous==0.24
Jinja2==2.10
MarkupSafe==1.0
Werkzeug==0.14.1
(mock-zoom-api)[0]mock-zoom-api$ python --version
Python 2.7.10

1 个答案:

答案 0 :(得分:0)

request会自动显示路由。变化:

def users(request):

def users():