nrp_cmd.errors

Errors raised from invenio repository.

 1#
 2# Copyright (C) 2024 CESNET z.s.p.o.
 3#
 4# invenio-nrp is free software; you can redistribute it and/or
 5# modify it under the terms of the MIT License; see LICENSE file for more
 6# details.
 7#
 8"""Errors raised from invenio repository."""
 9
10import json
11from typing import Any
12
13
14class RepositoryError(Exception):
15    """Base class for all repository errors."""
16
17    pass
18
19
20class RepositoryCommunicationError(RepositoryError):
21    """Base class for all repository communication errors."""
22
23
24class RepositoryNetworkError(RepositoryCommunicationError):
25    """Raised when a network error occurs."""
26
27
28class RepositoryJSONError(RepositoryCommunicationError):
29    """Raised from a repository when an error occurs."""
30
31    def __init__(self, request_info: Any, response: dict[str, Any]):  # noqa ANN401
32        """Initialize the error."""
33        self._request_info = request_info
34        self._response = response
35
36    @property
37    def request_info(self) -> Any:
38        """Return the request info."""
39        return self._request_info
40
41    @property
42    def json(self) -> dict[str, Any]:
43        """Return the JSON response."""
44        return self._response
45
46    def __repr__(self) -> str:
47        """Return the representation of the error."""
48        return f"{self._request_info.url} : {json.dumps(self.json)}"
49
50    def __str__(self) -> str:
51        """Return the string representation of the error."""
52        return self.__repr__()
53
54
55class RepositoryServerError(RepositoryJSONError):
56    """An error occurred on the server side (5xx http status code)."""
57
58
59class RepositoryClientError(RepositoryJSONError):
60    """An error occurred on the client side (4xx http status code).
61
62    This is usually not found, unauthorized, malformed request and similar.
63    """
64
65
66class UnstructureError(Exception):
67    pass
68
69
70class StructureError(Exception):
71    pass
72
73
74def is_instance_of_exceptions(
75    exception: Any, exceptions: tuple[type[Exception], ...] | type[Exception]
76) -> bool:  
77    # Check if the current exception is an instance of T
78    if isinstance(exception, exceptions):
79        return True
80
81    # Handle ExceptionGroup (Python 3.11+)
82    if isinstance(exception, BaseExceptionGroup):
83        sub_exception: Any
84        for sub_exception in exception.exceptions:  # type: ignore
85            if is_instance_of_exceptions(sub_exception, exceptions):
86                return True
87
88    # Check chained exceptions (__cause__ or __context__)
89    if exception.__cause__ is not None and is_instance_of_exceptions(
90        exception.__cause__, exceptions
91    ):
92        return True
93    if exception.__context__ is not None and is_instance_of_exceptions(
94        exception.__context__, exceptions
95    ):
96        return True
97
98    return False
class RepositoryError(builtins.Exception):
15class RepositoryError(Exception):
16    """Base class for all repository errors."""
17
18    pass

Base class for all repository errors.

class RepositoryCommunicationError(RepositoryError):
21class RepositoryCommunicationError(RepositoryError):
22    """Base class for all repository communication errors."""

Base class for all repository communication errors.

class RepositoryNetworkError(RepositoryCommunicationError):
25class RepositoryNetworkError(RepositoryCommunicationError):
26    """Raised when a network error occurs."""

Raised when a network error occurs.

class RepositoryJSONError(RepositoryCommunicationError):
29class RepositoryJSONError(RepositoryCommunicationError):
30    """Raised from a repository when an error occurs."""
31
32    def __init__(self, request_info: Any, response: dict[str, Any]):  # noqa ANN401
33        """Initialize the error."""
34        self._request_info = request_info
35        self._response = response
36
37    @property
38    def request_info(self) -> Any:
39        """Return the request info."""
40        return self._request_info
41
42    @property
43    def json(self) -> dict[str, Any]:
44        """Return the JSON response."""
45        return self._response
46
47    def __repr__(self) -> str:
48        """Return the representation of the error."""
49        return f"{self._request_info.url} : {json.dumps(self.json)}"
50
51    def __str__(self) -> str:
52        """Return the string representation of the error."""
53        return self.__repr__()

Raised from a repository when an error occurs.

RepositoryJSONError(request_info: Any, response: dict[str, typing.Any])
32    def __init__(self, request_info: Any, response: dict[str, Any]):  # noqa ANN401
33        """Initialize the error."""
34        self._request_info = request_info
35        self._response = response

Initialize the error.

request_info: Any
37    @property
38    def request_info(self) -> Any:
39        """Return the request info."""
40        return self._request_info

Return the request info.

json: dict[str, typing.Any]
42    @property
43    def json(self) -> dict[str, Any]:
44        """Return the JSON response."""
45        return self._response

Return the JSON response.

class RepositoryServerError(RepositoryJSONError):
56class RepositoryServerError(RepositoryJSONError):
57    """An error occurred on the server side (5xx http status code)."""

An error occurred on the server side (5xx http status code).

class RepositoryClientError(RepositoryJSONError):
60class RepositoryClientError(RepositoryJSONError):
61    """An error occurred on the client side (4xx http status code).
62
63    This is usually not found, unauthorized, malformed request and similar.
64    """

An error occurred on the client side (4xx http status code).

This is usually not found, unauthorized, malformed request and similar.

class UnstructureError(builtins.Exception):
67class UnstructureError(Exception):
68    pass

Common base class for all non-exit exceptions.

class StructureError(builtins.Exception):
71class StructureError(Exception):
72    pass

Common base class for all non-exit exceptions.

def is_instance_of_exceptions( exception: Any, exceptions: tuple[type[Exception], ...] | type[Exception]) -> bool:
75def is_instance_of_exceptions(
76    exception: Any, exceptions: tuple[type[Exception], ...] | type[Exception]
77) -> bool:  
78    # Check if the current exception is an instance of T
79    if isinstance(exception, exceptions):
80        return True
81
82    # Handle ExceptionGroup (Python 3.11+)
83    if isinstance(exception, BaseExceptionGroup):
84        sub_exception: Any
85        for sub_exception in exception.exceptions:  # type: ignore
86            if is_instance_of_exceptions(sub_exception, exceptions):
87                return True
88
89    # Check chained exceptions (__cause__ or __context__)
90    if exception.__cause__ is not None and is_instance_of_exceptions(
91        exception.__cause__, exceptions
92    ):
93        return True
94    if exception.__context__ is not None and is_instance_of_exceptions(
95        exception.__context__, exceptions
96    ):
97        return True
98
99    return False