errortools 1.2.0__tar.gz → 2.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 (69) hide show
  1. errortools-2.0.0/AUTHORS.txt +3 -0
  2. {errortools-1.2.0/errortools.egg-info → errortools-2.0.0}/PKG-INFO +42 -11
  3. {errortools-1.2.0 → errortools-2.0.0}/README.md +39 -10
  4. errortools-2.0.0/_errortools/_cli.py +32 -0
  5. {errortools-1.2.0 → errortools-2.0.0}/_errortools/classes/abc.py +351 -351
  6. {errortools-1.2.0 → errortools-2.0.0}/_errortools/classes/group.py +118 -118
  7. {errortools-1.2.0 → errortools-2.0.0}/_errortools/cli.py +120 -85
  8. errortools-2.0.0/_errortools/const.py +10 -0
  9. errortools-2.0.0/_errortools/decorator/__init__.py +1 -0
  10. {errortools-1.2.0/_errortools → errortools-2.0.0/_errortools/decorator}/cache.py +82 -81
  11. errortools-2.0.0/_errortools/decorator/deprecated.py +33 -0
  12. errortools-2.0.0/_errortools/ignore.py +284 -0
  13. {errortools-1.2.0 → errortools-2.0.0}/_errortools/logging/base.py +2 -2
  14. {errortools-1.2.0 → errortools-2.0.0}/_errortools/logging/sink.py +1 -1
  15. {errortools-1.2.0 → errortools-2.0.0}/_errortools/metadata.py +7 -0
  16. errortools-2.0.0/_errortools/partial.py +110 -0
  17. {errortools-1.2.0 → errortools-2.0.0}/_errortools/raises.py +183 -166
  18. {errortools-1.2.0 → errortools-2.0.0}/_errortools/version.py +7 -7
  19. {errortools-1.2.0 → errortools-2.0.0}/errortools/__init__.py +166 -152
  20. {errortools-1.2.0 → errortools-2.0.0/errortools.egg-info}/PKG-INFO +42 -11
  21. {errortools-1.2.0 → errortools-2.0.0}/errortools.egg-info/SOURCES.txt +10 -3
  22. errortools-2.0.0/errortools.egg-info/entry_points.txt +3 -0
  23. errortools-2.0.0/errortools.egg-info/requires.txt +1 -0
  24. {errortools-1.2.0 → errortools-2.0.0}/setup.py +35 -34
  25. errortools-2.0.0/tests/__init__.py +12 -0
  26. errortools-2.0.0/tests/run_tests.py +19 -0
  27. {errortools-1.2.0 → errortools-2.0.0}/tests/test_abc.py +304 -314
  28. {errortools-1.2.0 → errortools-2.0.0}/tests/test_cache.py +6 -1
  29. errortools-2.0.0/tests/test_const.py +33 -0
  30. errortools-2.0.0/tests/test_decorator.py +85 -0
  31. {errortools-1.2.0 → errortools-2.0.0}/tests/test_descriptor.py +5 -12
  32. {errortools-1.2.0 → errortools-2.0.0}/tests/test_errorcodes.py +6 -1
  33. {errortools-1.2.0 → errortools-2.0.0}/tests/test_groups.py +5 -3
  34. {errortools-1.2.0 → errortools-2.0.0}/tests/test_ignore.py +104 -1
  35. {errortools-1.2.0 → errortools-2.0.0}/tests/test_logging.py +5 -4
  36. {errortools-1.2.0 → errortools-2.0.0}/tests/test_mixins.py +5 -5
  37. errortools-2.0.0/tests/test_partials.py +233 -0
  38. {errortools-1.2.0 → errortools-2.0.0}/tests/test_raises.py +4 -20
  39. {errortools-1.2.0 → errortools-2.0.0}/tests/test_typing.py +6 -8
  40. {errortools-1.2.0 → errortools-2.0.0}/tests/test_warnings.py +5 -0
  41. errortools-1.2.0/AUTHORS.txt +0 -2
  42. errortools-1.2.0/_errortools/ignore.py +0 -155
  43. errortools-1.2.0/_errortools/tools/__init__.py +0 -1
  44. errortools-1.2.0/_errortools/tools/_warps.py +0 -27
  45. errortools-1.2.0/errortools.egg-info/entry_points.txt +0 -2
  46. errortools-1.2.0/tests/__init__.py +0 -3
  47. errortools-1.2.0/tests/run_tests.py +0 -13
  48. {errortools-1.2.0 → errortools-2.0.0}/LICENSE.txt +0 -0
  49. {errortools-1.2.0 → errortools-2.0.0}/_errortools/__init__.py +0 -0
  50. {errortools-1.2.0 → errortools-2.0.0}/_errortools/classes/__init__.py +0 -0
  51. {errortools-1.2.0 → errortools-2.0.0}/_errortools/classes/errorcodes.py +0 -0
  52. {errortools-1.2.0 → errortools-2.0.0}/_errortools/classes/warn.py +0 -0
  53. {errortools-1.2.0 → errortools-2.0.0}/_errortools/future.py +0 -0
  54. {errortools-1.2.0 → errortools-2.0.0}/_errortools/logging/__init__.py +0 -0
  55. {errortools-1.2.0 → errortools-2.0.0}/_errortools/logging/level.py +0 -0
  56. {errortools-1.2.0 → errortools-2.0.0}/_errortools/logging/logger.py +0 -0
  57. {errortools-1.2.0 → errortools-2.0.0}/_errortools/logging/record.py +0 -0
  58. {errortools-1.2.0 → errortools-2.0.0}/_errortools/methods/__init__.py +0 -0
  59. {errortools-1.2.0 → errortools-2.0.0}/_errortools/methods/errorattr.py +0 -0
  60. {errortools-1.2.0 → errortools-2.0.0}/_errortools/methods/errordelattr.py +0 -0
  61. {errortools-1.2.0 → errortools-2.0.0}/_errortools/methods/errorhasattr.py +0 -0
  62. {errortools-1.2.0 → errortools-2.0.0}/_errortools/methods/errorsetattr.py +0 -0
  63. {errortools-1.2.0 → errortools-2.0.0}/_errortools/py.typed +0 -0
  64. {errortools-1.2.0 → errortools-2.0.0}/_errortools/typing.py +0 -0
  65. {errortools-1.2.0 → errortools-2.0.0}/errortools/__main__.py +0 -0
  66. {errortools-1.2.0 → errortools-2.0.0}/errortools.egg-info/dependency_links.txt +0 -0
  67. {errortools-1.2.0 → errortools-2.0.0}/errortools.egg-info/top_level.txt +0 -0
  68. {errortools-1.2.0 → errortools-2.0.0}/setup.cfg +0 -0
  69. {errortools-1.2.0 → errortools-2.0.0}/tests/conftest.py +0 -0
