Пример #1
0
def validation_exception_handler(request: Request,
                                 exc: ValidationError) -> JSONAPIResponse:
    """Handle a general pydantic validation error

    The pydantic `ValidationError` usually contains a list of errors,
    this function extracts them and wraps them in the OPTIMADE specific error resource.

    Parameters:
        request: The HTTP request resulting in the exception being raised.
        exc: The exception being raised.

    Returns:
        A JSON HTTP response through [`general_exception()`][optimade.server.exception_handlers.general_exception].

    """
    status = 500
    title = "ValidationError"
    errors = set()
    for error in exc.errors():
        pointer = "/" + "/".join([str(_) for _ in error["loc"]])
        source = ErrorSource(pointer=pointer)
        code = error["type"]
        detail = error["msg"]
        errors.add(
            OptimadeError(detail=detail,
                          status=status,
                          title=title,
                          source=source,
                          code=code))
    return general_exception(request,
                             exc,
                             status_code=status,
                             errors=list(errors))
Пример #2
0
 async def catch_validation_error(
         self, exception: ValidationError
 ) -> typing.Union[Response, typing.Tuple]:
     """
     Used to handle request parsing errors
     """
     return {"error": exception.errors()}, 400
Пример #3
0
def _add_validations_errors(err: ValidationError,
                            errors: list[APIError]) -> list[APIError]:
    _error = errors[0]
    _error.code = 'invalid_request_validation'
    errors = []
    for error in err.errors():
        errors.append(
            APIError(
                **{
                    **_error.dict(),
                    'id':
                    Id.generate().value(),
                    'title':
                    error['msg'],
                    'detail':
                    dumps({
                        'field': list(error['loc'])[1:],
                        'message': f'{error["msg"]}: {error["type"]}',
                    }).decode('utf-8'),
                    'source': {
                        'pointer': error['loc'][0]
                    },
                    'meta': {
                        'error_correlation_id': _error.id
                    },
                }))
    return errors
Пример #4
0
 def _is_failed_due_to_extra_field(exc: pydantic.ValidationError):
     inner_errors = exc.errors()
     return (len(inner_errors) == 1
             and inner_errors[0]['type'] == 'value_error.extra'
             and len(inner_errors[0]['loc']) ==
             1  # Require the extra field to be on the top level
             )
Пример #5
0
def get_formatted_error_message(
        validation_error: pydantic.ValidationError,
        error_message_prefix: Optional[bool] = True) -> str:
    """
    Return formatted message about validation errors.

    :param validation_error: error that was raised on validation
    :type validation_error: pydantic.ValidationError
    :param error_message_prefix: `Incorrect input!` prefix on the start is included by
    :type error_message_prefix: Optional[bool]

    :return: formatted, user readable message
    :rtype: str
    """

    error_messages = ['💿 Please, correct your input:'
                      ] if error_message_prefix else []

    for error in validation_error.errors():
        error_location: str = error['loc'][0]  # ruined attr name
        error_message: str = error['msg']

        formatted_error_location = ' '.join(
            error_location.split('_')).capitalize()
        formatted_error_message = f'{formatted_error_location}: {error_message}'

        error_messages.append(formatted_error_message)

    message = '\n'.join(error_messages)

    return message
Пример #6
0
    def error_handler(
        cls,
        json_data: dict,
        validation_error: ValidationError,
        id_key: str,
        items_key: str,
    ) -> dict:
        bad_data_ids = []

        errors_data = []

        if json_data[
                "data"]:  # нам могут отправить пустой список (вообще не могу, но пусть будет)
            for error in validation_error.errors():
                errors_data.append({
                    "location": error["loc"],
                    "msg": error["msg"],
                    "type": error["type"],
                })
                element_number = error["loc"][1]
                element_id = json_data["data"][element_number][id_key]

                if element_id not in bad_data_ids:
                    bad_data_ids.append(element_id)

        response_bad_data = {
            "validation_error": {
                items_key: [{
                    "id": element_id
                } for element_id in bad_data_ids],
                "errors_data": errors_data,
            }
        }

        return response_bad_data
