errortools 2.5.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.
Files changed (76) hide show
  1. {errortools-2.5.0/errortools.egg-info → errortools-3.0.0}/PKG-INFO +4 -3
  2. {errortools-2.5.0 → errortools-3.0.0}/README.md +0 -1
  3. errortools-3.0.0/_errortools/_speedup.c +58 -0
  4. {errortools-2.5.0 → errortools-3.0.0}/_errortools/classes/abc.py +0 -148
  5. {errortools-2.5.0 → errortools-3.0.0}/_errortools/classes/group.py +41 -38
  6. {errortools-2.5.0 → errortools-3.0.0}/_errortools/future.py +24 -10
  7. {errortools-2.5.0 → errortools-3.0.0}/_errortools/logging/record.py +8 -1
  8. {errortools-2.5.0 → errortools-3.0.0}/_errortools/logging/sink.py +8 -1
  9. {errortools-2.5.0 → errortools-3.0.0}/_errortools/raises.py +42 -39
  10. {errortools-2.5.0 → errortools-3.0.0}/_errortools/typing.py +7 -1
  11. {errortools-2.5.0 → errortools-3.0.0}/_errortools/version.py +2 -2
  12. {errortools-2.5.0 → errortools-3.0.0}/_errortools/wrappers/cache.py +7 -1
  13. {errortools-2.5.0 → errortools-3.0.0}/_errortools/wrappers/ignore.py +8 -1
  14. {errortools-2.5.0 → errortools-3.0.0}/errortools/__init__.py +0 -12
  15. {errortools-2.5.0 → errortools-3.0.0/errortools.egg-info}/PKG-INFO +4 -3
  16. {errortools-2.5.0 → errortools-3.0.0}/errortools.egg-info/SOURCES.txt +1 -6
  17. errortools-3.0.0/setup.py +58 -0
  18. {errortools-2.5.0 → errortools-3.0.0}/tests/__init__.py +1 -1
  19. {errortools-2.5.0 → errortools-3.0.0}/tests/test_abc.py +0 -4
  20. {errortools-2.5.0 → errortools-3.0.0}/tests/test_const.py +0 -5
  21. {errortools-2.5.0 → errortools-3.0.0}/tests/test_decorator.py +0 -5
  22. {errortools-2.5.0 → errortools-3.0.0}/tests/test_descriptor.py +0 -5
  23. {errortools-2.5.0 → errortools-3.0.0}/tests/test_errno.py +0 -5
  24. {errortools-2.5.0 → errortools-3.0.0}/tests/test_errorcodes.py +0 -5
  25. {errortools-2.5.0 → errortools-3.0.0}/tests/test_future.py +0 -6
  26. errortools-3.0.0/tests/test_groups.py +128 -0
  27. {errortools-2.5.0 → errortools-3.0.0}/tests/test_ignore.py +0 -5
  28. {errortools-2.5.0 → errortools-3.0.0}/tests/test_logging.py +0 -5
  29. {errortools-2.5.0 → errortools-3.0.0}/tests/test_partials.py +0 -5
  30. {errortools-2.5.0 → errortools-3.0.0}/tests/test_raises.py +36 -37
  31. {errortools-2.5.0 → errortools-3.0.0}/tests/test_typing.py +0 -5
  32. {errortools-2.5.0 → errortools-3.0.0}/tests/test_warnings.py +0 -5
  33. errortools-2.5.0/_errortools/methods/__init__.py +0 -11
  34. errortools-2.5.0/_errortools/methods/errorattr.py +0 -37
  35. errortools-2.5.0/_errortools/methods/errordelattr.py +0 -35
  36. errortools-2.5.0/_errortools/methods/errorhasattr.py +0 -27
  37. errortools-2.5.0/_errortools/methods/errorsetattr.py +0 -40
  38. errortools-2.5.0/setup.py +0 -79
  39. errortools-2.5.0/tests/test_groups.py +0 -129
  40. errortools-2.5.0/tests/test_mixins.py +0 -256
  41. {errortools-2.5.0 → errortools-3.0.0}/AUTHORS.txt +0 -0
  42. {errortools-2.5.0 → errortools-3.0.0}/LICENSE.txt +0 -0
  43. {errortools-2.5.0 → errortools-3.0.0}/_errortools/__init__.py +0 -0
  44. {errortools-2.5.0 → errortools-3.0.0}/_errortools/_cli.py +0 -0
  45. {errortools-2.5.0 → errortools-3.0.0}/_errortools/classes/__init__.py +0 -0
  46. {errortools-2.5.0 → errortools-3.0.0}/_errortools/classes/errorcodes.py +0 -0
  47. {errortools-2.5.0 → errortools-3.0.0}/_errortools/classes/warn.py +0 -0
  48. {errortools-2.5.0 → errortools-3.0.0}/_errortools/cli.py +0 -0
  49. {errortools-2.5.0 → errortools-3.0.0}/_errortools/const.py +0 -0
  50. {errortools-2.5.0 → errortools-3.0.0}/_errortools/decorator/__init__.py +0 -0
  51. {errortools-2.5.0 → errortools-3.0.0}/_errortools/decorator/cache.py +0 -0
  52. {errortools-2.5.0 → errortools-3.0.0}/_errortools/decorator/deprecated.py +0 -0
  53. {errortools-2.5.0 → errortools-3.0.0}/_errortools/descriptor/__init__.py +0 -0
  54. {errortools-2.5.0 → errortools-3.0.0}/_errortools/descriptor/errormsg.py +0 -0
  55. {errortools-2.5.0 → errortools-3.0.0}/_errortools/descriptor/nonblankmsg.py +0 -0
  56. {errortools-2.5.0 → errortools-3.0.0}/_errortools/errno.py +0 -0
  57. {errortools-2.5.0 → errortools-3.0.0}/_errortools/ignore.py +0 -0
  58. {errortools-2.5.0 → errortools-3.0.0}/_errortools/logging/__init__.py +0 -0
  59. {errortools-2.5.0 → errortools-3.0.0}/_errortools/logging/base.py +0 -0
  60. {errortools-2.5.0 → errortools-3.0.0}/_errortools/logging/level.py +0 -0
  61. {errortools-2.5.0 → errortools-3.0.0}/_errortools/logging/logger.py +0 -0
  62. {errortools-2.5.0 → errortools-3.0.0}/_errortools/metadata.py +0 -0
  63. {errortools-2.5.0 → errortools-3.0.0}/_errortools/partial.py +0 -0
  64. {errortools-2.5.0 → errortools-3.0.0}/_errortools/py.typed +0 -0
  65. {errortools-2.5.0 → errortools-3.0.0}/_errortools/wrappers/__init__.py +0 -0
  66. {errortools-2.5.0 → errortools-3.0.0}/errortools/__main__.py +0 -0
  67. {errortools-2.5.0 → errortools-3.0.0}/errortools/future.py +0 -0
  68. {errortools-2.5.0 → errortools-3.0.0}/errortools/logging.py +0 -0
  69. {errortools-2.5.0 → errortools-3.0.0}/errortools/partial.py +0 -0
  70. {errortools-2.5.0 → errortools-3.0.0}/errortools.egg-info/dependency_links.txt +0 -0
  71. {errortools-2.5.0 → errortools-3.0.0}/errortools.egg-info/entry_points.txt +0 -0
  72. {errortools-2.5.0 → errortools-3.0.0}/errortools.egg-info/requires.txt +0 -0
  73. {errortools-2.5.0 → errortools-3.0.0}/errortools.egg-info/top_level.txt +0 -0
  74. {errortools-2.5.0 → errortools-3.0.0}/setup.cfg +0 -0
  75. {errortools-2.5.0 → errortools-3.0.0}/tests/conftest.py +0 -0
  76. {errortools-2.5.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: 2.5.0
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,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
@@ -51,7 +53,6 @@ A lightweight Python exception handling utility library.
51
53
  - **Future Utilities**: `super_fast_catch()`, `super_fast_reraise()`, `ExceptionCollector` — lightweight exception handling for high-performance scenarios
52
54
  - **Exception Caching**: `error_cache` — cache exceptions raised by functions (similar to `lru_cache`)
53
55
  - **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
56
  - **Type Aliases**: `ExceptionType`, `AnyErrorCode`, `BaseErrorCodesType`, and more
56
57
  - **Logging**: `logger` — loguru-inspired structured logger with leveled output, multiple sinks, context binding, and exception capture
57
58
 
@@ -15,7 +15,6 @@ A lightweight Python exception handling utility library.
15
15
  - **Future Utilities**: `super_fast_catch()`, `super_fast_reraise()`, `ExceptionCollector` — lightweight exception handling for high-performance scenarios
16
16
  - **Exception Caching**: `error_cache` — cache exceptions raised by functions (similar to `lru_cache`)
17
17
  - **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
18
  - **Type Aliases**: `ExceptionType`, `AnyErrorCode`, `BaseErrorCodesType`, and more
20
19
  - **Logging**: `logger` — loguru-inspired structured logger with leveled output, multiple sinks, context binding, and exception capture
21
20
 
@@ -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
+ }
@@ -11,13 +11,6 @@ if sys.version_info >= (3, 15):
11
11
  else:
