errortools 1.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ # Nothing here!
@@ -0,0 +1,9 @@
1
+ __author__: str = "Evan Yang"
2
+ __author_email__: str = "quantbit@126.com"
3
+ __copyright__: str = "Copyright 2026 (C) aiwonderland Evan Yang"
4
+ __description__: str = (
5
+ "errortools - a toolset for working with Python exceptions and warnings"
6
+ )
7
+ __license__: str = "MIT"
8
+ __title__: str = "errortools"
9
+ __url__: str = "https://github.com/more-abc/errortools"
_errortools/_types.py ADDED
@@ -0,0 +1,21 @@
1
+ import sys
2
+ import types
3
+
4
+ # Acquire the internal interpreter types for traceback objects and frame objects.
5
+
6
+ # This module uses a raised exception to safely obtain the runtime types
7
+ # of traceback and frame objects, for compatibility with older Python versions
8
+ # where these types are not easily importable from the types module.
9
+ if sys.version_info >= (3, 7):
10
+ # No docstrings are provided for standard library versions.
11
+ TracebackType = types.TracebackType
12
+ FrameType = types.FrameType
13
+ else:
14
+ try:
15
+ raise TypeError
16
+ except TypeError as exc:
17
+ TracebackType = type(exc.__traceback__)
18
+ """The type of traceback objects returned by exception.__traceback__."""
19
+
20
+ FrameType = type(exc.__traceback__.tb_frame) # type: ignore
21
+ """The type of frame objects representing an execution frame in the call stack."""
@@ -0,0 +1,7 @@
1
+ __version__: str = "1.0.0"
2
+ __version_tuple__: tuple[int, int, int] = (1, 0, 0)
3
+ __commit_id__: str | None = None
4
+
5
+ version = __version__
6
+ version_tuple = __version_tuple__
7
+ commit_id = __commit_id__
_errortools/abc.py ADDED
@@ -0,0 +1,333 @@
1
+ from typing import Any, Literal, Union
2
+ from abc import ABC, abstractmethod
3
+
4
+ from .tools.error_msg import (
5
+ ErrorAttrableRaiseNotImplementedErrorMessage as ErrorAttrNotImplementedMsg,
6
+ )
7
+ from .methods import (
8
+ ErrorAttrMixin,
9
+ ErrorAttrCheckMixin,
10
+ ErrorAttrDeletionMixin,
11
+ ErrorSetAttrMixin,
12
+ )
13
+ from .classes.errorcodes import (
14
+ BaseErrorCodes,
15
+ NotFoundError,
16
+ AccessDeniedError,
17
+ InvalidInputError,
18
+ ConfigurationError,
19
+ RuntimeFailure,
20
+ TimeoutFailure,
21
+ )
22
+ from .classes.warn import (
23
+ BaseWarning,
24
+ DeprecatedWarning,
25
+ PerformanceWarning,
26
+ ConfigurationWarning,
27
+ ResourceUsageWarning,
28
+ RuntimeBehaviourWarning,
29
+ )
30
+
31
+
32
+ def _check_methods(C: type[Any], *methods: str) -> Union[bool, Literal[NotImplemented]]: # type: ignore
33
+ """Check methods in `C`. If has, return `True`, else `NotImplemented`.
34
+ from `_collections_abc.py`.
35
+ Copyright 2007 Google, Inc. All Rights Reserved.
36
+ Licensed to PSF under a Contributor Agreement.
37
+ """
38
+ mro: tuple[type[Any], ...] = C.__mro__
39
+ for method in methods:
40
+ for B in mro:
41
+ if method in B.__dict__:
42
+ if B.__dict__[method] is None:
43
+ return NotImplemented
44
+ break
45
+ else:
46
+ return NotImplemented
47
+ return True
48
+
49
+
50
+ class ErrorAttrable(ABC):
51
+ """
52
+ Abstract Base Class (ABC) for classes supporting custom attribute error handling.
53
+
54
+ This class follows the design pattern of `collections.abc` (e.g., Iterable, Mapping):
55
+ - Uses `__subclasshook__` + `_check_methods` to validate subclass compliance
56
+ - Enforces implementation of attribute error handling methods via abstract methods
57
+ - Implements native attribute magic methods to forward errors to custom handlers
58
+
59
+ Core behavior:
60
+ When attribute operations (get/delete/check/set) fail, the corresponding native
61
+ magic methods automatically invoke custom error handling methods implemented by subclasses.
62
+ """
63
+
64
+ __slots__ = ()
65
+
66
+ @classmethod
67
+ def __subclasshook__(cls, C: type[Any]) -> Union[bool, Literal[NotImplemented]]: # type: ignore
68
+ """
69
+ Check if a class is a subclass of ErrorAttrable (per `collections.abc` style).
70
+
71
+ This method enables `issubclass()` to recognize classes that implement the core
72
+ __errorattr__ method (base requirement), matching the behavior of standard ABCs.
73
+
74
+ Args:
75
+ C: The class to check for compliance with ErrorAttrable interface
76
+
77
+ Returns:
78
+ True if C implements __errorattr__, NotImplemented otherwise
79
+ """
80
+ if cls is ErrorAttrable:
81
+ return _check_methods(C, "__errorattr__")
82
+ return NotImplemented
83
+
84
+ def __getattr__(self, name: str) -> Any:
85
+ """
86
+ Native magic method: Automatically invoked for missing attribute access.
87
+
88
+ Forwards the attribute lookup failure to the custom `__errorattr__` method.
89
+ """
90
+ return self.__errorattr__(name)
91
+
92
+ @abstractmethod
93
+ def __errorattr__(self, name: str) -> Any:
94
+ """
95
+ Abstract method for custom missing attribute handling (MUST be implemented).
96
+
97
+ Args:
98
+ name: Name of the missing attribute being accessed
99
+
100
+ Raises:
101
+ NotImplementedError: If not overridden
102
+ AttributeError: Recommended error type for missing attributes
103
+ """
104
+ raise NotImplementedError(ErrorAttrNotImplementedMsg)
105
+
106
+ def __delattr__(self, name: str) -> None:
107
+ """
108
+ Native magic method: Automatically invoked for attribute deletion errors.
109
+
110
+ Forwards to __errordelattr__ if implemented, else raises standard error.
111
+ """
112
+ if hasattr(self, "__errordelattr__"):
113
+ self.__errordelattr__(name)
114
+ else:
115
+ super().__delattr__(name)
116
+
117
+ def __errordelattr__(self, name: str) -> None:
118
+ """
119
+ Custom handler for attribute deletion errors (OPTIONAL to implement).
120
+
121
+ Args:
122
+ name: Name of the attribute being deleted
123
+ """
124
+ raise NotImplementedError(ErrorAttrNotImplementedMsg)
125
+
126
+ def __contains__(self, name: str) -> bool:
127
+ """
128
+ Alternative to __hasattr__: Check if attribute exists (customizable).
129
+
130
+ Forwards to __errorhasattr__ if implemented, else uses standard check.
131
+ """
132
+ if hasattr(self, "__errorhasattr__"):
133
+ return self.__errorhasattr__(name)
134
+ else:
135
+ return hasattr(super(), name)
136
+
137
+ def __errorhasattr__(self, name: str) -> bool:
138
+ """
139
+ Custom handler for attribute existence checks (OPTIONAL to implement).
140
+
141
+ Args:
142
+ name: Name of the attribute to check
143
+
144
+ Returns:
145
+ bool: True if attribute exists (custom logic), False otherwise
146
+ """
147
+ raise NotImplementedError(ErrorAttrNotImplementedMsg)
148
+
149
+ def __setattr__(self, name: str, value: Any) -> None:
150
+ """
151
+ Native magic method: Automatically invoked for attribute setting errors.
152
+
153
+ Forwards to __errorsetattr__ if implemented, else uses standard setting.
154
+ """
155
+ if hasattr(self, "__errorsetattr__"):
156
+ self.__errorsetattr__(name, value)
157
+ else:
158
+ super().__setattr__(name, value)
159
+
160
+ def __errorsetattr__(self, name: str, value: Any) -> None:
161
+ """
162
+ Custom handler for attribute setting errors (OPTIONAL to implement).
163
+
164
+ Args:
165
+ name: Name of the attribute to set
166
+ value: Value to assign to the attribute
167
+ """
168
+ raise NotImplementedError(ErrorAttrNotImplementedMsg)
169
+
170
+
171
+ # register four Mixin's
172
+ ErrorAttrable.register(ErrorAttrMixin)
173
+ ErrorAttrable.register(ErrorAttrDeletionMixin)
174
+ ErrorAttrable.register(ErrorAttrCheckMixin)
175
+ ErrorAttrable.register(ErrorSetAttrMixin)
176
+
177
+
178
+ # ----------------------------------------------------------------------
179
+ # ErrorCodeable
180
+ # ----------------------------------------------------------------------
181
+
182
+
183
+ class ErrorCodeable(ABC):
184
+ """Abstract Base Class for exceptions that carry a machine-readable error code.
185
+
186
+ Follows the ``collections.abc`` pattern: any class that exposes both a
187
+ ``code`` class attribute (``int``) and a ``default_detail`` class attribute
188
+ (``str``) is recognised as a virtual subclass automatically, without
189
+ explicit inheritance.
190
+
191
+ Concrete subclasses **must** implement:
192
+ - ``code`` — integer error code (class variable)
193
+ - ``default_detail`` — fallback human-readable message (class variable)
194
+
195
+ Example:
196
+
197
+ >>> class PaymentError(ErrorCodeable, Exception):
198
+ ... code = 6001
199
+ ... default_detail = "Payment failed."
200
+ >>> issubclass(PaymentError, ErrorCodeable)
201
+ True
202
+ """
203
+
204
+ __slots__ = ()
205
+
206
+ @classmethod
207
+ def __subclasshook__(cls, C: type[Any]) -> Union[bool, Literal[NotImplemented]]: # type: ignore
208
+ """Recognise any class that defines ``code`` and ``default_detail``."""
209
+ if cls is ErrorCodeable:
210
+ return _check_methods(C, "code", "default_detail")
211
+ return NotImplemented
212
+
213
+ @property
214
+ @abstractmethod
215
+ def code(self) -> int:
216
+ """Integer error code identifying this exception type."""
217
+ pass
218
+
219
+ @property
220
+ @abstractmethod
221
+ def default_detail(self) -> str:
222
+ """Fallback human-readable message used when no detail is provided."""
223
+ pass
224
+
225
+
226
+ # ----------------------------------------------------------------------
227
+ # Warnable
228
+ # ----------------------------------------------------------------------
229
+
230
+
231
+ class Warnable(ABC):
232
+ """Abstract Base Class for warning classes that can emit themselves.
233
+
234
+ Any class that exposes an ``emit`` classmethod is recognised as a
235
+ virtual subclass automatically via ``__subclasshook__``.
236
+
237
+ Concrete subclasses **must** implement:
238
+ - ``emit(cls, detail, stacklevel)`` — issue the warning via ``warnings.warn``
239
+
240
+ Example:
241
+
242
+ >>> class SlowWarning(Warnable, Warning):
243
+ ... default_detail = "This operation is slow."
244
+ ... @classmethod
245
+ ... def emit(cls, detail=None, stacklevel=2):
246
+ ... import warnings
247
+ ... warnings.warn(cls(detail), stacklevel=stacklevel)
248
+ >>> issubclass(SlowWarning, Warnable)
249
+ True
250
+ """
251
+
252
+ __slots__ = ()
253
+
254
+ @classmethod
255
+ def __subclasshook__(cls, C: type[Any]) -> Union[bool, Literal[NotImplemented]]: # type: ignore
256
+ """Recognise any class that defines an ``emit`` classmethod."""
257
+ if cls is Warnable:
258
+ return _check_methods(C, "emit")
259
+ return NotImplemented
260
+
261
+ @classmethod
262
+ @abstractmethod
263
+ def emit(cls, detail: str | None = None, stacklevel: int = 2) -> None:
264
+ """Issue this warning via ``warnings.warn``.
265
+
266
+ Args:
267
+ detail: Optional message override.
268
+ stacklevel: Passed to ``warnings.warn``; ``2`` points at the
269
+ caller of ``emit``.
270
+ """
271
+ pass
272
+
273
+
274
+ # ----------------------------------------------------------------------
275
+ # Raiseable
276
+ # ----------------------------------------------------------------------
277
+
278
+
279
+ class Raiseable(ABC):
280
+ """Abstract Base Class for objects that know how to raise themselves.
281
+
282
+ Concrete subclasses **must** implement ``raise_it()``, which should
283
+ raise ``self`` (or a derived exception). Any class that exposes a
284
+ ``raise_it`` method is recognised as a virtual subclass automatically.
285
+
286
+ Example:
287
+
288
+ >>> class MyError(Raiseable, Exception):
289
+ ... def raise_it(self):
290
+ ... raise self
291
+ >>> e = MyError("oops")
292
+ >>> e.raise_it()
293
+ Traceback (most recent call last):
294
+ ...
295
+ MyError: oops
296
+ """
297
+
298
+ __slots__ = ()
299
+
300
+ @classmethod
301
+ def __subclasshook__(cls, C: type[Any]) -> Union[bool, Literal[NotImplemented]]: # type: ignore
302
+ """Recognise any class that defines a ``raise_it`` method."""
303
+ if cls is Raiseable:
304
+ return _check_methods(C, "raise_it")
305
+ return NotImplemented
306
+
307
+ @abstractmethod
308
+ def raise_it(self) -> None:
309
+ """Raise this object as an exception.
310
+
311
+ Raises:
312
+ self: Or a derived exception wrapping this object.
313
+ """
314
+ pass
315
+
316
+
317
+ # ----------------------------------------------------------------------
318
+ # Register existing concrete classes as virtual subclasses
319
+ # ----------------------------------------------------------------------
320
+
321
+ ErrorCodeable.register(BaseErrorCodes)
322
+ ErrorCodeable.register(NotFoundError)
323
+ ErrorCodeable.register(AccessDeniedError)
324
+ ErrorCodeable.register(InvalidInputError)
325
+ ErrorCodeable.register(ConfigurationError)
326
+ ErrorCodeable.register(RuntimeFailure)
327
+ ErrorCodeable.register(TimeoutFailure)
328
+ Warnable.register(BaseWarning)
329
+ Warnable.register(DeprecatedWarning)
330
+ Warnable.register(PerformanceWarning)
331
+ Warnable.register(ConfigurationWarning)
332
+ Warnable.register(ResourceUsageWarning)
333
+ Warnable.register(RuntimeBehaviourWarning)
@@ -0,0 +1 @@
1
+ """Cache tools in `errortools`."""
@@ -0,0 +1,82 @@
1
+ """A helper tool for caching exceptions raised by functions, like lru_cache."""
2
+
3
+ import functools
4
+ from typing import (
5
+ Callable,
6
+ Any,
7
+ Optional,
8
+ TypeVar,
9
+ overload,
10
+ )
11
+
12
+ from _errortools.cached.wrapper import ErrorCacheWrapper
13
+
14
+ _T = TypeVar("_T", bound=Callable[..., Any])
15
+
16
+ # fmt: off
17
+
18
+
19
+ @overload
20
+ def error_cache(func: _T) -> ErrorCacheWrapper[_T]:
21
+ ...
22
+
23
+
24
+ @overload
25
+ def error_cache(maxsize: Optional[int] = 128) -> Callable[[_T], ErrorCacheWrapper[_T]]:
26
+ ...
27
+ # fmt: on
28
+
29
+
30
+ def error_cache( # type: ignore
31
+ func: Optional[_T] = None, maxsize: Optional[int] = 128
32
+ ) -> Any:
33
+ """
34
+ Decorator to cache exceptions raised by a function (like functools.lru_cache).
35
+
36
+ This decorator automatically caches exceptions thrown by the wrapped function,
37
+ keyed by the function's arguments. If the function succeeds, the cached exception
38
+ (if any) for those arguments is removed.
39
+
40
+ Key features (aligned with lru_cache):
41
+ - maxsize: Maximum number of cached errors (None = unlimited, default=128)
42
+ - LRU eviction: Evicts least recently used entries when maxsize is reached
43
+ - cache_info(): Returns hits/misses/maxsize/currsize stats
44
+ - clear_cache(): Clears cache and resets statistics
45
+
46
+ Usage (same as lru_cache):
47
+
48
+ @error_cache # Default maxsize=128
49
+ def risky_func(x: int) -> int: ...
50
+
51
+ @error_cache(maxsize=32) # Custom maxsize
52
+ def risky_func(x: int) -> int: ...
53
+
54
+ @error_cache(maxsize=None) # Unlimited cache
55
+ def risky_func(x: int) -> int: ...
56
+
57
+ @error_cache() # Explicit empty args (maxsize=128)
58
+ def risky_func(x: int) -> int: ...
59
+
60
+ Args:
61
+ func: The function to wrap (auto-passed when using @error_cache without args).
62
+ maxsize: Maximum number of cached errors (None = unlimited, default=128).
63
+
64
+ Returns:
65
+ Wrapped function with error caching functionality.
66
+
67
+ Raises:
68
+ TypeError: If non-hashable arguments are passed (same as lru_cache).
69
+ """
70
+
71
+ def decorator(f: _T) -> ErrorCacheWrapper[_T]:
72
+ if not callable(f):
73
+ raise TypeError(f"Expected a callable, got {type(f).__name__} instead")
74
+
75
+ wrapper = ErrorCacheWrapper(f, maxsize=maxsize)
76
+ functools.update_wrapper(wrapper, f)
77
+ return wrapper
78
+
79
+ # Handle both @error_cache and @error_cache(...) usage
80
+ if func is None:
81
+ return decorator
82
+ return decorator(func)
@@ -0,0 +1,76 @@
1
+ from collections import OrderedDict
2
+ from collections.abc import Hashable, Callable
3
+ from typing import Any, Generic, TypeVar, Optional, TypeAlias
4
+
5
+ _T = TypeVar("_T", bound=Callable[..., Any])
6
+ _Key: TypeAlias = tuple[
7
+ str, tuple[Hashable, ...], tuple[tuple[Hashable, Hashable], ...]
8
+ ]
9
+
10
+
11
+ class ErrorCacheWrapper(Generic[_T]):
12
+ """Wrapper class for error-cached functions (mimics lru_cache's wrapper style)."""
13
+
14
+ def __init__(self, func: _T, maxsize: Optional[int] = 128) -> None:
15
+ self.__wrapped__ = func # Required for inspect module compatibility
16
+ self._func_name = func.__name__
17
+
18
+ # LRU cache with maxsize support (OrderedDict preserves access order)
19
+ self._maxsize = maxsize if (maxsize is None or maxsize > 0) else None
20
+ self._cache: OrderedDict[_Key, Exception] = OrderedDict()
21
+
22
+ # Cache statistics (1:1 with lru_cache)
23
+ self._hits = 0
24
+ self._misses = 0
25
+
26
+ def __call__(self, *args: Hashable, **kwargs: Hashable) -> Any:
27
+ """Execute the wrapped function and cache exceptions if raised (with LRU)."""
28
+ cache_key = self._make_key(args, kwargs)
29
+
30
+ try:
31
+ result = self.__wrapped__(*args, **kwargs)
32
+ except Exception as exc:
33
+ # Cache exception and enforce LRU eviction
34
+ self._cache[cache_key] = exc
35
+ self._misses += 1
36
+
37
+ # Evict least recently used if maxsize is exceeded
38
+ if self._maxsize is not None and len(self._cache) > self._maxsize:
39
+ self._cache.popitem(last=False) # FIFO = LRU for insert order
40
+ raise
41
+ else:
42
+ # Auto-clear cache for successful calls
43
+ self._cache.pop(cache_key, None)
44
+ return result
45
+
46
+ def _make_key(
47
+ self, args: tuple[Hashable, ...], kwargs: dict[str, Hashable]
48
+ ) -> _Key:
49
+ """Generate a unique hashable key (consistent with lru_cache's logic)."""
50
+ sorted_kwargs = tuple(sorted(kwargs.items()))
51
+ return (self._func_name, args, sorted_kwargs)
52
+
53
+ # ---------------------- Cache control methods (like lru_cache) ----------------------
54
+ def get_cached_error(
55
+ self, *args: Hashable, **kwargs: Hashable
56
+ ) -> Optional[Exception]:
57
+ """Get the cached exception for the given arguments (if exists)."""
58
+ cache_key = self._make_key(args, kwargs)
59
+ if cache_key in self._cache:
60
+ self._hits += 1
61
+ self._cache.move_to_end(cache_key) # Update LRU order (most recent)
62
+ return self._cache[cache_key]
63
+ return None
64
+
65
+ def clear_cache(self) -> None:
66
+ """Clear all cached exceptions and reset statistics (mimics lru_cache.clear)."""
67
+ self._cache.clear()
68
+ self._hits = 0
69
+ self._misses = 0
70
+
71
+ def cache_info(self) -> str:
72
+ """Return cache statistics (1:1 with lru_cache.cache_info)."""
73
+ return (
74
+ f"ErrorCacheInfo(hits={self._hits}, misses={self._misses}, "
75
+ f"maxsize={self._maxsize}, currsize={len(self._cache)})"
76
+ )
@@ -0,0 +1 @@
1
+ """Base classes."""
@@ -0,0 +1,148 @@
1
+ """Base exception classes with general-purpose error code support."""
2
+
3
+ from .base.base import ErrorToolsBaseException
4
+
5
+ __all__ = [
6
+ "BaseErrorCodes",
7
+ "InvalidInputError",
8
+ "NotFoundError",
9
+ "AccessDeniedError",
10
+ "ConfigurationError",
11
+ "RuntimeFailure",
12
+ "TimeoutFailure",
13
+ ]
14
+
15
+
16
+ class BaseErrorCodes(ErrorToolsBaseException):
17
+ """A base exception with class-level error code and default detail.
18
+
19
+ Subclass and override `code` and `default_detail` to define
20
+ domain-specific exceptions with stable, machine-readable codes. The
21
+ ``detail`` passed at raise-time overrides the class default.
22
+
23
+ Error code ranges (by convention):
24
+
25
+ - ``1xxx`` — input / validation
26
+ - ``2xxx`` — access / permission
27
+ - ``3xxx`` — resource lookup
28
+ - ``4xxx`` — runtime / execution
29
+ - ``5xxx`` — configuration / setup
30
+ - ``-1`` — unspecified
31
+
32
+ Attributes:
33
+ code: Integer error code for this exception class. Defaults to ``-1``.
34
+ default_detail: Fallback message used when no *detail* is supplied.
35
+
36
+ Example:
37
+ >>> class PaymentError(BaseErrorCodes):
38
+ ... code = 6001
39
+ ... default_detail = "Payment processing failed."
40
+ >>> raise PaymentError()
41
+ Traceback (most recent call last):
42
+ ...
43
+ PaymentError: [6001] Payment processing failed.
44
+ >>> raise PaymentError("card declined")
45
+ Traceback (most recent call last):
46
+ ...
47
+ PaymentError: [6001] card declined
48
+ """
49
+
50
+ code: int = -1
51
+ default_detail: str = "An error occurred."
52
+
53
+ def __init__(self, detail: str | None = None) -> None:
54
+ """Initialise the exception with an optional detail message.
55
+
56
+ Args:
57
+ detail: Human-readable description of the error. Falls back to
58
+ `default_detail` when ``None``.
59
+ """
60
+ self.detail = detail if detail is not None else self.default_detail
61
+ super().__init__(self.detail)
62
+
63
+ def __str__(self) -> str:
64
+ return f"[{self.code}] {self.detail}"
65
+
66
+ def __repr__(self) -> str:
67
+ return f"{type(self).__name__}(detail={self.detail!r}, code={self.code!r})"
68
+
69
+ # ------------------------------------------------------------------
70
+ # Factory classmethods
71
+ # ------------------------------------------------------------------
72
+
73
+ @classmethod
74
+ def invalid_input(cls, detail: str | None = None) -> InvalidInputError:
75
+ """Return an `InvalidInputError` (1001) instance."""
76
+ return InvalidInputError(detail)
77
+
78
+ @classmethod
79
+ def not_found(cls, detail: str | None = None) -> NotFoundError:
80
+ """Return a `NotFoundError` (3001) instance."""
81
+ return NotFoundError(detail)
82
+
83
+ @classmethod
84
+ def access_denied(cls, detail: str | None = None) -> AccessDeniedError:
85
+ """Return an `AccessDeniedError` (2001) instance."""
86
+ return AccessDeniedError(detail)
87
+
88
+ @classmethod
89
+ def configuration_error(cls, detail: str | None = None) -> ConfigurationError:
90
+ """Return a `ConfigurationError` (5001) instance."""
91
+ return ConfigurationError(detail)
92
+
93
+ @classmethod
94
+ def runtime_failure(cls, detail: str | None = None) -> RuntimeFailure:
95
+ """Return a `RuntimeFailure` (4001) instance."""
96
+ return RuntimeFailure(detail)
97
+
98
+ @classmethod
99
+ def timeout_failure(cls, detail: str | None = None) -> TimeoutFailure:
100
+ """Return a `TimeoutFailure` (4002) instance."""
101
+ return TimeoutFailure(detail)
102
+
103
+
104
+ # ----------------------------------------------------------------------
105
+ # Predefined subclasses — general application categories
106
+ # ----------------------------------------------------------------------
107
+
108
+
109
+ class InvalidInputError(BaseErrorCodes):
110
+ """1001 — Input failed validation or is of the wrong type/format."""
111
+
112
+ code = 1001
113
+ default_detail = "Invalid input."
114
+
115
+
116
+ class AccessDeniedError(BaseErrorCodes):
117
+ """2001 — The caller lacks permission to perform the requested action."""
118
+
119
+ code = 2001
120
+ default_detail = "Access denied."
121
+
122
+
123
+ class NotFoundError(BaseErrorCodes):
124
+ """3001 — The requested resource or item could not be located."""
125
+
126
+ code = 3001
127
+ default_detail = "Resource not found."
128
+
129
+
130
+ class RuntimeFailure(BaseErrorCodes):
131
+ """4001 — An unexpected failure occurred during execution."""
132
+
133
+ code = 4001
134
+ default_detail = "Runtime failure."
135
+
136
+
137
+ class TimeoutFailure(BaseErrorCodes):
138
+ """4002 — An operation exceeded its allowed time limit."""
139
+
140
+ code = 4002
141
+ default_detail = "Operation timed out."
142
+
143
+
144
+ class ConfigurationError(BaseErrorCodes):
145
+ """5001 — The application is misconfigured or missing required settings."""
146
+
147
+ code = 5001
148
+ default_detail = "Configuration error."