Пример #7
0
def simplify_validation_error(e: ValidationError):
    """Validation errors are long and messy. Return a simplified version

    Because we do so much overloading, ValidationErrors thrown by parse_raw can cover between 2 and 5+
    fields/schemas, explaining how the model wouldn't fit each one individually. The client probably
    doesn't want to sit through parsing that kind of error, so we work to return a simplified version.

    TODO: This is a quick and dirty function. Come up with something a bit more comprehensive and 'better'.
    """

    pattern_err_set: Set[_PatternError] = set()
    other_err_set: Set[_OtherError] = set()
    for err in e.errors():
        em = _ErrorModel(**err)
        pm = _try_pattern_error_from(em)
        if pm:
            pattern_err_set.add(pm)
            continue
        other_err_set.add(_other_error_from(em))

    pattern_err_strings = list("\t'%s': '%s'" % (p_em.loc, p_em.regex)
                               for p_em in pattern_err_set)
    other_err_strings = list("\t%s(%s): '%s'" % (o_em.type, o_em.loc, o_em.msg)
                             for o_em in other_err_set)

    msg = "Message failed validation."
    if pattern_err_strings:
        msg += "\n  'Regex' type failures: {\n%s\n}" % (
            ",\n".join(pattern_err_strings), )
    if other_err_strings:
        msg += "\n  'Other' type failures: {\n%s\n}" % (
            ",\n".join(other_err_strings), )
    return msg
Пример #8
0
def handle_validation_error(error: ValidationError) -> Response:
    """Convert a ValidationError from parsing JSON input to a error response."""
    response = jsonify({
        "reason": "validation_failed",
        "errors": error.errors()
    })
    response.status_code = 400
    return cast(Response, response)
Пример #9
0
def convert_error(err: ValidationError) -> Error:
    errors = []
    for error in err.errors():
        if isinstance(error["loc"], tuple):
            name = ".".join([str(x) for x in error["loc"]])
        else:
            name = str(error["loc"])
        errors.append("%s: %s" % (name, error["msg"]))
    return Error(code=ErrorCode.INVALID_REQUEST, errors=errors)
Пример #10
0
async def validation_exception_handler(request: Request,
                                       exc: ValidationError) -> JSONResponse:
    return JSONResponse(status_code=HTTP_422_UNPROCESSABLE_ENTITY,
                        content={
                            "detail":
                            jsonable_encoder(exc.errors()),
                            "body":
                            jsonable_encoder(exc.body) if exc.body else None
                        })
Пример #11
0
async def validation_exception_handler(request: Request, exc: ValidationError):
    return JSONResponse(
        status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
        content=jsonable_encoder({
            "code": "30012",
            "detail": exc.errors(),
            "message": ERR_MSG["30012"],
            "response_id": request.state.request_tag
        }),
    )
Пример #12
0
async def validation_error_handler(request: Request, e: ValidationError):
    return JSONResponse(
        status_code=400,
        content={
            'message': '数据格式非法',
            'name': 'ValidationError',
            'code': 4000,
            'detail': e.errors(),
        },
    )
Пример #13
0
 def __init__(self, e: ValidationError, message: str = 'Validation Error'):
     payload = dict({
         'message':
         'validation errors',
         'errors': [{
             'field': error['loc'][0],
             'message': error['msg']
         } for error in e.errors()]
     })
     super().__init__(message=message, payload=payload)
Пример #14
0
def error_list_from_pydantic_error(error: ValidationError) -> list[Error]:
    res = []
    for err in error.errors():
        res.append(
            Error(
                path=err['loc'],
                type=err['type'],
                context=err.get('ctx'),
            ))

    return res
Пример #15
0
def format_errors(error: ValidationError) -> dict:
    """Structure pydantic validation errors into a dict."""
    return {
        'msgType':
        'Errors',
        'errors': [{
            'loc': err['loc'],
            'msg': err['msg'],
            'type': err['type'],
        } for err in error.errors()]
    }
Пример #16
0
def invalid_params_from_validation_error(exc: ValidationError) -> InvalidParams:
    errors = []

    for err in exc.errors():
        if err['loc'][:1] == ('body', ):
            err['loc'] = err['loc'][1:]
        else:
            assert err['loc']
            err['loc'] = (f"<{err['loc'][0]}>", ) + err['loc'][1:]
        errors.append(err)

    return InvalidParams(data={'errors': errors})
Пример #17
0
def transform_to_json_api_errors(validation_error: ValidationError) -> dict:
    def transform_error(error):
        return {
            'detail': error.get('msg'),
            'title': error.get('type'),
            'source': {
                'pointer': '/' + '/'.join(error['loc']),
            },
        }

    error_response = ErrorResponse(
        errors=[transform_error(error) for error in validation_error.errors()])
    return filter_none(error_response.dict())
Пример #18
0
    def from_validation_error(cls, validation_error: pydantic.ValidationError):
        errors = validation_error.errors()
        payload = {}

        for error in errors:
            field = error["loc"][0]
            message = error["msg"]
            error_type = error["type"]

            errors = payload.setdefault(field, [])
            errors.append(FieldError(message=message, type=error_type))

        return cls(errors=type_(**payload))
