Coverage for src/paperap/exceptions.py: 92%

1"""

2----------------------------------------------------------------------------

3

4 METADATA:

5

6 File: exceptions.py

7 Project: paperap

8 Created: 2025-03-04

9 Version: 0.0.5

10 Author: Jess Mann

11 Email: jess@jmann.me

12 Copyright (c) 2025 Jess Mann

13

14----------------------------------------------------------------------------

15

16 LAST MODIFIED:

17

18 2025-03-04 By Jess Mann

19

20"""

21

22 from __future__ import annotations

23

24 from string import Template

25

26

27 class PaperlessError(Exception):

28 """Base exception for all paperless client errors."""

29

30

31 class ConfigurationError(PaperlessError):

32 """Raised when the configuration is invalid."""

33

34

35 class APIError(PaperlessError):

36 """Raised when the API returns an error."""

37

38 status_code: int | None = None

39

40 def __init__(self, message: str | None = None, status_code: int | None = None) -> None:

41 self.status_code = status_code

42 if not message:

43 message = "An error occurred."

44 message = f"API Error {status_code}: {message}"

45 message = Template(message).safe_substitute(status_code=status_code)

46 super().__init__(message)

47

48

49 class AuthenticationError(APIError):

50 """Raised when authentication fails."""

51

52

53 class InsufficientPermissionError(APIError):

54 """Raised when a user does not have permission to perform an action."""

55

56

57 class FeatureNotAvailableError(APIError):

58 """Raised when a feature is not available."""

59

60

61 class FilterDisabledError(FeatureNotAvailableError):

62 """Raised when a filter is not available."""

63

64

65 class RequestError(APIError):

66 """Raised when an error occurs while making a request."""

67

68

69 class BadResponseError(APIError):

70 """Raised when a response is returned, but the status code is not 200."""

71

72

73 class ResponseParsingError(APIError):

74 """Raised when the response can't be parsed."""

75

76

77 class ResourceNotFoundError(APIError):

78 """Raised when a requested resource is not found."""

79

80 resource_name: str | None = None

81

82 def __init__(self, message: str | None = None, resource_name: str | None = None) -> None:

83 self.resource_name = resource_name

84 if not message:

85 message = "Resource ${resource} not found."

86 message = Template(message).safe_substitute(resource=resource_name)

87 super().__init__(message, 404)

88

89

90 class ObjectNotFoundError(ResourceNotFoundError):

91 """Raised when a requested object is not found."""

92

93 model_id: int | None = None

94

95 def __init__(

96 self, message: str | None = None, resource_name: str | None = None, model_id: int | None = None

97 ) -> None:

98 self.model_id = model_id

99 if not message:

100 message = "Resource ${resource} (#${pk}) not found."

101 message = Template(message).safe_substitute(resource=resource_name, pk=model_id)

102 super().__init__(message, resource_name)

103

104

105 class MultipleObjectsFoundError(APIError):

106 """Raised when multiple objects are found when only one was expected."""