errortools 2.4.0__tar.gz → 3.0.0__tar.gz
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.
- {errortools-2.4.0/errortools.egg-info → errortools-3.0.0}/PKG-INFO +16 -6
- {errortools-2.4.0 → errortools-3.0.0}/README.md +11 -4
- errortools-3.0.0/_errortools/_speedup.c +58 -0
- {errortools-2.4.0 → errortools-3.0.0}/_errortools/classes/abc.py +5 -148
- {errortools-2.4.0 → errortools-3.0.0}/_errortools/classes/group.py +41 -38
- {errortools-2.4.0 → errortools-3.0.0}/_errortools/decorator/deprecated.py +1 -1
- {errortools-2.4.0 → errortools-3.0.0}/_errortools/future.py +179 -165
- {errortools-2.4.0 → errortools-3.0.0}/_errortools/logging/record.py +8 -1
- {errortools-2.4.0 → errortools-3.0.0}/_errortools/logging/sink.py +10 -3
- errortools-3.0.0/_errortools/partial.py +199 -0
- {errortools-2.4.0 → errortools-3.0.0}/_errortools/raises.py +42 -39
- {errortools-2.4.0 → errortools-3.0.0}/_errortools/typing.py +7 -1
- {errortools-2.4.0 → errortools-3.0.0}/_errortools/version.py +2 -2
- {errortools-2.4.0 → errortools-3.0.0}/_errortools/wrappers/cache.py +7 -1
- {errortools-2.4.0 → errortools-3.0.0}/_errortools/wrappers/ignore.py +8 -1
- {errortools-2.4.0 → errortools-3.0.0}/errortools/__init__.py +0 -12
- errortools-3.0.0/errortools/future.py +5 -0
- errortools-3.0.0/errortools/logging.py +46 -0
- errortools-3.0.0/errortools/partial.py +5 -0
- {errortools-2.4.0 → errortools-3.0.0/errortools.egg-info}/PKG-INFO +16 -6
- {errortools-2.4.0 → errortools-3.0.0}/errortools.egg-info/SOURCES.txt +4 -6
- errortools-3.0.0/setup.py +58 -0
- {errortools-2.4.0 → errortools-3.0.0}/tests/__init__.py +1 -1
- {errortools-2.4.0 → errortools-3.0.0}/tests/test_abc.py +0 -4
- {errortools-2.4.0 → errortools-3.0.0}/tests/test_const.py +0 -5
- {errortools-2.4.0 → errortools-3.0.0}/tests/test_decorator.py +3 -8
- {errortools-2.4.0 → errortools-3.0.0}/tests/test_descriptor.py +0 -5
- {errortools-2.4.0 → errortools-3.0.0}/tests/test_errno.py +0 -5
- {errortools-2.4.0 → errortools-3.0.0}/tests/test_errorcodes.py +0 -5
- {errortools-2.4.0 → errortools-3.0.0}/tests/test_future.py +0 -6
- errortools-3.0.0/tests/test_groups.py +128 -0
- {errortools-2.4.0 → errortools-3.0.0}/tests/test_ignore.py +0 -5
- {errortools-2.4.0 → errortools-3.0.0}/tests/test_logging.py +7 -10
- {errortools-2.4.0 → errortools-3.0.0}/tests/test_partials.py +0 -5
- {errortools-2.4.0 → errortools-3.0.0}/tests/test_raises.py +36 -37
- {errortools-2.4.0 → errortools-3.0.0}/tests/test_typing.py +0 -5
- {errortools-2.4.0 → errortools-3.0.0}/tests/test_warnings.py +0 -5
- errortools-2.4.0/_errortools/methods/__init__.py +0 -11
- errortools-2.4.0/_errortools/methods/errorattr.py +0 -37
- errortools-2.4.0/_errortools/methods/errordelattr.py +0 -35
- errortools-2.4.0/_errortools/methods/errorhasattr.py +0 -27
- errortools-2.4.0/_errortools/methods/errorsetattr.py +0 -40
- errortools-2.4.0/_errortools/partial.py +0 -110
- errortools-2.4.0/setup.py +0 -35
- errortools-2.4.0/tests/test_groups.py +0 -129
- errortools-2.4.0/tests/test_mixins.py +0 -256
- {errortools-2.4.0 → errortools-3.0.0}/AUTHORS.txt +0 -0
- {errortools-2.4.0 → errortools-3.0.0}/LICENSE.txt +0 -0
- {errortools-2.4.0 → errortools-3.0.0}/_errortools/__init__.py +0 -0
- {errortools-2.4.0 → errortools-3.0.0}/_errortools/_cli.py +0 -0
- {errortools-2.4.0 → errortools-3.0.0}/_errortools/classes/__init__.py +0 -0
- {errortools-2.4.0 → errortools-3.0.0}/_errortools/classes/errorcodes.py +0 -0
- {errortools-2.4.0 → errortools-3.0.0}/_errortools/classes/warn.py +0 -0
- {errortools-2.4.0 → errortools-3.0.0}/_errortools/cli.py +0 -0
- {errortools-2.4.0 → errortools-3.0.0}/_errortools/const.py +0 -0
- {errortools-2.4.0 → errortools-3.0.0}/_errortools/decorator/__init__.py +0 -0
- {errortools-2.4.0 → errortools-3.0.0}/_errortools/decorator/cache.py +0 -0
- {errortools-2.4.0 → errortools-3.0.0}/_errortools/descriptor/__init__.py +0 -0
- {errortools-2.4.0 → errortools-3.0.0}/_errortools/descriptor/errormsg.py +0 -0
- {errortools-2.4.0 → errortools-3.0.0}/_errortools/descriptor/nonblankmsg.py +0 -0
- {errortools-2.4.0 → errortools-3.0.0}/_errortools/errno.py +0 -0
- {errortools-2.4.0 → errortools-3.0.0}/_errortools/ignore.py +0 -0
- {errortools-2.4.0 → errortools-3.0.0}/_errortools/logging/__init__.py +0 -0
- {errortools-2.4.0 → errortools-3.0.0}/_errortools/logging/base.py +0 -0
- {errortools-2.4.0 → errortools-3.0.0}/_errortools/logging/level.py +0 -0
- {errortools-2.4.0 → errortools-3.0.0}/_errortools/logging/logger.py +0 -0
- {errortools-2.4.0 → errortools-3.0.0}/_errortools/metadata.py +0 -0
- {errortools-2.4.0 → errortools-3.0.0}/_errortools/py.typed +0 -0
- {errortools-2.4.0 → errortools-3.0.0}/_errortools/wrappers/__init__.py +0 -0
- {errortools-2.4.0 → errortools-3.0.0}/errortools/__main__.py +0 -0
- {errortools-2.4.0 → errortools-3.0.0}/errortools.egg-info/dependency_links.txt +0 -0
- {errortools-2.4.0 → errortools-3.0.0}/errortools.egg-info/entry_points.txt +0 -0
- {errortools-2.4.0 → errortools-3.0.0}/errortools.egg-info/requires.txt +0 -0
- {errortools-2.4.0 → errortools-3.0.0}/errortools.egg-info/top_level.txt +0 -0
- {errortools-2.4.0 → errortools-3.0.0}/setup.cfg +0 -0
- {errortools-2.4.0 → errortools-3.0.0}/tests/conftest.py +0 -0
- {errortools-2.4.0 → errortools-3.0.0}/tests/run_tests.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: errortools
|
|
3
|
-
Version:
|
|
3
|
+
Version: 3.0.0
|
|
4
4
|
Summary: errortools - a toolset for working with Python exceptions and warnings and logging.
|
|
5
5
|
Home-page: https://github.com/more-abc/errortools
|
|
6
6
|
Author: Evan Yang
|
|
@@ -8,14 +8,17 @@ Author-email: quantbit@126.com
|
|
|
8
8
|
License: MIT
|
|
9
9
|
Classifier: License :: OSI Approved :: MIT License
|
|
10
10
|
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
11
13
|
Classifier: Programming Language :: Python :: 3.10
|
|
12
14
|
Classifier: Programming Language :: Python :: 3.11
|
|
13
15
|
Classifier: Programming Language :: Python :: 3.12
|
|
14
16
|
Classifier: Programming Language :: Python :: 3.13
|
|
15
17
|
Classifier: Programming Language :: Python :: 3.14
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.15
|
|
16
19
|
Classifier: Operating System :: OS Independent
|
|
17
20
|
Classifier: Typing :: Typed
|
|
18
|
-
Requires-Python: >=3.
|
|
21
|
+
Requires-Python: >=3.8
|
|
19
22
|
Description-Content-Type: text/markdown
|
|
20
23
|
License-File: LICENSE.txt
|
|
21
24
|
License-File: AUTHORS.txt
|
|
@@ -36,13 +39,20 @@ Dynamic: summary
|
|
|
36
39
|
# errortools
|
|
37
40
|
A lightweight Python exception handling utility library.
|
|
38
41
|
|
|
42
|
+
[](https://google.github.io/styleguide/pyguide.html#s3.8-comments-and-docstrings)
|
|
43
|
+
[](https://pypi.org/project/errortools/)
|
|
44
|
+
[](https://pypi.org/project/errortools/)
|
|
45
|
+

|
|
46
|
+

|
|
47
|
+

|
|
48
|
+

|
|
49
|
+
|
|
39
50
|
## Features
|
|
40
51
|
- **Raise Exceptions**: `raises()`, `raises_all()`, `reraise()` — batch raising and exception conversion
|
|
41
52
|
- **Catch & Suppress**: `ignore()`, `ignore_subclass()`, `ignore_warns()`, `fast_ignore()`, `super_fast_ignore()`, `timeout()`, `retry()` — graceful suppression of exceptions and warnings, with automatic retry
|
|
42
53
|
- **Future Utilities**: `super_fast_catch()`, `super_fast_reraise()`, `ExceptionCollector` — lightweight exception handling for high-performance scenarios
|
|
43
54
|
- **Exception Caching**: `error_cache` — cache exceptions raised by functions (similar to `lru_cache`)
|
|
44
55
|
- **Custom Exceptions**: `PureBaseException`, `ContextException`, `BaseErrorCodes`, `BaseWarning` — structured exception classes with error codes, trace IDs, and context
|
|
45
|
-
- **Attribute Error Mixin**: Customize error behavior for attribute access, assignment, and deletion
|
|
46
56
|
- **Type Aliases**: `ExceptionType`, `AnyErrorCode`, `BaseErrorCodesType`, and more
|
|
47
57
|
- **Logging**: `logger` — loguru-inspired structured logger with leveled output, multiple sinks, context binding, and exception capture
|
|
48
58
|
|
|
@@ -255,9 +265,9 @@ logger.success("All systems operational")
|
|
|
255
265
|
Output (colourised in a terminal):
|
|
256
266
|
|
|
257
267
|
```
|
|
258
|
-
2026-
|
|
259
|
-
2026-
|
|
260
|
-
2026-
|
|
268
|
+
2026-04-30 08:34:21.850 | ℹ INFO | <string>:<module>:3 - Server started on port 8080
|
|
269
|
+
2026-04-30 08:34:21.851 | ⚠ WARNING | <string>:<module>:4 - Disk at 92.5%
|
|
270
|
+
2026-04-30 08:34:21.851 | ✔ SUCCESS | <string>:<module>:5 - All systems operational
|
|
261
271
|
```
|
|
262
272
|
|
|
263
273
|
### Log levels
|
|
@@ -1,13 +1,20 @@
|
|
|
1
1
|
# errortools
|
|
2
2
|
A lightweight Python exception handling utility library.
|
|
3
3
|
|
|
4
|
+
[](https://google.github.io/styleguide/pyguide.html#s3.8-comments-and-docstrings)
|
|
5
|
+
[](https://pypi.org/project/errortools/)
|
|
6
|
+
[](https://pypi.org/project/errortools/)
|
|
7
|
+

|
|
8
|
+

|
|
9
|
+

|
|
10
|
+

|
|
11
|
+
|
|
4
12
|
## Features
|
|
5
13
|
- **Raise Exceptions**: `raises()`, `raises_all()`, `reraise()` — batch raising and exception conversion
|
|
6
14
|
- **Catch & Suppress**: `ignore()`, `ignore_subclass()`, `ignore_warns()`, `fast_ignore()`, `super_fast_ignore()`, `timeout()`, `retry()` — graceful suppression of exceptions and warnings, with automatic retry
|
|
7
15
|
- **Future Utilities**: `super_fast_catch()`, `super_fast_reraise()`, `ExceptionCollector` — lightweight exception handling for high-performance scenarios
|
|
8
16
|
- **Exception Caching**: `error_cache` — cache exceptions raised by functions (similar to `lru_cache`)
|
|
9
17
|
- **Custom Exceptions**: `PureBaseException`, `ContextException`, `BaseErrorCodes`, `BaseWarning` — structured exception classes with error codes, trace IDs, and context
|
|
10
|
-
- **Attribute Error Mixin**: Customize error behavior for attribute access, assignment, and deletion
|
|
11
18
|
- **Type Aliases**: `ExceptionType`, `AnyErrorCode`, `BaseErrorCodesType`, and more
|
|
12
19
|
- **Logging**: `logger` — loguru-inspired structured logger with leveled output, multiple sinks, context binding, and exception capture
|
|
13
20
|
|
|
@@ -220,9 +227,9 @@ logger.success("All systems operational")
|
|
|
220
227
|
Output (colourised in a terminal):
|
|
221
228
|
|
|
222
229
|
```
|
|
223
|
-
2026-
|
|
224
|
-
2026-
|
|
225
|
-
2026-
|
|
230
|
+
2026-04-30 08:34:21.850 | ℹ INFO | <string>:<module>:3 - Server started on port 8080
|
|
231
|
+
2026-04-30 08:34:21.851 | ⚠ WARNING | <string>:<module>:4 - Disk at 92.5%
|
|
232
|
+
2026-04-30 08:34:21.851 | ✔ SUCCESS | <string>:<module>:5 - All systems operational
|
|
226
233
|
```
|
|
227
234
|
|
|
228
235
|
### Log levels
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
#define PY_SSIZE_T_CLEAN
|
|
2
|
+
#include <Python.h>
|
|
3
|
+
|
|
4
|
+
/* Fast exception type checking */
|
|
5
|
+
static PyObject* fast_issubclass_check(PyObject* self, PyObject* args) {
|
|
6
|
+
PyObject *typ, *excs;
|
|
7
|
+
if (!PyArg_ParseTuple(args, "OO", &typ, &excs)) {
|
|
8
|
+
return NULL;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
if (typ == Py_None) {
|
|
12
|
+
Py_RETURN_FALSE;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
int result = PyObject_IsSubclass(typ, excs);
|
|
16
|
+
if (result == -1) {
|
|
17
|
+
return NULL;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return PyBool_FromLong(result);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/* Fast exception collector append */
|
|
24
|
+
static PyObject* fast_append_exception(PyObject* self, PyObject* args) {
|
|
25
|
+
PyObject *list, *exc;
|
|
26
|
+
if (!PyArg_ParseTuple(args, "OO", &list, &exc)) {
|
|
27
|
+
return NULL;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (PyList_Append(list, exc) == -1) {
|
|
31
|
+
return NULL;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
Py_RETURN_NONE;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/* Method definitions */
|
|
38
|
+
static PyMethodDef SpeedupMethods[] = {
|
|
39
|
+
{"fast_issubclass_check", fast_issubclass_check, METH_VARARGS,
|
|
40
|
+
"Fast exception type checking"},
|
|
41
|
+
{"fast_append_exception", fast_append_exception, METH_VARARGS,
|
|
42
|
+
"Fast exception list append"},
|
|
43
|
+
{NULL, NULL, 0, NULL}
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
/* Module definition */
|
|
47
|
+
static struct PyModuleDef speedupmodule = {
|
|
48
|
+
PyModuleDef_HEAD_INIT,
|
|
49
|
+
"_speedup",
|
|
50
|
+
"C speedup for errortools",
|
|
51
|
+
-1,
|
|
52
|
+
SpeedupMethods
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
/* Module initialization */
|
|
56
|
+
PyMODINIT_FUNC PyInit__speedup(void) {
|
|
57
|
+
return PyModule_Create(&speedupmodule);
|
|
58
|
+
}
|
|
@@ -4,14 +4,12 @@ import copy
|
|
|
4
4
|
import shutil
|
|
5
5
|
import csv
|
|
6
6
|
import configparser
|
|
7
|
+
import sys
|
|
7
8
|
|
|
8
|
-
|
|
9
|
-
from
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
ErrorAttrDeletionMixin,
|
|
13
|
-
ErrorSetAttrMixin,
|
|
14
|
-
)
|
|
9
|
+
if sys.version_info >= (3, 15):
|
|
10
|
+
from typing import disjoint_base
|
|
11
|
+
else:
|
|
12
|
+
from typing_extensions import disjoint_base
|
|
15
13
|
|
|
16
14
|
|
|
17
15
|
def _check_methods(C: type[Any], *methods: str) -> Union[bool, Literal[NotImplemented]]: # type: ignore
|
|
@@ -31,147 +29,6 @@ def _check_methods(C: type[Any], *methods: str) -> Union[bool, Literal[NotImplem
|
|
|
31
29
|
return True
|
|
32
30
|
|
|
33
31
|
|
|
34
|
-
@disjoint_base
|
|
35
|
-
class ErrorAttrable(ABC):
|
|
36
|
-
"""
|
|
37
|
-
Abstract Base Class (ABC) for classes supporting custom attribute error handling.
|
|
38
|
-
|
|
39
|
-
This class follows the design pattern of `collections.abc` (e.g., Iterable, Mapping):
|
|
40
|
-
- Uses `__subclasshook__` + `_check_methods` to validate subclass compliance
|
|
41
|
-
- Enforces implementation of attribute error handling methods via abstract methods
|
|
42
|
-
- Implements native attribute magic methods to forward errors to custom handlers
|
|
43
|
-
|
|
44
|
-
Core behavior:
|
|
45
|
-
When attribute operations (get/delete/check/set) fail, the corresponding native
|
|
46
|
-
magic methods automatically invoke custom error handling methods implemented by subclasses.
|
|
47
|
-
"""
|
|
48
|
-
|
|
49
|
-
__slots__ = ()
|
|
50
|
-
|
|
51
|
-
@classmethod
|
|
52
|
-
def __subclasshook__(cls, C: type[Any]) -> Union[bool, Literal[NotImplemented]]: # type: ignore
|
|
53
|
-
"""
|
|
54
|
-
Check if a class is a subclass of ErrorAttrable (per `collections.abc` style).
|
|
55
|
-
|
|
56
|
-
This method enables `issubclass()` to recognize classes that implement the core
|
|
57
|
-
__errorattr__ method (base requirement), matching the behavior of standard ABCs.
|
|
58
|
-
|
|
59
|
-
Args:
|
|
60
|
-
C: The class to check for compliance with ErrorAttrable interface
|
|
61
|
-
|
|
62
|
-
Returns:
|
|
63
|
-
True if C implements __errorattr__, NotImplemented otherwise
|
|
64
|
-
"""
|
|
65
|
-
if cls is ErrorAttrable:
|
|
66
|
-
return _check_methods(C, "__errorattr__")
|
|
67
|
-
return NotImplemented
|
|
68
|
-
|
|
69
|
-
def __getattr__(self, name: str) -> Any:
|
|
70
|
-
"""
|
|
71
|
-
Native magic method: Automatically invoked for missing attribute access.
|
|
72
|
-
|
|
73
|
-
Forwards the attribute lookup failure to the custom `__errorattr__` method.
|
|
74
|
-
"""
|
|
75
|
-
return self.__errorattr__(name)
|
|
76
|
-
|
|
77
|
-
@abstractmethod
|
|
78
|
-
def __errorattr__(self, name: str) -> Any:
|
|
79
|
-
"""
|
|
80
|
-
Abstract method for custom missing attribute handling (MUST be implemented).
|
|
81
|
-
|
|
82
|
-
Args:
|
|
83
|
-
name: Name of the missing attribute being accessed
|
|
84
|
-
|
|
85
|
-
Raises:
|
|
86
|
-
NotImplementedError: If not overridden
|
|
87
|
-
AttributeError: Recommended error type for missing attributes
|
|
88
|
-
"""
|
|
89
|
-
raise NotImplementedError(
|
|
90
|
-
"Subclasses of ErrorAttrable must implement __errorattr__(self, name: str).\n"
|
|
91
|
-
"See `collections.abc` for similar abstract method requirements (e.g., __iter__ for Iterable)."
|
|
92
|
-
)
|
|
93
|
-
|
|
94
|
-
def __delattr__(self, name: str) -> None:
|
|
95
|
-
"""
|
|
96
|
-
Native magic method: Automatically invoked for attribute deletion errors.
|
|
97
|
-
|
|
98
|
-
Forwards to __errordelattr__ if implemented, else raises standard error.
|
|
99
|
-
"""
|
|
100
|
-
if hasattr(self, "__errordelattr__"):
|
|
101
|
-
self.__errordelattr__(name)
|
|
102
|
-
else:
|
|
103
|
-
super().__delattr__(name)
|
|
104
|
-
|
|
105
|
-
def __errordelattr__(self, name: str) -> None:
|
|
106
|
-
"""
|
|
107
|
-
Custom handler for attribute deletion errors (OPTIONAL to implement).
|
|
108
|
-
|
|
109
|
-
Args:
|
|
110
|
-
name: Name of the attribute being deleted
|
|
111
|
-
"""
|
|
112
|
-
raise NotImplementedError(
|
|
113
|
-
"Subclasses of ErrorAttrable must implement __errordelattr__(self, name: str).\n"
|
|
114
|
-
"See `collections.abc` for similar abstract method requirements (e.g., __iter__ for Iterable)."
|
|
115
|
-
)
|
|
116
|
-
|
|
117
|
-
def __contains__(self, name: str) -> bool:
|
|
118
|
-
"""
|
|
119
|
-
Alternative to __hasattr__: Check if attribute exists (customizable).
|
|
120
|
-
|
|
121
|
-
Forwards to __errorhasattr__ if implemented, else uses standard check.
|
|
122
|
-
"""
|
|
123
|
-
if hasattr(self, "__errorhasattr__"):
|
|
124
|
-
return self.__errorhasattr__(name)
|
|
125
|
-
else:
|
|
126
|
-
return hasattr(super(), name)
|
|
127
|
-
|
|
128
|
-
def __errorhasattr__(self, name: str) -> bool:
|
|
129
|
-
"""
|
|
130
|
-
Custom handler for attribute existence checks (OPTIONAL to implement).
|
|
131
|
-
|
|
132
|
-
Args:
|
|
133
|
-
name: Name of the attribute to check
|
|
134
|
-
|
|
135
|
-
Returns:
|
|
136
|
-
bool: True if attribute exists (custom logic), False otherwise
|
|
137
|
-
"""
|
|
138
|
-
raise NotImplementedError(
|
|
139
|
-
"Subclasses of ErrorAttrable must implement __errorhasattr__(self, name: str).\n"
|
|
140
|
-
"See `collections.abc` for similar abstract method requirements (e.g., __iter__ for Iterable)."
|
|
141
|
-
)
|
|
142
|
-
|
|
143
|
-
def __setattr__(self, name: str, value: Any) -> None:
|
|
144
|
-
"""
|
|
145
|
-
Native magic method: Automatically invoked for attribute setting errors.
|
|
146
|
-
|
|
147
|
-
Forwards to __errorsetattr__ if implemented, else uses standard setting.
|
|
148
|
-
"""
|
|
149
|
-
if hasattr(self, "__errorsetattr__"):
|
|
150
|
-
self.__errorsetattr__(name, value)
|
|
151
|
-
else:
|
|
152
|
-
super().__setattr__(name, value)
|
|
153
|
-
|
|
154
|
-
def __errorsetattr__(self, name: str, value: Any) -> None:
|
|
155
|
-
"""
|
|
156
|
-
Custom handler for attribute setting errors (OPTIONAL to implement).
|
|
157
|
-
|
|
158
|
-
Args:
|
|
159
|
-
name: Name of the attribute to set
|
|
160
|
-
value: Value to assign to the attribute
|
|
161
|
-
"""
|
|
162
|
-
raise NotImplementedError(
|
|
163
|
-
"Subclasses of ErrorAttrable must implement __errorsetattr__(self, name: str, value: Any).\n"
|
|
164
|
-
"See `collections.abc` for similar abstract method requirements (e.g., __iter__ for Iterable)."
|
|
165
|
-
)
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
# register four Mixin's
|
|
169
|
-
ErrorAttrable.register(ErrorAttrMixin)
|
|
170
|
-
ErrorAttrable.register(ErrorAttrDeletionMixin)
|
|
171
|
-
ErrorAttrable.register(ErrorAttrCheckMixin)
|
|
172
|
-
ErrorAttrable.register(ErrorSetAttrMixin)
|
|
173
|
-
|
|
174
|
-
|
|
175
32
|
# ----------------------------------------------------------------------
|
|
176
33
|
# ErrorCodeable
|
|
177
34
|
# ----------------------------------------------------------------------
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"""Base and concrete group classes for collecting and raising exceptions together."""
|
|
2
2
|
|
|
3
3
|
from abc import abstractmethod, ABC
|
|
4
|
+
import sys
|
|
4
5
|
|
|
5
6
|
__all__ = [
|
|
6
7
|
"BaseGroup",
|
|
@@ -67,52 +68,54 @@ class BaseGroup(Exception, ABC):
|
|
|
67
68
|
)
|
|
68
69
|
|
|
69
70
|
|
|
70
|
-
|
|
71
|
-
"""A collector that accumulates exceptions and raises them as an ExceptionGroup.
|
|
71
|
+
if sys.version_info >= (3, 11):
|
|
72
72
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
collected without raising.
|
|
73
|
+
class GroupErrors(BaseGroup):
|
|
74
|
+
"""A collector that accumulates exceptions and raises them as an ExceptionGroup.
|
|
76
75
|
|
|
77
|
-
|
|
76
|
+
Call `collect` to add exceptions one by one, then `raise_group`
|
|
77
|
+
to raise them all at once. Use `errors` to inspect what has been
|
|
78
|
+
collected without raising.
|
|
78
79
|
|
|
79
|
-
|
|
80
|
-
>>> g.collect(TypeError("expected str"))
|
|
81
|
-
>>> g.collect(ValueError("value out of range"))
|
|
82
|
-
>>> g.raise_group()
|
|
83
|
-
Traceback (most recent call last):
|
|
84
|
-
...
|
|
85
|
-
ExceptionGroup: validation failed (2 sub-exceptions)
|
|
86
|
-
"""
|
|
80
|
+
Example:
|
|
87
81
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
82
|
+
>>> g = GroupErrors("validation failed")
|
|
83
|
+
>>> g.collect(TypeError("expected str"))
|
|
84
|
+
>>> g.collect(ValueError("value out of range"))
|
|
85
|
+
>>> g.raise_group()
|
|
86
|
+
Traceback (most recent call last):
|
|
87
|
+
...
|
|
88
|
+
ExceptionGroup: validation failed (2 sub-exceptions)
|
|
89
|
+
"""
|
|
91
90
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
return list(self._errors)
|
|
91
|
+
def __init__(self, group_msg: str = "multiple errors") -> None:
|
|
92
|
+
super().__init__(group_msg)
|
|
93
|
+
self._errors: list[Exception] = []
|
|
96
94
|
|
|
97
|
-
|
|
98
|
-
|
|
95
|
+
@property
|
|
96
|
+
def errors(self) -> list[Exception]:
|
|
97
|
+
"""A copy of the collected exceptions."""
|
|
98
|
+
return list(self._errors)
|
|
99
99
|
|
|
100
|
-
|
|
101
|
-
exc
|
|
102
|
-
"""
|
|
103
|
-
self._errors.append(exc)
|
|
100
|
+
def collect(self, exc: Exception) -> None:
|
|
101
|
+
"""Add *exc* to the group without raising it.
|
|
104
102
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
103
|
+
Args:
|
|
104
|
+
exc: The exception instance to collect.
|
|
105
|
+
"""
|
|
106
|
+
self._errors.append(exc)
|
|
108
107
|
|
|
109
|
-
|
|
110
|
-
|
|
108
|
+
def clear(self) -> None:
|
|
109
|
+
"""Remove all collected exceptions."""
|
|
110
|
+
self._errors.clear()
|
|
111
111
|
|
|
112
|
-
|
|
112
|
+
def raise_group(self) -> None:
|
|
113
|
+
"""Raise all collected exceptions as an `ExceptionGroup`.
|
|
113
114
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
115
|
+
Does nothing if no exceptions have been collected.
|
|
116
|
+
|
|
117
|
+
Raises:
|
|
118
|
+
ExceptionGroup: Containing every exception added via `collect`.
|
|
119
|
+
"""
|
|
120
|
+
if self._errors:
|
|
121
|
+
raise ExceptionGroup(self.group_msg, self._errors)
|
|
@@ -53,7 +53,7 @@ def experimental(
|
|
|
53
53
|
@wraps(func)
|
|
54
54
|
def wrapper(*args, **kwargs):
|
|
55
55
|
msg = f"{func.__name__} is experimental. {reason}"
|
|
56
|
-
warnings.warn(msg,
|
|
56
|
+
warnings.warn(msg, FutureWarning, stacklevel=2)
|
|
57
57
|
return func(*args, **kwargs)
|
|
58
58
|
|
|
59
59
|
return wrapper
|