errortools 2.5.0__tar.gz → 3.1.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.
Files changed (78) hide show
  1. errortools-3.1.0/AUTHORS.txt +12 -0
  2. {errortools-2.5.0/errortools.egg-info → errortools-3.1.0}/PKG-INFO +6 -4
  3. {errortools-2.5.0 → errortools-3.1.0}/README.md +2 -2
  4. errortools-3.1.0/_errortools/_speedup.c +127 -0
  5. {errortools-2.5.0 → errortools-3.1.0}/_errortools/cli.py +1 -1
  6. {errortools-2.5.0 → errortools-3.1.0}/_errortools/future.py +24 -10
  7. {errortools-2.5.0 → errortools-3.1.0}/_errortools/ignore.py +8 -0
  8. {errortools-2.5.0 → errortools-3.1.0}/_errortools/raises.py +42 -39
  9. {errortools-2.5.0 → errortools-3.1.0}/_errortools/typing.py +23 -5
  10. {errortools-2.5.0 → errortools-3.1.0}/_errortools/version.py +2 -2
  11. {errortools-2.5.0 → errortools-3.1.0}/errortools/__init__.py +0 -12
  12. {errortools-2.5.0 → errortools-3.1.0/errortools.egg-info}/PKG-INFO +6 -4
  13. errortools-3.1.0/errortools.egg-info/SOURCES.txt +47 -0
  14. {errortools-2.5.0 → errortools-3.1.0}/errortools.egg-info/entry_points.txt +0 -1
  15. {errortools-2.5.0 → errortools-3.1.0}/errortools.egg-info/top_level.txt +1 -1
  16. errortools-3.1.0/setup.py +58 -0
  17. {errortools-2.5.0/tests → errortools-3.1.0/testing}/__init__.py +1 -2
  18. errortools-3.1.0/testing/__main__.py +4 -0
  19. {errortools-2.5.0/tests → errortools-3.1.0/testing}/test_abc.py +0 -7
  20. {errortools-2.5.0/tests → errortools-3.1.0/testing}/test_const.py +0 -5
  21. {errortools-2.5.0/tests → errortools-3.1.0/testing}/test_decorator.py +0 -5
  22. {errortools-2.5.0/tests → errortools-3.1.0/testing}/test_descriptor.py +0 -5
  23. {errortools-2.5.0/tests → errortools-3.1.0/testing}/test_errno.py +0 -5
  24. {errortools-2.5.0/tests → errortools-3.1.0/testing}/test_errorcodes.py +0 -5
  25. {errortools-2.5.0/tests → errortools-3.1.0/testing}/test_future.py +0 -6
  26. {errortools-2.5.0/tests → errortools-3.1.0/testing}/test_groups.py +6 -5
  27. {errortools-2.5.0/tests → errortools-3.1.0/testing}/test_ignore.py +0 -5
  28. {errortools-2.5.0/tests → errortools-3.1.0/testing}/test_logging.py +0 -5
  29. {errortools-2.5.0/tests → errortools-3.1.0/testing}/test_partials.py +0 -5
  30. {errortools-2.5.0/tests → errortools-3.1.0/testing}/test_raises.py +36 -37
  31. {errortools-2.5.0/tests → errortools-3.1.0/testing}/test_typing.py +0 -5
  32. {errortools-2.5.0/tests → errortools-3.1.0/testing}/test_warnings.py +0 -5
  33. errortools-2.5.0/AUTHORS.txt +0 -3
  34. errortools-2.5.0/_errortools/classes/__init__.py +0 -1
  35. errortools-2.5.0/_errortools/classes/abc.py +0 -359
  36. errortools-2.5.0/_errortools/classes/errorcodes.py +0 -273
  37. errortools-2.5.0/_errortools/classes/group.py +0 -118
  38. errortools-2.5.0/_errortools/classes/warn.py +0 -124
  39. errortools-2.5.0/_errortools/decorator/__init__.py +0 -1
  40. errortools-2.5.0/_errortools/decorator/cache.py +0 -82
  41. errortools-2.5.0/_errortools/decorator/deprecated.py +0 -61
  42. errortools-2.5.0/_errortools/descriptor/__init__.py +0 -2
  43. errortools-2.5.0/_errortools/descriptor/errormsg.py +0 -37
  44. errortools-2.5.0/_errortools/descriptor/nonblankmsg.py +0 -52
  45. errortools-2.5.0/_errortools/logging/__init__.py +0 -43
  46. errortools-2.5.0/_errortools/logging/base.py +0 -467
  47. errortools-2.5.0/_errortools/logging/level.py +0 -85
  48. errortools-2.5.0/_errortools/logging/logger.py +0 -13
  49. errortools-2.5.0/_errortools/logging/record.py +0 -109
  50. errortools-2.5.0/_errortools/logging/sink.py +0 -236
  51. errortools-2.5.0/_errortools/methods/__init__.py +0 -11
  52. errortools-2.5.0/_errortools/methods/errorattr.py +0 -37
  53. errortools-2.5.0/_errortools/methods/errordelattr.py +0 -35
  54. errortools-2.5.0/_errortools/methods/errorhasattr.py +0 -27
  55. errortools-2.5.0/_errortools/methods/errorsetattr.py +0 -40
  56. errortools-2.5.0/_errortools/wrappers/__init__.py +0 -2
  57. errortools-2.5.0/_errortools/wrappers/cache.py +0 -95
  58. errortools-2.5.0/_errortools/wrappers/ignore.py +0 -115
  59. errortools-2.5.0/errortools.egg-info/SOURCES.txt +0 -71
  60. errortools-2.5.0/setup.py +0 -79
  61. errortools-2.5.0/tests/test_mixins.py +0 -256
  62. {errortools-2.5.0 → errortools-3.1.0}/LICENSE.txt +0 -0
  63. {errortools-2.5.0 → errortools-3.1.0}/_errortools/__init__.py +0 -0
  64. {errortools-2.5.0 → errortools-3.1.0}/_errortools/_cli.py +0 -0
  65. {errortools-2.5.0 → errortools-3.1.0}/_errortools/const.py +0 -0
  66. {errortools-2.5.0 → errortools-3.1.0}/_errortools/errno.py +0 -0
  67. {errortools-2.5.0 → errortools-3.1.0}/_errortools/metadata.py +0 -0
  68. {errortools-2.5.0 → errortools-3.1.0}/_errortools/partial.py +0 -0
  69. {errortools-2.5.0 → errortools-3.1.0}/_errortools/py.typed +0 -0
  70. {errortools-2.5.0 → errortools-3.1.0}/errortools/__main__.py +0 -0
  71. {errortools-2.5.0 → errortools-3.1.0}/errortools/future.py +0 -0
  72. {errortools-2.5.0 → errortools-3.1.0}/errortools/logging.py +0 -0
  73. {errortools-2.5.0 → errortools-3.1.0}/errortools/partial.py +0 -0
  74. {errortools-2.5.0 → errortools-3.1.0}/errortools.egg-info/dependency_links.txt +0 -0
  75. {errortools-2.5.0 → errortools-3.1.0}/errortools.egg-info/requires.txt +0 -0
  76. {errortools-2.5.0 → errortools-3.1.0}/setup.cfg +0 -0
  77. {errortools-2.5.0/tests → errortools-3.1.0/testing}/conftest.py +0 -0
  78. {errortools-2.5.0/tests → errortools-3.1.0/testing}/run_tests.py +0 -0