@@ -0,0 +1,3 @@
1
+ aiwonderland
2
+ qorexdev
3
+ vgauraha62
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: errortools
3
- Version: 1.2.0
3
+ Version: 2.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
@@ -19,6 +19,7 @@ Requires-Python: >=3.10
19
19
  Description-Content-Type: text/markdown
20
20
  License-File: LICENSE.txt
21
21
  License-File: AUTHORS.txt
22
+ Requires-Dist: namebyauthor==1.0.0
22
23
  Dynamic: author
23
24
  Dynamic: author-email
24
25
  Dynamic: classifier
@@ -27,6 +28,7 @@ Dynamic: description-content-type
27
28
  Dynamic: home-page
28
29
  Dynamic: license
29
30
  Dynamic: license-file
31
+ Dynamic: requires-dist
30
32
  Dynamic: requires-python
31
33
  Dynamic: summary
32
34
 
@@ -35,7 +37,7 @@ A lightweight Python exception handling utility library.
35
37
 
36
38
  ## Features
37
39
  - **Raise Exceptions**: `raises()`, `raises_all()`, `reraise()` — batch raising and exception conversion
38
- - **Catch & Suppress**: `ignore()`, `ignore_subclass()`, `ignore_warns()`, `fast_ignore()`, `super_fast_ignore()`, `timeout()` — graceful suppression of exceptions and warnings
40
+ - **Catch & Suppress**: `ignore()`, `ignore_subclass()`, `ignore_warns()`, `fast_ignore()`, `super_fast_ignore()`, `timeout()`, `retry()` — graceful suppression of exceptions and warnings, with automatic retry
39
41
  - **Exception Caching**: `error_cache` — cache exceptions raised by functions (similar to `lru_cache`)
