Coverage for src/mactime/errors.py: 100%
53 statements
« prev ^ index » next coverage.py v7.6.12, created at 2025-02-24 19:31 +0100
« prev ^ index » next coverage.py v7.6.12, created at 2025-02-24 19:31 +0100
1from __future__ import annotations
3import ctypes
4import errno
5import os
6from typing import Optional, Type, ClassVar
9class MacTimeError(Exception):
10 """Base exception class for mactime errors."""
12 exit_code: ClassVar[int] = 1
15class ArgumentsError(MacTimeError, ValueError):
16 exit_code = 2
19class NotEnoughArgumentsError(MacTimeError, ValueError):
20 exit_code = 22
23class FSOperationError(MacTimeError, OSError):
24 """Base class for file operation errors."""
26 _registry: ClassVar[dict[int, Type[FSOperationError]]] = {}
27 error_codes: ClassVar[set[int]] = set()
28 error_message: ClassVar[str] = "Unknown error"
29 exit_code: ClassVar[int] = 22
31 def __init__(
32 self,
33 path: str,
34 operation: str,
35 errno: int,
36 message: str | None = None,
37 ):
38 self.path = path
39 self.operation = operation
40 self.errno = errno
41 self.message = message or self.error_message
42 super().__init__(f"{operation} on {path!r}: {self.message} (errno {errno!r})")
44 def __init_subclass__(cls) -> None:
45 super().__init_subclass__()
46 for code in cls.error_codes:
47 FSOperationError._registry[code] = cls
49 @classmethod
50 def check_call(cls, ret: int, path: str | os.PathLike, operation: str) -> None:
51 if ret == 0:
52 return
54 err = ctypes.get_errno()
55 specific_error = cls._registry.get(err, FSOperationError)
56 raise specific_error(path, operation, err)
59class PathNotFoundError(FSOperationError):
60 error_codes = {errno.ENOENT}
61 error_message = "Path not found"
62 exit_code = 2
65class FSPermissionError(FSOperationError):
66 error_codes = {errno.EACCES, errno.EPERM}
67 error_message = "Permission denied"
68 exit_code = 13
71class InvalidAttributeError(FSOperationError):
72 error_codes = {errno.EINVAL}
73 error_message = "Invalid attribute or operation"
74 exit_code = 22
77class UnsupportedOperationError(FSOperationError):
78 error_codes = {errno.ENOTSUP}
79 error_message = "Operation not supported"
80 exit_code = 45
83class FileIOError(FSOperationError):
84 error_codes = {errno.EIO}
85 error_message = "I/O error occurred"
86 exit_code = 5