Пользовательский обработчик ошибок Flask неправильно обрабатывает зарегистрированный тип ошибки - PullRequest
0 голосов
/ 04 мая 2019

Я создал базовое приложение Flask и зарегистрировал собственный обработчик ошибок для определенного пользовательского типа исключения. Однако когда этот тип исключения генерируется и передается в стек, Flask не использует указанный пользовательский обработчик ошибок.

Я создал второй обработчик ошибок с базовым типом исключения, который успешно перехватывает ошибку. Присутствие базового обработчика исключений не влияет на способность настраиваемого обработчика ошибок отлавливать ошибки. Если базовый обработчик не присутствует, ошибка пузырится вплоть до страницы Flask 500 по умолчанию.

Я также сделал print(srv.error_handler_spec), и кажется, что обработчик ошибок успешно регистрируется.

Вот основная часть srv.py, точка входа для моего приложения Flask

from flask import Flask, request
from flask import jsonify

srv = Flask(__name__)

class APIError(Exception):
    def __init__(self, message, status_code=500):
        Exception.__init__(self)
        self.message = message
        self.status_code = status_code

    def log_error(self):
        logging.error(f"API error: {self.to_json()}")

    def to_dict(self):
        return {"message": self.message, "status_code": self.status_code}


@srv.errorhandler(Exception)
def exception_handler(e: Exception):
    response = jsonify(
        {"message": f"unhandled exception encountered", "status_code": 500}
    )
    logging.error(f"unhandled exception encountered. type: {e.__class__}")
    response.status_code = 500
    return response


@srv.errorhandler(APIError)
def api_error_handler(e: APIError):
    response = jsonify(e.to_dict())
    response.status_code = e.status_code
    return response


print(srv.error_handler_spec)


@srv.route("/", methods=["GET"])
def hello_world():
    return "hello world"


@srv.route("/error", methods=["GET"])
def error():
    raise APIError("generic error", status_code=400)

Это вывод журнала из Flask при скручивании /error

[32mapp_1      |[0m {None: {None: {<class 'Exception'>: <function exception_handler at 0x7f211b8a5598>, <class 'srv.APIError'>: <function api_error_handler at 0x7f211b8a5620>}}}
[32mapp_1      |[0m {None: {None: {<class 'Exception'>: <function exception_handler at 0x7f211b8a5e18>, <class '__main__.APIError'>: <function api_error_handler at 0x7f211b8a5ea0>}}}
[32mapp_1      |[0m  * Serving Flask app "srv" (lazy loading)
[32mapp_1      |[0m  * Environment: production
[32mapp_1      |[0m    WARNING: Do not use the development server in a production environment.
[32mapp_1      |[0m    Use a production WSGI server instead.
[32mapp_1      |[0m  * Debug mode: off
[32mapp_1      |[0m  * Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)
[32mapp_1      |[0m ERROR:root:unhandled exception encountered. type: <class 'srv.APIError'>
[32mapp_1      |[0m 172.27.0.5 - - [04/May/2019 06:52:47] "POST /api/user/create HTTP/1.1" 500 -
[32mapp_1      |[0m INFO:werkzeug:172.27.0.5 - - [04/May/2019 06:52:47] "POST /api/user/create HTTP/1.1" 500 -
[32mapp_1      |[0m 172.27.0.5 - - [04/May/2019 06:52:47] "GET /error HTTP/1.1" 400 -
[32mapp_1      |[0m INFO:werkzeug:172.27.0.5 - - [04/May/2019 06:52:47] "GET /error HTTP/1.1" 400 -

Как видно из строки журнала ERROR:root:unhandled exception encountered. type: <class 'srv.APIError'>, он использует общий обработчик Exception, а не пользовательский для APIError.

Ожидаемое поведение - вместо этого Flask вместо этого использует пользовательский обработчик ошибок и вообще не печатает ни одной строки журнала.

Для записи результаты из curl согласуются с общим обработчиком ошибок, возвращающим ответ. Это определенно не проблема с универсальным обработчиком, перекрывающим более специфический обработчик. (Хотя это также было бы ошибочным согласно документации Flask).

Что дает?

1 Ответ

0 голосов
/ 04 мая 2019

Я нашел обходной путь, который заключается в том, чтобы поместить определение APIError в отдельный файл Python и импортировать его в srv.py.

Причина, по которой он не работает, заключается в том, что isinstance() работает неправильно,Возникающее исключение имеет тип srv.APIError, но проверяется тип, к которому он относится: __main__.APIError, которые не относятся к этому типу.

Это не связано с дублированием типов из другого модуля, поскольку изменение ошибкиимя типа StupidError дает те же результаты.

Однако я до сих пор не знаю, почему это происходит.: /

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...