@@ -0,0 +1,12 @@
1
+ # (Lines starting with # are comments)
2
+ # Tips:
3
+ # Contributors are not sorted by initials,
4
+ # but by contribution time.
5
+ # Here are the real contributors
6
+ aiwonderland
7
+ qorexdev
8
+ vgauraha62
9
+ yangphysics
10
+ # And here are bot contributors
11
+ dependabot[bot]
12
+ AbaAbaAba-bot-like[bot]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: errortools
3
- Version: 2.5.0
3
+ Version: 3.1.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,6 +8,8 @@ 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
@@ -16,7 +18,7 @@ Classifier: Programming Language :: Python :: 3.14
16
18
  Classifier: Programming Language :: Python :: 3.15
17
19
  Classifier: Operating System :: OS Independent
18
20
  Classifier: Typing :: Typed
19
- Requires-Python: >=3.10
21
+ Requires-Python: >=3.8
20
22
  Description-Content-Type: text/markdown
21
23
  License-File: LICENSE.txt
22
24
  License-File: AUTHORS.txt
@@ -44,6 +46,7 @@ A lightweight Python exception handling utility library.
44
46
  ![This month commits](https://img.shields.io/github/commit-activity/m/more-abc/errortools)
45
47
  ![Past year commits](https://img.shields.io/github/commit-activity/y/more-abc/errortools)
46
48
  ![Total commits badge](https://img.shields.io/github/commit-activity/t/more-abc/errortools)
49
+ ![OS support](https://img.shields.io/badge/OS-macOS%20Linux%20Windows-red)
47
50
 
48
51
  ## Features
49
52
  - **Raise Exceptions**: `raises()`, `raises_all()`, `reraise()` — batch raising and exception conversion
@@ -51,7 +54,6 @@ A lightweight Python exception handling utility library.
51
54
  - **Future Utilities**: `super_fast_catch()`, `super_fast_reraise()`, `ExceptionCollector` — lightweight exception handling for high-performance scenarios
52
55
  - **Exception Caching**: `error_cache` — cache exceptions raised by functions (similar to `lru_cache`)
53
56
  - **Custom Exceptions**: `PureBaseException`, `ContextException`, `BaseErrorCodes`, `BaseWarning` — structured exception classes with error codes, trace IDs, and context
54
- - **Attribute Error Mixin**: Customize error behavior for attribute access, assignment, and deletion
55
57
  - **Type Aliases**: `ExceptionType`, `AnyErrorCode`, `BaseErrorCodesType`, and more
56
58
  - **Logging**: `logger` — loguru-inspired structured logger with leveled output, multiple sinks, context binding, and exception capture
57
59
 
@@ -95,7 +97,7 @@ assert err.traceback # full formatted traceback string
95
97
  | `exception` | `Exception \| None` | The original exception instance |
96
98
  | `traceback` | `str \| None` | Formatted traceback string for debugging |
97
99
 
98
- ## Examples
100
+ ## Sorry, but there was more code examples!
99
101
 
100
102
  ```python
101
103
  # ── ignore as a decorator ──
@@ -8,6 +8,7 @@ A lightweight Python exception handling utility library.
8
8
  ![This month commits](https://img.shields.io/github/commit-activity/m/more-abc/errortools)
9
9
  ![Past year commits](https://img.shields.io/github/commit-activity/y/more-abc/errortools)
10
10
  ![Total commits badge](https://img.shields.io/github/commit-activity/t/more-abc/errortools)
11
+ ![OS support](https://img.shields.io/badge/OS-macOS%20Linux%20Windows-red)
11
12
 
12
13
  ## Features
13
14
  - **Raise Exceptions**: `raises()`, `raises_all()`, `reraise()` — batch raising and exception conversion
@@ -15,7 +16,6 @@ A lightweight Python exception handling utility library.
15
16
  - **Future Utilities**: `super_fast_catch()`, `super_fast_reraise()`, `ExceptionCollector` — lightweight exception handling for high-performance scenarios
16
17
  - **Exception Caching**: `error_cache` — cache exceptions raised by functions (similar to `lru_cache`)
17
18
  - **Custom Exceptions**: `PureBaseException`, `ContextException`, `BaseErrorCodes`, `BaseWarning` — structured exception classes with error codes, trace IDs, and context
18
- - **Attribute Error Mixin**: Customize error behavior for attribute access, assignment, and deletion
19
19
  - **Type Aliases**: `ExceptionType`, `AnyErrorCode`, `BaseErrorCodesType`, and more
20
20
  - **Logging**: `logger` — loguru-inspired structured logger with leveled output, multiple sinks, context binding, and exception capture
21
21
 
@@ -59,7 +59,7 @@ assert err.traceback # full formatted traceback string
59
59
  | `exception` | `Exception \| None` | The original exception instance |
60
60
  | `traceback` | `str \| None` | Formatted traceback string for debugging |
61
61
 
62
- ## Examples
62
+ ## Sorry, but there was more code examples!
63
63
 
64
64
  ```python
65
65
  # ── ignore as a decorator ──
@@ -0,0 +1,127 @@
1
+ #define PY_SSIZE_T_CLEAN
2
+ #include <Python.h>
3
+
4
+ /* Fast exception type checking
5
+ *
6
+ * Optimized check for exception type hierarchy using PyObject_IsSubclass.
7
+ * Returns False immediately if typ is None, otherwise checks if typ is a
8
+ * subclass of excs.
9
+ *
10
+ * Args:
11
+ * typ: The type object to check (or None)
12
+ * excs: The exception class(es) to check against
13
+ *
14
+ * Returns:
15
+ * True if typ is a subclass of excs, False otherwise
16
+ * NULL on error with exception set
17
+ */
18
+ static PyObject* fast_issubclass_check(PyObject* self, PyObject* const* args, Py_ssize_t nargs) {
19
+ if (nargs != 2) {
20
+ PyErr_Format(PyExc_TypeError,
21
+ "fast_issubclass_check() takes exactly 2 arguments (%zd given)",
22
+ nargs);
23
+ return NULL;
24
+ }
25
+
26
+ PyObject *typ = args[0];
27
+ PyObject *excs = args[1];
28
+
29
+ /* Handle None case explicitly */
30
+ if (typ == Py_None) {
31
+ Py_RETURN_FALSE;
32
+ }
33
+
34
+ /* Validate that excs is a class or tuple of classes */
35
+ if (!PyType_Check(excs) && !PyTuple_Check(excs)) {
36
+ PyErr_SetString(PyExc_TypeError,
37
+ "second argument must be a class or tuple of classes");
38
+ return NULL;
39
+ }
40
+
41
+ int result = PyObject_IsSubclass(typ, excs);
42
+ if (result == -1) {
43
+ return NULL; /* Exception already set by PyObject_IsSubclass */
44
+ }
45
+
46
+ /* Return bool directly instead of going through PyBool_FromLong */
47
+ if (result == 1) {
48
+ Py_RETURN_TRUE;
49
+ } else {
50
+ Py_RETURN_FALSE;
51
+ }
52
+ }
53
+
54
+ /* Fast exception collector append
55
+ *
56
+ * Optimized append operation for adding exceptions to a list.
57
+ *
58
+ * Args:
59
+ * list: The list object to append to
60
+ * exc: The exception object to append
61
+ *
62
+ * Returns:
63
+ * None on success
64
+ * NULL on error with exception set
65
+ */
66
+ static PyObject* fast_append_exception(PyObject* self, PyObject* const* args, Py_ssize_t nargs) {
67
+ if (nargs != 2) {
68
+ PyErr_Format(PyExc_TypeError,
69
+ "fast_append_exception() takes exactly 2 arguments (%zd given)",
70
+ nargs);
71
+ return NULL;
72
+ }
73
+
74
+ PyObject *list = args[0];
75
+ PyObject *exc = args[1];
76
+
77
+ /* Validate that first argument is actually a list */
78
+ if (!PyList_Check(list)) {
79
+ PyErr_SetString(PyExc_TypeError, "first argument must be a list");
80
+ return NULL;
81
+ }
82
+
83
+ if (PyList_Append(list, exc) == -1) {
84
+ return NULL; /* Exception already set by PyList_Append */
85
+ }
86
+
87
+ Py_RETURN_NONE;
88
+ }
89
+
90
+ /* Method definitions */
91
+ static PyMethodDef SpeedupMethods[] = {
92
+ {
93
+ "fast_issubclass_check",
94
+ (PyCFunction)fast_issubclass_check,
95
+ METH_FASTCALL,
96
+ "fast_issubclass_check(typ, excs) -> bool\n\n"
97
+ "Check if typ is a subclass of excs exception type(s).\n"
98
+ "Returns False if typ is None, otherwise uses PyObject_IsSubclass.\n"
99
+ "Optimized for exception handling performance."
100
+ },
101
+ {
102
+ "fast_append_exception",
103
+ (PyCFunction)fast_append_exception,
104
+ METH_FASTCALL,
105
+ "fast_append_exception(list, exc) -> None\n\n"
106
+ "Append an exception to a list with minimal overhead.\n"
107
+ "Validates that the first argument is a list."
108
+ },
109
+ {NULL, NULL, 0, NULL} /* Sentinel */
110
+ };
111
+
112
+ /* Module definition */
113
+ static struct PyModuleDef speedupmodule = {
114
+ PyModuleDef_HEAD_INIT,
115
+ "_speedup", /* name */
116
+ "C speedup module for errortools\n\n"
117
+ "Provides optimized implementations of exception handling operations:\n"
118
+ " - fast_issubclass_check: Quick exception type hierarchy checking\n"
119
+ " - fast_append_exception: Efficient exception list append operations",
120
+ -1, /* size */
121
+ SpeedupMethods /* methods */
122
+ };
123
+
124
+ /* Module initialization */
125
+ PyMODINIT_FUNC PyInit__speedup(void) {
126
+ return PyModule_Create(&speedupmodule);
127
+ }
@@ -95,7 +95,7 @@ def main() -> None:
95
95
  elif args.url:
96
96
  print(f"URL: {__url__}")
97
97
  elif args.run_tests:
98
- from tests.run_tests import run_tests
98
+ from testing.run_tests import run_tests
99
99
 
100
100
  run_tests()
101
101
  elif args.info:
@@ -1,8 +1,25 @@
1
1
  """Future-focused lightweight exception handling utilities."""
2
2
 
3
3
  from __future__ import annotations
4
+ import sys
5
+
6
+ if sys.version_info <= (3, 10):
7
+ from typing_extensions import TypeAlias
8
+ else:
9
+ from typing import TypeAlias
10
+ from typing import cast, Literal
11
+
12
+ # Try to import C speedup
13
+ try:
14
+ from _errortools._speedup import fast_issubclass_check, fast_append_exception # type: ignore[import-not-found]
15
+ except ImportError:
16
+
17
+ def fast_issubclass_check(typ, excs) -> bool:
18
+ return typ is not None and issubclass(typ, excs)
19
+
20
+ def fast_append_exception(lst, exc) -> None:
21
+ lst.append(exc)
4
22
 
5
- from typing import TypeAlias, cast, Literal
6
23
 
7
24
  __all__ = [
8
25
  "super_fast_ignore",
@@ -26,10 +43,7 @@ class super_fast_ignore:
26
43
  return
27
44
 
28
45
  def __exit__(self, typ: _ExcType | None, *_) -> bool:
29
- if typ is None:
30
- return False
31
- excs = self.excs
32
- return issubclass(typ, excs)
46
+ return cast(bool, fast_issubclass_check(typ, self.excs))
33
47
 
34
48
 
35
49
  class super_fast_catch:
@@ -50,11 +64,11 @@ class super_fast_catch:
50
64
  self.excs = excs if excs else (BaseException,)
51
65
  self.exception: BaseException | None = None
52
66
 
53
- def __enter__(self) -> "super_fast_catch":
67
+ def __enter__(self) -> super_fast_catch:
54
68
  return self
55
69
 
56
70
  def __exit__(self, typ: _ExcType | None, val, *_) -> bool:
57
- if typ is None or not issubclass(typ, self.excs):
71
+ if not fast_issubclass_check(typ, self.excs):
58
72
  return False
59
73
  self.exception = val
60
74
  return True
@@ -117,7 +131,7 @@ class ExceptionCollector:
117
131
 
118
132
  def __exit__(self, exc_typ, exc_val, *_) -> bool:
119
133
  if exc_typ is not None:
120
- self._exceptions.append(exc_val)
134
+ fast_append_exception(self._exceptions, exc_val)
121
135
  if self._stop_on_first:
122
136
  return False
123
137
  return True
@@ -129,14 +143,14 @@ class ExceptionCollector:
129
143
  func(*args, **kwargs)
130
144
  return False
131
145
  except BaseException as exc:
132
- self._exceptions.append(exc)
146
+ fast_append_exception(self._exceptions, exc)
133
147
  if self._stop_on_first:
134
148
  raise
135
149
  return True
136
150
 
137
151
  def add(self, exc: BaseException) -> None:
138
152
  """Manually add an exception."""
139
- self._exceptions.append(exc)
153
+ fast_append_exception(self._exceptions, exc)
140
154
  if self._stop_on_first:
141
155
  raise exc
142
156
 
@@ -107,11 +107,19 @@ class fast_ignore:
107
107
  >>> with fast_ignore(KeyError):
108
108
  ... d = {}
109
109
  ... _ = d["missing"]
110
+
111
+ .. deprecated:: 3.0.0
112
+ This class is deprecated as it is functionally redundant.
110
113
  """
111
114
 
112
115
  __slots__ = ("_excs",)
113
116
 
114
117
  def __init__(self, *excs: ExceptionType) -> None:
118
+ warnings.warn(
119
+ "fast_ignore is deprecated as it is functionally redundant.",
120
+ DeprecationWarning,
121
+ stacklevel=2,
122
+ )
115
123
  for exc in excs:
116
124
  if not isinstance(exc, type) or not issubclass(exc, BaseException):
117
125
  raise TypeError(f"Expected Exception subclass, got {exc!r}")
@@ -1,5 +1,6 @@
1
1
  """Utilities for raising exceptions."""
2
2
 
3
+ import sys
3
4
  from contextlib import contextmanager
4
5
  from itertools import product
5
6
  from typing import Callable, Any
@@ -107,45 +108,47 @@ def assert_raises(
107
108
  )
108
109
 
109
110
 
110
- def raises_all(
111
- errors: Iterable[type[Exception]],
112
- msgs: Iterable[str],
113
- baseerror: type[Exception] = Exception,
114
- group_msg: str = "multiple errors",
115
- ) -> None:
116
- """Validate exception types and raise all (error, message) combinations as an ExceptionGroup.
117
-
118
- Args:
119
- errors: An iterable of exception types to include in the group.
120
- msgs: An iterable of message strings to pair with each exception type.
121
- baseerror: The base exception class that every type in *errors* must
122
- inherit from. Defaults to `Exception`.
123
- group_msg: The message attached to the `ExceptionGroup` itself.
124
- Defaults to ``"multiple errors"``.
125
-
126
- Raises:
127
- TypeError: If any type in *errors* is not a subclass of *baseerror*.
128
- ExceptionGroup: Containing one ``errors[i](msgs[j])`` instance for
129
- every ``(i, j)`` pair in the Cartesian product.
130
-
131
- Example:
132
- >>> raises_all([ValueError, TypeError], ["bad input"])
133
- Traceback (most recent call last):
134
- ...
135
- ExceptionGroup: multiple errors (2 sub-exceptions)
136
- """
137
- # NOTE: Computes the Cartesian product of *errors* x *msgs*, validates that every
138
- # error type is a subclass of *baseerror*, then raises a single
139
- # `ExceptionGroup` containing one instantiated exception per pair.
140
- # If the product is empty (either iterable is empty) the function returns
141
- # without raising.
142
- pairs = _warp_list_product(errors, msgs)
143
- if not pairs:
144
- return
145
- for error, _ in pairs:
146
- if not _is_base_subclass(error=error, baseerror=baseerror):
147
- raise TypeError(f"{error!r} is not a subclass of {baseerror.__name__}")
148
- raise ExceptionGroup(group_msg, [error(msg) for error, msg in pairs])
111
+ if sys.version_info >= (3, 11):
112
+
113
+ def raises_all(
114
+ errors: Iterable[type[Exception]],
115
+ msgs: Iterable[str],
116
+ baseerror: type[Exception] = Exception,
117
+ group_msg: str = "multiple errors",
118
+ ) -> None:
119
+ """Validate exception types and raise all (error, message) combinations as an ExceptionGroup.
120
+
121
+ Args:
122
+ errors: An iterable of exception types to include in the group.
123
+ msgs: An iterable of message strings to pair with each exception type.
124
+ baseerror: The base exception class that every type in *errors* must
125
+ inherit from. Defaults to `Exception`.
126
+ group_msg: The message attached to the `ExceptionGroup` itself.
127
+ Defaults to ``"multiple errors"``.
128
+
129
+ Raises:
130
+ TypeError: If any type in *errors* is not a subclass of *baseerror*.
131
+ ExceptionGroup: Containing one ``errors[i](msgs[j])`` instance for
132
+ every ``(i, j)`` pair in the Cartesian product.
133
+
134
+ Example:
135
+ >>> raises_all([ValueError, TypeError], ["bad input"])
136
+ Traceback (most recent call last):
137
+ ...
138
+ ExceptionGroup: multiple errors (2 sub-exceptions)
139
+ """
140
+ # NOTE: Computes the Cartesian product of *errors* x *msgs*, validates that every
141
+ # error type is a subclass of *baseerror*, then raises a single
142
+ # `ExceptionGroup` containing one instantiated exception per pair.
143
+ # If the product is empty (either iterable is empty) the function returns
144
+ # without raising.
145
+ pairs = _warp_list_product(errors, msgs)
146
+ if not pairs:
147
+ return
148
+ for error, _ in pairs:
149
+ if not _is_base_subclass(error=error, baseerror=baseerror):
150
+ raise TypeError(f"{error!r} is not a subclass of {baseerror.__name__}")
151
+ raise ExceptionGroup(group_msg, [error(msg) for error, msg in pairs])
149
152
 
150
153
 
151
154
  @contextmanager
@@ -1,6 +1,12 @@
1
1
  """Public type aliases for errortools exception classes."""
2
2
 
3
- from typing import TypeAlias, Union
3
+ import sys
4
+
5
+ if sys.version_info <= (3, 10):
6
+ from typing_extensions import TypeAlias
7
+ else:
8
+ from typing import TypeAlias
9
+ from typing import Union
4
10
 
5
11
  from .classes.errorcodes import (
6
12
  PureBaseException,
@@ -57,16 +63,28 @@ AnyErrorCode: TypeAlias = Union[
57
63
  """Union of all predefined error-code subclasses."""
58
64
 
59
65
  InputError: TypeAlias = InvalidInputError
60
- """Alias for `InvalidInputError` (1001)."""
66
+ """Alias for `InvalidInputError` (1001).
67
+
68
+ .. deprecated:: 3.0.0
69
+ This type alias is deprecated as it is redundant."""
61
70
 
62
71
  AccessError: TypeAlias = AccessDeniedError
63
- """Alias for `AccessDeniedError` (2001)."""
72
+ """Alias for `AccessDeniedError` (2001).
73
+
74
+ .. deprecated:: 3.0.0
75
+ This type alias is deprecated as it is redundant."""
64
76
 
65
77
  LookupError_: TypeAlias = NotFoundError
66
- """Alias for `NotFoundError` (3001). Trailing underscore avoids shadowing builtins."""
78
+ """Alias for `NotFoundError` (3001). Trailing underscore avoids shadowing builtins.
79
+
80
+ .. deprecated:: 3.0.0
81
+ This type alias is deprecated as it is redundant."""
67
82
 
68
83
  RuntimeError_: TypeAlias = Union[RuntimeFailure, TimeoutFailure]
69
- """Union of runtime-related errors: `RuntimeFailure` (4001) and `TimeoutFailure` (4002)."""
84
+ """Union of runtime-related errors: `RuntimeFailure` (4001) and `TimeoutFailure` (4002).
85
+
86
+ .. deprecated:: 3.0.0
87
+ This type alias is deprecated as it is redundant."""
70
88
 
71
89
  # ---------------------------------------------------------------------------
72
90
  # More type aliases
@@ -1,5 +1,5 @@
1
- __version__: str = "2.5.0"
2
- __version_tuple__: tuple[int, int, int] = (2, 5, 0)
1
+ __version__: str = "3.1.0"
2
+ __version_tuple__: tuple[int, int, int] = (3, 1, 0)
3
3
  __commit_id__: str | None = None
4
4
 
5
5
  version = __version__
@@ -39,14 +39,7 @@ from _errortools.classes.warn import (
39
39
  RuntimeBehaviourWarning,
40
40
  ConfigurationWarning,
41
41
  )
42
- from _errortools.methods import (
43
- ErrorSetAttrMixin,
44
- ErrorAttrCheckMixin,
45
- ErrorAttrDeletionMixin,
46
- ErrorAttrMixin,
47
- )
48
42
  from _errortools.classes.abc import (
49
- ErrorAttrable,
50
43
  ErrorCodeable,
51
44
  Warnable,
52
45
  Raiseable,
@@ -130,11 +123,6 @@ __all__ = [
130
123
  "ResourceUsageWarning",
131
124
  "RuntimeBehaviourWarning",
132
125
  "ConfigurationWarning",
133
- "ErrorAttrMixin",
134
- "ErrorAttrDeletionMixin",
135
- "ErrorAttrCheckMixin",
136
- "ErrorSetAttrMixin",
137
- "ErrorAttrable",
138
126
  "ErrorCodeable",
139
127
  "Warnable",
140
128
  "Raiseable",
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: errortools
3
- Version: 2.5.0
3
+ Version: 3.1.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,6 +8,8 @@ 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
@@ -16,7 +18,7 @@ Classifier: Programming Language :: Python :: 3.14
16
18
  Classifier: Programming Language :: Python :: 3.15
17
19
  Classifier: Operating System :: OS Independent
18
20
  Classifier: Typing :: Typed
19
- Requires-Python: >=3.10
21
+ Requires-Python: >=3.8
20
22
  Description-Content-Type: text/markdown
21
23
  License-File: LICENSE.txt
22
24
  License-File: AUTHORS.txt
@@ -44,6 +46,7 @@ A lightweight Python exception handling utility library.
44
46
  ![This month commits](https://img.shields.io/github/commit-activity/m/more-abc/errortools)
45
47
  ![Past year commits](https://img.shields.io/github/commit-activity/y/more-abc/errortools)
46
48
  ![Total commits badge](https://img.shields.io/github/commit-activity/t/more-abc/errortools)
49
+ ![OS support](https://img.shields.io/badge/OS-macOS%20Linux%20Windows-red)
47
50
 
48
51
  ## Features
49
52
  - **Raise Exceptions**: `raises()`, `raises_all()`, `reraise()` — batch raising and exception conversion
@@ -51,7 +54,6 @@ A lightweight Python exception handling utility library.
51
54
  - **Future Utilities**: `super_fast_catch()`, `super_fast_reraise()`, `ExceptionCollector` — lightweight exception handling for high-performance scenarios
52
55
  - **Exception Caching**: `error_cache` — cache exceptions raised by functions (similar to `lru_cache`)
53
56
  - **Custom Exceptions**: `PureBaseException`, `ContextException`, `BaseErrorCodes`, `BaseWarning` — structured exception classes with error codes, trace IDs, and context
54
- - **Attribute Error Mixin**: Customize error behavior for attribute access, assignment, and deletion
55
57
  - **Type Aliases**: `ExceptionType`, `AnyErrorCode`, `BaseErrorCodesType`, and more
56
58
  - **Logging**: `logger` — loguru-inspired structured logger with leveled output, multiple sinks, context binding, and exception capture
57
59
 
@@ -95,7 +97,7 @@ assert err.traceback # full formatted traceback string
95
97
  | `exception` | `Exception \| None` | The original exception instance |
96
98
  | `traceback` | `str \| None` | Formatted traceback string for debugging |
97
99
 
98
- ## Examples
100
+ ## Sorry, but there was more code examples!
99
101
 
100
102
  ```python
101
103
  # ── ignore as a decorator ──
@@ -0,0 +1,47 @@
1
+ AUTHORS.txt
2
+ LICENSE.txt
3
+ README.md
4
+ setup.py
5
+ _errortools/__init__.py
6
+ _errortools/_cli.py
7
+ _errortools/_speedup.c
8
+ _errortools/cli.py
9
+ _errortools/const.py
10
+ _errortools/errno.py
11
+ _errortools/future.py
12
+ _errortools/ignore.py
13
+ _errortools/metadata.py
14
+ _errortools/partial.py
15
+ _errortools/py.typed
16
+ _errortools/raises.py
17
+ _errortools/typing.py
18
+ _errortools/version.py
19
+ errortools/__init__.py
20
+ errortools/__main__.py
21
+ errortools/future.py
22
+ errortools/logging.py
23
+ errortools/partial.py
24
+ errortools.egg-info/PKG-INFO
25
+ errortools.egg-info/SOURCES.txt
26
+ errortools.egg-info/dependency_links.txt
27
+ errortools.egg-info/entry_points.txt
28
+ errortools.egg-info/requires.txt
29
+ errortools.egg-info/top_level.txt
30
+ testing/__init__.py
31
+ testing/__main__.py
32
+ testing/conftest.py
33
+ testing/run_tests.py
34
+ testing/test_abc.py
35
+ testing/test_const.py
36
+ testing/test_decorator.py
37
+ testing/test_descriptor.py
38
+ testing/test_errno.py
39
+ testing/test_errorcodes.py
40
+ testing/test_future.py
41
+ testing/test_groups.py
42
+ testing/test_ignore.py
43
+ testing/test_logging.py
44
+ testing/test_partials.py
45
+ testing/test_raises.py
46
+ testing/test_typing.py
47
+ testing/test_warnings.py
@@ -1,3 +1,2 @@
1
1
  [console_scripts]
2
2
  logger = _errortools.cli:main
3
- python -m errortools = _errortools.cli:main
@@ -1,3 +1,3 @@
1
1
  _errortools
2
2
  errortools
3
- tests
3
+ testing
@@ -0,0 +1,58 @@
1
+ import sys
2
+
3
+ from setuptools import setup, Extension
4
+
5
+ _VERSION: str = "3.1.0"
6
+ _CLI_INFO: dict[str, list[str]] = {
7
+ "console_scripts": [
8
+ # "python -m errortools = _errortools.cli:main",
9
+ "logger = _errortools.cli:main",
10
+ ]
11
+ }
12
+ _DESCRIPTION: str = (
13
+ "errortools - a toolset for working with Python exceptions and warnings and logging."
14
+ )
15
+ _URL: str = "https://github.com/more-abc/errortools"
16
+ _AUTHOR: str = "Evan Yang"
17
+ _AUTHOR_EMAIL: str = "quantbit@126.com"
18
+ _LICENSE: str = "MIT"
19
+
20
+ # C extension for performance
21
+ _speedup_module = Extension(
22
+ "_errortools._speedup",
23
+ sources=["_errortools/_speedup.c"],
24
+ extra_compile_args=["/O2"] if sys.platform == "win32" else ["-O3", "-march=native"],
25
+ )
26
+
27
+ setup(
28
+ name="errortools",
29
+ version=_VERSION,
30
+ description=_DESCRIPTION,
31
+ long_description=open("README.md", encoding="utf-8").read(),
32
+ long_description_content_type="text/markdown",
33
+ url=_URL,
34
+ author=_AUTHOR,
35
+ author_email=_AUTHOR_EMAIL,
36
+ license=_LICENSE,
37
+ classifiers=[
38
+ "License :: OSI Approved :: MIT License",
39
+ "Programming Language :: Python :: 3",
40
+ "Programming Language :: Python :: 3.8",
41
+ "Programming Language :: Python :: 3.9",
42
+ "Programming Language :: Python :: 3.10",
43
+ "Programming Language :: Python :: 3.11",
44
+ "Programming Language :: Python :: 3.12",
45
+ "Programming Language :: Python :: 3.13",
46
+ "Programming Language :: Python :: 3.14",
47
+ "Programming Language :: Python :: 3.15",
48
+ "Operating System :: OS Independent",
49
+ "Typing :: Typed",
50
+ ],
51
+ packages=["_errortools", "errortools", "testing"],
52
+ package_data={"errortools": ["py.typed"]},
53
+ include_package_data=True,
54
+ python_requires=">=3.8",
55
+ install_requires=["namebyauthor==1.0.0", "typing_extensions>=4.8.0"],
56
+ entry_points=_CLI_INFO,
57
+ ext_modules=[_speedup_module],
58
+ )