Пример #19
0
def _raise_formatted_validation_error(err: pydantic.ValidationError):
    error_list = err.errors()
    if len(error_list) != 1:
        return

    error = error_list[0]
    loc = error.get("loc")
    msg = error.get("msg")

    if not (loc and msg) or not isinstance(loc, tuple):
        return

    varname = ".".join((x for x in loc if isinstance(x, str)))
    raise errors.SnapcraftError(f"error setting {varname}: {msg}")
Пример #20
0
    async def on_validation_error(
        self, exception: ValidationError, context: CONTEXT
    ) -> StreamResponse:
        """
        This method is a hook to intercept ValidationError.

        This hook can be redefined to return a custom HTTP response error.
        The exception is a pydantic.ValidationError and the context is "body",
        "headers", "path" or "query string"
        """
        errors = exception.errors()
        for error in errors:
            error["in"] = context

        return json_response(data=errors, status=400)
Пример #21
0
def validation_exception_handler(request: Request, exc: ValidationError):
    status = 500
    title = "ValidationError"
    errors = set()
    for error in exc.errors():
        pointer = "/" + "/".join([str(_) for _ in error["loc"]])
        source = ErrorSource(pointer=pointer)
        code = error["type"]
        detail = error["msg"]
        errors.add(
            OptimadeError(
                detail=detail, status=status, title=title, source=source, code=code
            )
        )
    return general_exception(request, exc, status_code=status, errors=list(errors))
Пример #22
0
def transform_validation_error_to_json_api_errors(
        status_code: int, exception: ValidationError) -> ErrorResponse:
    """
    Object marshalling for validation errors.  format pydantic validation
    errors to expected json:api response shape.
    """
    def transform_error(error):
        return Error(
            status=str(status_code),
            detail=error.get('msg'),
            source=ErrorSource(pointer='/' +
                               '/'.join(str(node) for node in error['loc'])),
            title=error.get('type'))

    return ErrorResponse(
        errors=[transform_error(error) for error in exception.errors()])
Пример #23
0
 def error_handler(
     cls,
     validation_error: ValidationError,
 ):
     errors_data = []
     for error in validation_error.errors():
         errors_data.append({
             "location": error["loc"],
             "msg": error["msg"],
             "type": error["type"],
         })
     response_bad_data = {
         "validation_error": {
             "errors_data": errors_data,
         }
     }
     return response_bad_data
Пример #24
0
def get_formatted_error_message(
        validation_error: pydantic.ValidationError) -> str:
    """
    Return formatted message about validation errors.

    :param validation_error: error that was raised on validation
    :type validation_error: pydantic.ValidationError

    :return: formatted, user readable message
    :rtype: str
    """

    message = '\n'.join([
        f"{error['loc'][0]:<10} - {error['msg']}"
        for error in validation_error.errors()
    ])

    return message
Пример #25
0
def validation_exception_handler(request: Request, exc: ValidationError):
    from optimade.models import Error, ErrorSource

    status = 500
    title = "ValidationError"
    errors = []
    for error in exc.errors():
        pointer = "/" + "/".join([str(_) for _ in error["loc"]])
        source = ErrorSource(pointer=pointer)
        code = error["type"]
        detail = error["msg"]
        errors.append(
            Error(detail=detail,
                  status=status,
                  title=title,
                  source=source,
                  code=code))
    return general_exception(request, exc, status_code=status, errors=errors)
Пример #26
0
def format_validation_error(prefix: str, exc: ValidationError) -> str:
    errors = [
        (
            prefix
            + "".join(
                json.dumps([item]) for item in error["loc"] if item != "__root__"
            ),
            error["msg"]
            if error["msg"][0].isupper()
            else error["msg"][0].capitalize() + error["msg"][1:],
        )
        for error in exc.errors()
    ]
    width = max(len(loc) for loc, _ in errors) + 1
    return "\n".join(
        "{loc:<{width}} => {msg}".format(
            loc=loc,
            width=width,
            msg=msg + "." * (not msg.endswith(".")),
        )
        for loc, msg in errors
    )
Пример #27
0
async def validation_exception_handler(request: Request, exc: ValidationError):
    return JSONResponse(status_code=400, content=exc.errors())
Пример #28
0
 def __init__(self, error: ValidationError):
     super().__init__(
         status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
         detail=jsonable_encoder(error.errors()),
     )
Пример #29
0
def unpack_error_details(error: ValidationError) -> str:
    return error.errors()
Пример #30
0
def invalid_request_from_validation_error(exc: ValidationError) -> InvalidRequest:
    return InvalidRequest(data={'errors': exc.errors()})