Coverage for src/paperap/exceptions.py: 91%
43 statements
« prev ^ index » next coverage.py v7.6.12, created at 2025-03-18 12:26 -0400
« prev ^ index » next coverage.py v7.6.12, created at 2025-03-18 12:26 -0400
1"""
2----------------------------------------------------------------------------
4 METADATA:
6 File: exceptions.py
7 Project: paperap
8 Created: 2025-03-04
9 Version: 0.0.7
10 Author: Jess Mann
11 Email: jess@jmann.me
12 Copyright (c) 2025 Jess Mann
14----------------------------------------------------------------------------
16 LAST MODIFIED:
18 2025-03-04 By Jess Mann
20"""
22from __future__ import annotations
24from string import Template
26import pydantic
29class PaperlessError(Exception):
30 """Base exception for all paperless client errors."""
33class ModelValidationError(PaperlessError, ValueError):
34 """Raised when a model fails validation."""
36 def __init__(self, message: str | None = None, model: pydantic.BaseModel | None = None) -> None:
37 if not message:
38 message = f"Model failed validation for {model.__class__.__name__}."
39 super().__init__(message)
42class ConfigurationError(PaperlessError):
43 """Raised when the configuration is invalid."""
46class APIError(PaperlessError):
47 """Raised when the API returns an error."""
49 status_code: int | None = None
51 def __init__(self, message: str | None = None, status_code: int | None = None) -> None:
52 self.status_code = status_code
53 if not message:
54 message = "An error occurred."
55 message = f"API Error {status_code}: {message}"
56 message = Template(message).safe_substitute(status_code=status_code)
57 super().__init__(message)
60class AuthenticationError(APIError):
61 """Raised when authentication fails."""
64class InsufficientPermissionError(APIError):
65 """Raised when a user does not have permission to perform an action."""
68class FeatureNotAvailableError(APIError):
69 """Raised when a feature is not available."""
72class FilterDisabledError(FeatureNotAvailableError):
73 """Raised when a filter is not available."""
76class RequestError(APIError):
77 """Raised when an error occurs while making a request."""
80class BadResponseError(APIError):
81 """Raised when a response is returned, but the status code is not 200."""
84class ResponseParsingError(APIError):
85 """Raised when the response can't be parsed."""
88class ResourceNotFoundError(APIError):
89 """Raised when a requested resource is not found."""
91 resource_name: str | None = None
93 def __init__(self, message: str | None = None, resource_name: str | None = None) -> None:
94 self.resource_name = resource_name
95 if not message:
96 message = "Resource ${resource} not found."
97 message = Template(message).safe_substitute(resource=resource_name)
98 super().__init__(message, 404)
101class ObjectNotFoundError(ResourceNotFoundError):
102 """Raised when a requested object is not found."""
104 model_id: int | None = None
106 def __init__(
107 self, message: str | None = None, resource_name: str | None = None, model_id: int | None = None
108 ) -> None:
109 self.model_id = model_id
110 if not message:
111 message = "Resource ${resource} (#${pk}) not found."
112 message = Template(message).safe_substitute(resource=resource_name, pk=model_id)
113 super().__init__(message, resource_name)
116class MultipleObjectsFoundError(APIError):
117 """Raised when multiple objects are found when only one was expected."""