40
42
  - **Custom Exceptions**: `PureBaseException`, `ContextException`, `BaseErrorCodes`, `BaseWarning` — structured exception classes with error codes, trace IDs, and context
41
43
  - **Attribute Error Mixin**: Customize error behavior for attribute access, assignment, and deletion
@@ -49,12 +51,12 @@ pip install errortools
49
51
 
50
52
  ---
51
53
 
52
- ## Example
54
+ ## Examples
53
55
 
54
56
  ```python
55
57
  import warnings
56
58
  from errortools import (
57
- ignore, fast_ignore, ignore_subclass, ignore_warns, timeout,
59
+ ignore, fast_ignore, ignore_subclass, ignore_warns, timeout, retry,
58
60
  reraise, raises, raises_all, assert_raises,
59
61
  error_cache,
60
62
  PureBaseException, ContextException, BaseErrorCodes, BaseWarning,
@@ -70,8 +72,22 @@ assert err.name == "KeyError" # exception class name
70
72
  assert err.count == 1 # how many times suppressed
71
73
  assert err.exception # the original KeyError instance
72
74
  assert err.traceback # full formatted traceback string
75
+ ```
76
+
77
+ **Attributes on the returned object:**
78
+
79
+ | Attribute | Type | Description |
80
+ |---|---|---|
81
+ | `be_ignore` | `bool` | `True` if an exception was suppressed |
82
+ | `name` | `str \| None` | Class name of the suppressed exception |
83
+ | `count` | `int` | Number of suppressed exceptions |
84
+ | `exception` | `Exception \| None` | The original exception instance |
85
+ | `traceback` | `str \| None` | Formatted traceback string for debugging |
86
+
87
+ ## Examples
73
88
 
74
- # ignore as a decorator
89
+ ```python
90
+ # ── ignore as a decorator ──
75
91
  @ignore(ValueError, TypeError)
76
92
  def parse(x: str) -> int:
77
93
  return int(x)
@@ -103,14 +119,29 @@ async def fetch_data(url: str) -> bytes:
103
119
 
104
120
  # asyncio.TimeoutError raised automatically if it exceeds 5 s
105
121
 
106
- # ── 6. reraise ── convert exception types on the fly ─────────────────────────
122
+ # ── 6. retry ── automatically retry on failure ───────────────────────────────
123
+ @retry(times=3, on=ConnectionError, delay=1.0)
124
+ def connect(host: str) -> None:
125
+ ... # retried up to 3 times on ConnectionError
126
+
127
+ # works with async functions too
128
+ @retry(times=5, on=TimeoutError, delay=0.5)
129
+ async def fetch(url: str) -> bytes:
130
+ ...
131
+
132
+ # multiple exception types
133
+ @retry(times=2, on=(ValueError, KeyError))
134
+ def parse(data: dict) -> str:
135
+ return data["key"]
136
+
137
+ # ── 7. reraise ── convert exception types on the fly ─────────────────────────
107
138
  with reraise(KeyError, ValueError):
108
139
  raise KeyError("missing key") # → ValueError: 'missing key'
109
140
 
110
141
  with reraise((KeyError, IndexError), RuntimeError):
111
142
  _ = [][99] # → RuntimeError: list index out of range
112
143
 
113
- # ── 7. raises / raises_all ── batch raise ────────────────────────────────────
144
+ # ── 8. raises / raises_all ── batch raise ────────────────────────────────────
114
145
  raises([ValueError], ["bad input"]) # → ValueError: bad input
115
146
 
116
147
  raises_all(
@@ -118,11 +149,11 @@ raises_all(
118
149
  ["bad input"],
119
150
  ) # → ExceptionGroup (2 sub-exceptions)
120
151
 
121
- # ── 8. assert_raises ── assert a callable raises ─────────────────────────────
152
+ # ── 9. assert_raises ── assert a callable raises ─────────────────────────────
122
153
  exc = assert_raises(int, [ValueError], "not-a-number")
123
154
  print(exc) # invalid literal for int() with base 10: 'not-a-number'
124
155
 
125
- # ── 9. error_cache ── cache exceptions by call arguments ─────────────────────
156
+ # ── 10. error_cache ── cache exceptions by call arguments ─────────────────────
126
157
  @error_cache(maxsize=64)
127
158
  def load(user_id: int) -> dict:
128
159
  if user_id < 0:
@@ -135,7 +166,7 @@ with ignore(ValueError):
135
166
  print(load.cache_info()) # CacheInfo(hits=0, misses=1, maxsize=64, currsize=1)
136
167
  load.clear_cache()
137
168
 
138
- # ── 10. Custom exceptions — three layers ──────────────────────────────────────
169
+ # ── 11. Custom exceptions — three layers ──────────────────────────────────────
139
170
 
140
171
  # Layer 1: PureBaseException — code + detail only
141
172
  class AppError(PureBaseException):
@@ -171,7 +202,7 @@ raise BaseErrorCodes.runtime_failure("crash") # RuntimeFailure [
171
202
  raise BaseErrorCodes.timeout_failure() # TimeoutFailure [4002]
172
203
  raise BaseErrorCodes.configuration_error("missing key") # ConfigurationError [5001]
173
204
 
174
- # ── 11. BaseWarning ── structured warnings with factory methods ───────────────
205
+ # ── 12. BaseWarning ── structured warnings with factory methods ───────────────
175
206
  class ExperimentalWarning(BaseWarning):
176
207
  default_detail = "This feature is experimental."
177
208
 
@@ -3,7 +3,7 @@ A lightweight Python exception handling utility library.
3
3
 
4
4
  ## Features
5
5
  - **Raise Exceptions**: `raises()`, `raises_all()`, `reraise()` — batch raising and exception conversion
6
- - **Catch & Suppress**: `ignore()`, `ignore_subclass()`, `ignore_warns()`, `fast_ignore()`, `super_fast_ignore()`, `timeout()` — graceful suppression of exceptions and warnings
6
+ - **Catch & Suppress**: `ignore()`, `ignore_subclass()`, `ignore_warns()`, `fast_ignore()`, `super_fast_ignore()`, `timeout()`, `retry()` — graceful suppression of exceptions and warnings, with automatic retry
7
7
  - **Exception Caching**: `error_cache` — cache exceptions raised by functions (similar to `lru_cache`)
8
8
  - **Custom Exceptions**: `PureBaseException`, `ContextException`, `BaseErrorCodes`, `BaseWarning` — structured exception classes with error codes, trace IDs, and context
9
9
  - **Attribute Error Mixin**: Customize error behavior for attribute access, assignment, and deletion
@@ -17,12 +17,12 @@ pip install errortools
17
17
 
18
18
  ---
19
19
 
20
- ## Example
20
+ ## Examples
21
21
 
22
22
  ```python
