"""
----------------------------------------------------------------------------
METADATA:
File: exceptions.py
Project: paperap
Created: 2025-03-04
Version: 0.0.8
Author: Jess Mann
Email: jess@jmann.me
Copyright (c) 2025 Jess Mann
----------------------------------------------------------------------------
LAST MODIFIED:
2025-03-04 By Jess Mann
"""
from __future__ import annotations
from string import Template
import pydantic
[docs]
class PaperapError(Exception):
"""Base exception for all paperless client errors."""
[docs]
class ModelValidationError(PaperapError, ValueError):
"""Raised when a model fails validation."""
[docs]
def __init__(self, message: str | None = None, model: pydantic.BaseModel | None = None) -> None:
if not message:
message = f"Model failed validation for {model.__class__.__name__}."
super().__init__(message)
[docs]
class ReadOnlyFieldError(ModelValidationError):
"""Raised when a read-only field is set."""
[docs]
class ConfigurationError(PaperapError):
"""Raised when the configuration is invalid."""
[docs]
class PaperlessError(PaperapError):
"""Raised due to a feature or error of paperless ngx"""
[docs]
class APIError(PaperlessError):
"""Raised when the API returns an error."""
status_code: int | None = None
[docs]
def __init__(self, message: str | None = None, status_code: int | None = None) -> None:
self.status_code = status_code
if not message:
message = "An error occurred."
message = f"API Error {status_code}: {message}"
message = Template(message).safe_substitute(status_code=status_code)
super().__init__(message)
[docs]
class AuthenticationError(APIError):
"""Raised when authentication fails."""
[docs]
class InsufficientPermissionError(APIError):
"""Raised when a user does not have permission to perform an action."""
[docs]
class FeatureNotAvailableError(APIError):
"""Raised when a feature is not available."""
[docs]
class FilterDisabledError(FeatureNotAvailableError):
"""Raised when a filter is not available."""
[docs]
class RequestError(APIError):
"""Raised when an error occurs while making a request."""
[docs]
class BadResponseError(APIError):
"""Raised when a response is returned, but the status code is not 200."""
[docs]
class ResponseParsingError(APIError):
"""Raised when the response can't be parsed."""
[docs]
class ResourceNotFoundError(APIError):
"""Raised when a requested resource is not found."""
resource_name: str | None = None
[docs]
def __init__(self, message: str | None = None, resource_name: str | None = None) -> None:
self.resource_name = resource_name
if not message:
message = "Resource ${resource} not found."
message = Template(message).safe_substitute(resource=resource_name)
super().__init__(message, 404)
[docs]
class RelationshipNotFoundError(ResourceNotFoundError):
"""Raised when a requested relationship is not found."""
[docs]
class ObjectNotFoundError(ResourceNotFoundError):
"""Raised when a requested object is not found."""
model_id: int | None = None
[docs]
def __init__(self, message: str | None = None, resource_name: str | None = None, model_id: int | None = None) -> None:
self.model_id = model_id
if not message:
message = "Resource ${resource} (#${pk}) not found."
message = Template(message).safe_substitute(resource=resource_name, pk=model_id)
super().__init__(message, resource_name)
[docs]
class MultipleObjectsFoundError(APIError):
"""Raised when multiple objects are found when only one was expected."""
[docs]
class DocumentError(PaperapError):
"""Raised when an error occurs with a local document."""
[docs]
class NoImagesError(DocumentError):
"""Raised when no images are found in a pdf."""
[docs]
class DocumentParsingError(DocumentError):
"""Raised when a document cannot be parsed."""