使Python装饰器与Hug API框架一起使用

时间:2017-03-11 15:43:54

标签: python python-3.x decorator python-decorators hug

我是Python的新手。我正在使用Hug构建一个简单的API。我正在尝试使用装饰器来处理所有未处理的异常,如下面的代码所示。但似乎我没有正确地在装饰器中传递Hug所需的输入。

auth.py

from functools import wraps

import hug
from falcon import HTTP_400, HTTP_500

import store
import validator
from user_entity import UserEntity


def _error(dict, response, status=HTTP_400):
    response.status = status
    return {'errors': dict}


def handle_exceptions(f):
    """Handle all non-handled exceptions."""
    @wraps(f)
    def decorated(*args, **kwargs):
        try:
            return f(*args, **kwargs)
        except Exception as e:
            return _error({'message': str(e)}, HTTP_500)
    return decorated


@hug.post('/')
@handle_exceptions
def create_user(username, password, response):
    """Validate and create a user in the database."""
    is_valid, vres = validator.validate_user(username, password)
    if not is_valid:
        return _error(
            {k: v for k, v in vres.items() if v is not None}, response)

    user = UserEntity(username=username, password=password)
    urn, usr = user.db_view()
    store.create_user(urn, usr)

    return user.public_view()

这是我得到的错误:

Traceback (most recent call last):  
  File "auth.py", line 23, in decorated  
    return f(*args, **kwargs)  
TypeError: create_user() missing 1 required positional argument: 'response'  

During handling of the above exception, another exception occurred: 

Traceback (most recent call last):  
  File   "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/wsgiref/handlers.py", line 137, in run  
    self.result = application(self.environ, self.start_response)  
  File "/Users/munjal/.virtualenvs/utl-identity-auth-server/lib/python3.6/site-packages/falcon/api.py", line 189, in __call__  
    responder(req, resp, **params)  
  File "/Users/munjal/.virtualenvs/utl-identity-auth-server/lib/python3.6/site-packages/hug/interface.py", line 651, in __call__  
    self.render_content(self.call_function(**input_parameters), request, response, **kwargs)  
  File "/Users/munjal/.virtualenvs/utl-identity-auth-server/lib/python3.6/site-packages/hug/interface.py", line 595, in call_function  
    return self.interface(**parameters)  
  File "/Users/munjal/.virtualenvs/utl-identity-auth-server/lib/python3.6/site-packages/hug/interface.py", line 117, in __call__  
    return __hug_internal_self._function(*args, **kwargs)  
  File "auth.py", line 25, in decorated  
    return _error({'message': str(e)}, HTTP_500)  
  File "auth.py", line 14, in _error  
    response.status = status  
AttributeError: 'str' object has no attribute 'status'  

2 个答案:

答案 0 :(得分:2)

您忘记了

中的response参数
return _error({'message': str(e)}, HTTP_500)

我不认为装饰师的工作原理。 Hug通过function.__code__.co_varnames识别必要的参数。 functools.wraps不会修改此内容。使用装饰器后,hug.post可以看到的是带参数*args, *kwargs的函数,这没有帮助。

您可以使用ExceptionRouter

链接路由器

答案 1 :(得分:0)

我有完全相同的需求。虽然我不确定它是否理想,但我找到了办法。

  def handle_exceptions(f):
     @wraps(f)
     def decorated(*args, response, **kwargs):
        try:
            return f(*args, response=response, **kwargs)
        except MyError as e:
            response.status = HTTP_400
            return {'errors': str(e)}
        except Exception as e:
            response.status = HTTP_500
            return {'errors': 'internal server error'}
     return decorated


  @hug.post('/login')
  def login(user_id: btext, user_email: btext, request, response):
      load_session_data(request, response)
      validate_user(user_id, user_email)
      assert 3 < 2
      update_session_data(request, response, user_id=user_id, user_email=user_email)

测试&#39;断言&#39;显示返回的内容为'internal server error',而不是默认的'A server error occurred. Please contact the administrator.'

wrapshug.decorators.wraps,而不是functools.wraps。后者将返回默认的'A server error occurred. Please contact the administrator.'