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

Making Python decorators work with the Hug API framework

我是 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'  

您在

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

而且我认为装饰器一般不会起作用。 Hug通过function.__code__.co_varnames来标识必要的参数。这未被 functools.wraps 修改。使用装饰器后,hug.post 看到的是一个带有参数 *args, *kwargs 的函数,这没有帮助。

您可以将您的路由器链接到 ExceptionRouter

我有完全相同的需求。我找到了一种方法,尽管我不确定它是否理想。

  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)

测试 'assert' 显示 returned 内容是 'internal server error' 而不是默认的 'A server error occurred. Please contact the administrator.'

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