# -*- coding: utf-8 -*-
"""Views for handling Python exceptions.
Includes special views that catch the following:
    1. colander.Invalid
"""
import logging
import pprint
import colander
from pyramid.response import Response
from pyramid.view import view_config
@view_config(context=Exception)
[docs]def pyramid_error_view(exception, request):
    """Register a pyramid view to handle exceptions; i.e., log them and generate a Response.
    :param exception: exception to be handled
    :type exception: Exception (Python base exception type) (i.e., type of ``context``)
    :param request: the pyramid request that lead to the exception being raised.
    :type request: pyramid.request.Request
    :return: the pyramid response to be rendered
    :rtype: pyramid.response.Response
    """
    if "log" not in general_error.__dict__:
        general_error.log = logging.getLogger(__name__)
    # Log exception with traceback
    general_error.log.error(request)
    general_error.log.exception(exception)
    # Specialized handlers for certain exception types
    if issubclass(type(exception), colander.Invalid):
        return failed_colander_validation(exception, request)
    return general_error(exception, request)
 
[docs]def general_error(exception, request):
    """Catch any Python ``Exception``.
    :param exception: exception to be handled
    :type exception: Exception
    :param request: the pyramid request that lead to the exception being raised.
    :type request: pyramid.request.Request
    :return: the pyramid response to be rendered
    :rtype: pyramid.response.Response
    """
    status_int = 500
    body = '{0:d}: {1:s}\n{2:s}'.format(status_int, request.referrer, exception)
    response = Response(body=body, status_int=status_int)
    return response
 
[docs]def failed_colander_validation(exception, request):
    """Catch ``colander.Invalid`` and give an informative 500 response.
    :param exception: exception to be handled
    :type exception: colander.Invalid
    :param request: the pyramid request that lead to the exception being raised.
    :type request: pyramid.request.Request
    :return: the pyramid response to be rendered
    :rtype: pyramid.response.Response
    """
    status_int = 500
    body = '{0:d}: {1:s}\nFailed validation:\n{2:s}'.format(status_int, request.referrer, pprint.pformat(exception.asdict()))
    response = Response(body=body, status_int=status_int)
    return response