23
23
  import warnings
24
24
  from errortools import (
25
- ignore, fast_ignore, ignore_subclass, ignore_warns, timeout,
25
+ ignore, fast_ignore, ignore_subclass, ignore_warns, timeout, retry,
26
26
  reraise, raises, raises_all, assert_raises,
27
27
  error_cache,
28
28
  PureBaseException, ContextException, BaseErrorCodes, BaseWarning,
@@ -38,8 +38,22 @@ assert err.name == "KeyError" # exception class name
38
38
  assert err.count == 1 # how many times suppressed
39
39
  assert err.exception # the original KeyError instance
40
40
  assert err.traceback # full formatted traceback string
41
+ ```
42
+
43
+ **Attributes on the returned object:**
44
+
45
+ | Attribute | Type | Description |
46
+ |---|---|---|
47
+ | `be_ignore` | `bool` | `True` if an exception was suppressed |
48
+ | `name` | `str \| None` | Class name of the suppressed exception |
49
+ | `count` | `int` | Number of suppressed exceptions |
50
+ | `exception` | `Exception \| None` | The original exception instance |
51
+ | `traceback` | `str \| None` | Formatted traceback string for debugging |
52
+
53
+ ## Examples
41
54
 
42
- # ignore as a decorator
55
+ ```python
56
+ # ── ignore as a decorator ──
43
57
  @ignore(ValueError, TypeError)
44
58
  def parse(x: str) -> int:
45
59
  return int(x)
@@ -71,14 +85,29 @@ async def fetch_data(url: str) -> bytes:
71
85
 
72
86
  # asyncio.TimeoutError raised automatically if it exceeds 5 s
73
87
 
74
- # ── 6. reraise ── convert exception types on the fly ─────────────────────────
88
+ # ── 6. retry ── automatically retry on failure ───────────────────────────────
89
+ @retry(times=3, on=ConnectionError, delay=1.0)
90
+ def connect(host: str) -> None:
91
+ ... # retried up to 3 times on ConnectionError
92
+
93
+ # works with async functions too
94
+ @retry(times=5, on=TimeoutError, delay=0.5)
95
+ async def fetch(url: str) -> bytes:
96
+ ...
97
+
98
+ # multiple exception types
99
+ @retry(times=2, on=(ValueError, KeyError))
100
+ def parse(data: dict) -> str:
101
+ return data["key"]
102
+
103
+ # ── 7. reraise ── convert exception types on the fly ─────────────────────────
75
104
  with reraise(KeyError, ValueError):
76
105
  raise KeyError("missing key") # → ValueError: 'missing key'
77
106
 
78
107
  with reraise((KeyError, IndexError), RuntimeError):
79
108
  _ = [][99] # → RuntimeError: list index out of range
80
109
 
81
- # ── 7. raises / raises_all ── batch raise ────────────────────────────────────
110
+ # ── 8. raises / raises_all ── batch raise ────────────────────────────────────
82
111
  raises([ValueError], ["bad input"]) # → ValueError: bad input
83
112
 
84
113
  raises_all(
@@ -86,11 +115,11 @@ raises_all(
86
115
  ["bad input"],
87
116
  ) # → ExceptionGroup (2 sub-exceptions)
88
117
 
89
- # ── 8. assert_raises ── assert a callable raises ─────────────────────────────
118
+ # ── 9. assert_raises ── assert a callable raises ─────────────────────────────
90
119
  exc = assert_raises(int, [ValueError], "not-a-number")
91
120
  print(exc) # invalid literal for int() with base 10: 'not-a-number'
92
121
 
93
- # ── 9. error_cache ── cache exceptions by call arguments ─────────────────────
122
+ # ── 10. error_cache ── cache exceptions by call arguments ─────────────────────
94
123
  @error_cache(maxsize=64)
95
124
  def load(user_id: int) -> dict:
96
125
  if user_id < 0:
@@ -103,7 +132,7 @@ with ignore(ValueError):
103
132
  print(load.cache_info()) # CacheInfo(hits=0, misses=1, maxsize=64, currsize=1)
104
133
  load.clear_cache()
105
134
 
106
- # ── 10. Custom exceptions — three layers ──────────────────────────────────────
135
+ # ── 11. Custom exceptions — three layers ──────────────────────────────────────
107
136
 
108
137
  # Layer 1: PureBaseException — code + detail only
109
138
  class AppError(PureBaseException):
@@ -139,7 +168,7 @@ raise BaseErrorCodes.runtime_failure("crash") # RuntimeFailure [
139
168
  raise BaseErrorCodes.timeout_failure() # TimeoutFailure [4002]
140
169
  raise BaseErrorCodes.configuration_error("missing key") # ConfigurationError [5001]
141
170
 
142
- # ── 11. BaseWarning ── structured warnings with factory methods ───────────────
171
+ # ── 12. BaseWarning ── structured warnings with factory methods ───────────────
143
172
  class ExperimentalWarning(BaseWarning):
144
173
  default_detail = "This feature is experimental."
145
174
 
@@ -0,0 +1,32 @@
1
+ import sys
2
+
3
+ from _errortools.metadata import (
4
+ __author__,
5
+ __author_email__,
6
+ __copyright__,
7
+ __description__,
8
+ __license__,
9
+ __url__,
10
+ )
11
+ from _errortools.version import __version__
12
+
13
+
14
+ def _cmd_log(message: str, level: str, output: str) -> None:
15
+ """Emit a single log message via the errortools logger."""
16
+ from .logging import BaseLogger
17
+ from .logging.level import get_level
18
+
19
+ stream = sys.stdout if output == "stdout" else sys.stderr
20
+ log = BaseLogger(name="errortools-cli")
21
+ log.add(stream, level="TRACE", colorize=None)
22
+ log.log(get_level(level), message)
23
+
24
+
25
+ def _print_info() -> None:
26
+ """Print a summary of all package metadata."""
27
+ print(f"errortools v{__version__}")
28
+ print(f" {__description__}")
29
+ print(f" Author: {__author__} <{__author_email__}>")
30
+ print(f" License: {__license__}")
31
+ print(f" URL: {__url__}")
32
+ print(f" Copyright: {__copyright__}")