12
12
  from typing_extensions import disjoint_base
13
13
 
14
- from ..methods import (
15
- ErrorAttrMixin,
16
- ErrorAttrCheckMixin,
17
- ErrorAttrDeletionMixin,
18
- ErrorSetAttrMixin,
19
- )
20
-
21
14
 
22
15
  def _check_methods(C: type[Any], *methods: str) -> Union[bool, Literal[NotImplemented]]: # type: ignore
23
16
  """Check methods in `C`. If has, return `True`, else `NotImplemented`."""
@@ -36,147 +29,6 @@ def _check_methods(C: type[Any], *methods: str) -> Union[bool, Literal[NotImplem
36
29
  return True
37
30
 
38
31
 
39
- @disjoint_base
40
- class ErrorAttrable(ABC):
41
- """
42
- Abstract Base Class (ABC) for classes supporting custom attribute error handling.
43
-
44
- This class follows the design pattern of `collections.abc` (e.g., Iterable, Mapping):
45
- - Uses `__subclasshook__` + `_check_methods` to validate subclass compliance
46
- - Enforces implementation of attribute error handling methods via abstract methods
47
- - Implements native attribute magic methods to forward errors to custom handlers
48
-
49
- Core behavior:
50
- When attribute operations (get/delete/check/set) fail, the corresponding native
51
- magic methods automatically invoke custom error handling methods implemented by subclasses.
52
- """
53
-
54
- __slots__ = ()
55
-
56
- @classmethod
57
- def __subclasshook__(cls, C: type[Any]) -> Union[bool, Literal[NotImplemented]]: # type: ignore
58
- """
59
- Check if a class is a subclass of ErrorAttrable (per `collections.abc` style).
60
-
61
- This method enables `issubclass()` to recognize classes that implement the core
62
- __errorattr__ method (base requirement), matching the behavior of standard ABCs.
63
-
64
- Args:
65
- C: The class to check for compliance with ErrorAttrable interface
66
-
67
- Returns:
68
- True if C implements __errorattr__, NotImplemented otherwise
69
- """
70
- if cls is ErrorAttrable:
71
- return _check_methods(C, "__errorattr__")
72
- return NotImplemented
73
-
74
- def __getattr__(self, name: str) -> Any:
75
- """
76
- Native magic method: Automatically invoked for missing attribute access.
77
-
78
- Forwards the attribute lookup failure to the custom `__errorattr__` method.
79
- """
80
- return self.__errorattr__(name)
81
-
82
- @abstractmethod
83
- def __errorattr__(self, name: str) -> Any:
84
- """
85
- Abstract method for custom missing attribute handling (MUST be implemented).
86
-
87
- Args:
88
- name: Name of the missing attribute being accessed
89
-
90
- Raises:
91
- NotImplementedError: If not overridden
92
- AttributeError: Recommended error type for missing attributes
93
- """
94
- raise NotImplementedError(
95
- "Subclasses of ErrorAttrable must implement __errorattr__(self, name: str).\n"
96
- "See `collections.abc` for similar abstract method requirements (e.g., __iter__ for Iterable)."
97
- )
98
-
99
- def __delattr__(self, name: str) -> None:
100
- """
101
- Native magic method: Automatically invoked for attribute deletion errors.
102
-
103
- Forwards to __errordelattr__ if implemented, else raises standard error.
104
- """
105
- if hasattr(self, "__errordelattr__"):
106
- self.__errordelattr__(name)
107
- else:
108
- super().__delattr__(name)
109
-
110
- def __errordelattr__(self, name: str) -> None:
111
- """
112
- Custom handler for attribute deletion errors (OPTIONAL to implement).
113
-
114
- Args:
115
- name: Name of the attribute being deleted
116
- """
117
- raise NotImplementedError(
118
- "Subclasses of ErrorAttrable must implement __errordelattr__(self, name: str).\n"
119
- "See `collections.abc` for similar abstract method requirements (e.g., __iter__ for Iterable)."
120
- )
121
-
122
- def __contains__(self, name: str) -> bool:
123
- """
124
- Alternative to __hasattr__: Check if attribute exists (customizable).
125
-
126
- Forwards to __errorhasattr__ if implemented, else uses standard check.
127
- """
128
- if hasattr(self, "__errorhasattr__"):
129
- return self.__errorhasattr__(name)
130
- else:
131
- return hasattr(super(), name)
132
-
133
- def __errorhasattr__(self, name: str) -> bool:
134
- """
135
- Custom handler for attribute existence checks (OPTIONAL to implement).
136
-
137
- Args:
138
- name: Name of the attribute to check
139
-
140
- Returns:
141
- bool: True if attribute exists (custom logic), False otherwise
142
- """
143
- raise NotImplementedError(
144
- "Subclasses of ErrorAttrable must implement __errorhasattr__(self, name: str).\n"
145
- "See `collections.abc` for similar abstract method requirements (e.g., __iter__ for Iterable)."
146
- )
147
-
148
- def __setattr__(self, name: str, value: Any) -> None:
149
- """
150
- Native magic method: Automatically invoked for attribute setting errors.
151
-
152
- Forwards to __errorsetattr__ if implemented, else uses standard setting.
153
- """
154
- if hasattr(self, "__errorsetattr__"):
155
- self.__errorsetattr__(name, value)
156
- else:
157
- super().__setattr__(name, value)
158
-
159
- def __errorsetattr__(self, name: str, value: Any) -> None:
160
- """
161
- Custom handler for attribute setting errors (OPTIONAL to implement).
162
-
163
- Args:
164
- name: Name of the attribute to set
165
- value: Value to assign to the attribute
166
- """
167
- raise NotImplementedError(
168
- "Subclasses of ErrorAttrable must implement __errorsetattr__(self, name: str, value: Any).\n"
169
- "See `collections.abc` for similar abstract method requirements (e.g., __iter__ for Iterable)."
170
- )
171
-
172
-
173
- # register four Mixin's
174
- ErrorAttrable.register(ErrorAttrMixin)
175
- ErrorAttrable.register(ErrorAttrDeletionMixin)
176
- ErrorAttrable.register(ErrorAttrCheckMixin)
177
- ErrorAttrable.register(ErrorSetAttrMixin)
178
-
179
-
180
32
  # ----------------------------------------------------------------------
181
33
  # ErrorCodeable
182
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
- class GroupErrors(BaseGroup):
71
- """A collector that accumulates exceptions and raises them as an ExceptionGroup.
71
+ if sys.version_info >= (3, 11):
72
72
 
73
- Call `collect` to add exceptions one by one, then `raise_group`
74
- to raise them all at once. Use `errors` to inspect what has been
75
- collected without raising.
73
+ class GroupErrors(BaseGroup):
74
+ """A collector that accumulates exceptions and raises them as an ExceptionGroup.
76
75
 
77
- Example:
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
- >>> g = GroupErrors("validation failed")
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
- def __init__(self, group_msg: str = "multiple errors") -> None:
89
- super().__init__(group_msg)
90
- self._errors: list[Exception] = []
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
- @property
93
- def errors(self) -> list[Exception]:
94
- """A copy of the collected exceptions."""
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
- def collect(self, exc: Exception) -> None:
98
- """Add *exc* to the group without raising it.
95
+ @property
96
+ def errors(self) -> list[Exception]:
97
+ """A copy of the collected exceptions."""
98
+ return list(self._errors)
99
99
 
100
- Args:
101
- exc: The exception instance to collect.
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
- def clear(self) -> None:
106
- """Remove all collected exceptions."""
107
- self._errors.clear()
103
+ Args:
104
+ exc: The exception instance to collect.
105
+ """
106
+ self._errors.append(exc)
108
107
 
109
- def raise_group(self) -> None:
110
- """Raise all collected exceptions as an `ExceptionGroup`.
108
+ def clear(self) -> None:
109
+ """Remove all collected exceptions."""
110
+ self._errors.clear()
111
111
 
112
- Does nothing if no exceptions have been collected.
112
+ def raise_group(self) -> None:
113
+ """Raise all collected exceptions as an `ExceptionGroup`.
113
114
 
114
- Raises:
115
- ExceptionGroup: Containing every exception added via `collect`.
116
- """
117
- if self._errors:
118
- raise ExceptionGroup(self.group_msg, self._errors)
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)
@@ -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
 
@@ -6,10 +6,17 @@ import sys
6
6
  import threading
7
7
  import traceback
8
8
  from dataclasses import dataclass, field
9
- from datetime import datetime, UTC
9
+ from datetime import datetime
10
10
  from types import TracebackType
11
11
  from typing import Any
12
12
 
13
+ if sys.version_info >= (3, 9):
14
+ from datetime import UTC
15
+ else:
16
+ from datetime import timezone
17
+
18
+ UTC = timezone.utc
19
+
13
20
  from .level import Level
14
21
 
15
22
 
@@ -5,10 +5,17 @@ from __future__ import annotations
5
5
  import sys
6
6
  import threading
7
7
  from abc import ABC, abstractmethod
8
- from datetime import datetime, UTC
8
+ from datetime import datetime
9
9
  from pathlib import Path
10
10
  from typing import IO, Any
11
11
 
12
+ if sys.version_info >= (3, 9):
13
+ from datetime import UTC
14
+ else:
15
+ from datetime import timezone
16
+
17
+ UTC = timezone.utc
18
+
12
19
  from .level import Level
13
20
  from .record import Record
14
21
 
@@ -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,
@@ -1,5 +1,5 @@
1
- __version__: str = "2.5.0"
2
- __version_tuple__: tuple[int, int, int] = (2, 5, 0)
1
+ __version__: str = "3.0.0"
2
+ __version_tuple__: tuple[int, int, int] = (3, 0, 0)
3
3
  __commit_id__: str | None = None
4
4
 
5
5
  version = __version__
@@ -1,6 +1,12 @@
1
1
  from collections import OrderedDict
2
2
  from collections.abc import Hashable, Callable
3
- from typing import Any, Generic, TypeVar, Optional, TypeAlias, NamedTuple
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 Any, Generic, NamedTuple, Optional, TypeVar
4
10
 
5
11
  _T = TypeVar("_T", bound=Callable[..., Any])
6
12
  _Key: TypeAlias = tuple[
@@ -1,6 +1,13 @@
1
1
  import traceback
2
2
  from collections.abc import Callable
3
- from typing import Any, Generic, TypeVar, Optional, TypeAlias
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
+
10
+ from typing import Any, Generic, TypeVar, Optional
4
11
 
5
12
  _T = TypeVar("_T", bound=Callable[..., Any])
6
13
  _ExcType: TypeAlias = type[Exception]
@@ -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",