exception_wrap 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: exception_wrap
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: An exception wrapper for decorating functions with detailed generic error handling and logging.
|
|
5
|
+
Requires-Python: >=3.13
|
|
6
|
+
Description-Content-Type: text/markdown
|
|
7
|
+
|
|
8
|
+
# Exception Wrapper
|
|
9
|
+
|
|
10
|
+
Rather than needing to remember all of the exception types or do "catch all" exceptions, and rather than having to reimplement logging formats constantly,
|
|
11
|
+
this module provides consistent and comprehensive logging and error handing approach.
|
|
12
|
+
|
|
13
|
+
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
lib.py,sha256=E1o_wzl3hx-OJJTbzlCN6cr-nXRRiwPLpG0jPU25zCA,17627
|
|
2
|
+
exception_wrap-0.1.0.dist-info/METADATA,sha256=2oluAPEepSpOYklKrRFXCyygt0rn9dHrKw8xEZgOitE,492
|
|
3
|
+
exception_wrap-0.1.0.dist-info/WHEEL,sha256=YLJXdYXQ2FQ0Uqn2J-6iEIC-3iOey8lH3xCtvFLkd8Q,91
|
|
4
|
+
exception_wrap-0.1.0.dist-info/top_level.txt,sha256=oyXcrLgLICoBS0ILk_wZBhkAAY-M4hbQoMsA1hDsf5c,4
|
|
5
|
+
exception_wrap-0.1.0.dist-info/RECORD,,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
lib
|
lib.py
ADDED
|
@@ -0,0 +1,498 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Generic Exception Handler and Logger Module
|
|
3
|
+
|
|
4
|
+
Provides a decorator for automatic exception handling and logging with detailed
|
|
5
|
+
information for all standard Python built-in exceptions.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import functools
|
|
9
|
+
import sys
|
|
10
|
+
from datetime import datetime, timezone
|
|
11
|
+
from typing import Callable, Any, Optional
|
|
12
|
+
import uuid
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def log_exception(
|
|
16
|
+
exception_id: str,
|
|
17
|
+
func_name: str,
|
|
18
|
+
exc_type: type,
|
|
19
|
+
exc_value: Exception,
|
|
20
|
+
exc_info: tuple,
|
|
21
|
+
logged_args: dict = None
|
|
22
|
+
) -> None:
|
|
23
|
+
"""
|
|
24
|
+
Log exception details in a structured format.
|
|
25
|
+
|
|
26
|
+
Args:
|
|
27
|
+
exception_id: UUIDv4 string for tracking this exception
|
|
28
|
+
func_name: Name of the function where exception occurred
|
|
29
|
+
exc_type: Type of the exception
|
|
30
|
+
exc_value: The exception instance
|
|
31
|
+
exc_info: Exception info tuple from sys.exc_info()
|
|
32
|
+
logged_args: Dictionary of log_this_* arguments to include in log
|
|
33
|
+
"""
|
|
34
|
+
timestamp = datetime.now(timezone.utc).isoformat()
|
|
35
|
+
|
|
36
|
+
# Extract helpful information
|
|
37
|
+
exc_msg = str(exc_value) if str(exc_value) else "No message provided"
|
|
38
|
+
|
|
39
|
+
# Get line number if available
|
|
40
|
+
tb = exc_info[2]
|
|
41
|
+
line_no = tb.tb_lineno if tb else "Unknown"
|
|
42
|
+
|
|
43
|
+
# Format logged arguments if present
|
|
44
|
+
logged_args_str = ""
|
|
45
|
+
if logged_args:
|
|
46
|
+
# Sort for consistent ordering in logs
|
|
47
|
+
sorted_args = sorted(logged_args.items())
|
|
48
|
+
args_parts = [f"{k}: {v}" for k, v in sorted_args]
|
|
49
|
+
logged_args_str = f"logged args: {', '.join(args_parts)} - "
|
|
50
|
+
|
|
51
|
+
# Format the log message
|
|
52
|
+
log_msg = (
|
|
53
|
+
f"{timestamp} - {exception_id} - {func_name} - "
|
|
54
|
+
f"{logged_args_str}"
|
|
55
|
+
f"ERROR: {exc_type.__name__}: {exc_msg} (Line: {line_no})"
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
print(log_msg, file=sys.stderr)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def exception_handler(func: Callable) -> Callable:
|
|
62
|
+
"""
|
|
63
|
+
Decorator that wraps a function with comprehensive exception handling.
|
|
64
|
+
|
|
65
|
+
The decorated function should accept 'exception_id' and 'func_name' as
|
|
66
|
+
keyword arguments, or they will be auto-generated/detected.
|
|
67
|
+
|
|
68
|
+
Usage:
|
|
69
|
+
@exception_handler
|
|
70
|
+
def my_function(arg1, arg2, exception_id=None, func_name=None):
|
|
71
|
+
# function code here
|
|
72
|
+
pass
|
|
73
|
+
"""
|
|
74
|
+
@functools.wraps(func)
|
|
75
|
+
def wrapper(*args, **kwargs):
|
|
76
|
+
# Extract or generate tracking information
|
|
77
|
+
exception_id = kwargs.pop('exception_id', str(uuid.uuid4()))
|
|
78
|
+
func_name = kwargs.pop('func_name', func.__name__)
|
|
79
|
+
|
|
80
|
+
# Extract all log_this_* arguments
|
|
81
|
+
logged_args = {}
|
|
82
|
+
keys_to_remove = []
|
|
83
|
+
for key in kwargs:
|
|
84
|
+
if key.startswith('log_this_'):
|
|
85
|
+
# Remove the 'log_this_' prefix for cleaner logging
|
|
86
|
+
clean_key = key[9:] # len('log_this_') = 9
|
|
87
|
+
logged_args[clean_key] = kwargs[key]
|
|
88
|
+
keys_to_remove.append(key)
|
|
89
|
+
|
|
90
|
+
# Remove log_this_* arguments from kwargs
|
|
91
|
+
for key in keys_to_remove:
|
|
92
|
+
kwargs.pop(key)
|
|
93
|
+
|
|
94
|
+
try:
|
|
95
|
+
return func(*args, **kwargs)
|
|
96
|
+
|
|
97
|
+
# Concrete Exceptions - Most Specific First
|
|
98
|
+
|
|
99
|
+
# System Exit Exceptions
|
|
100
|
+
except KeyboardInterrupt as e:
|
|
101
|
+
exc_info = sys.exc_info()
|
|
102
|
+
log_exception(exception_id, func_name, KeyboardInterrupt, e, exc_info, logged_args)
|
|
103
|
+
raise
|
|
104
|
+
|
|
105
|
+
except SystemExit as e:
|
|
106
|
+
exc_info = sys.exc_info()
|
|
107
|
+
log_exception(exception_id, func_name, SystemExit, e, exc_info, logged_args)
|
|
108
|
+
raise
|
|
109
|
+
|
|
110
|
+
# OS and I/O Exceptions
|
|
111
|
+
except FileNotFoundError as e:
|
|
112
|
+
exc_info = sys.exc_info()
|
|
113
|
+
log_exception(exception_id, func_name, FileNotFoundError, e, exc_info, logged_args)
|
|
114
|
+
raise
|
|
115
|
+
|
|
116
|
+
except FileExistsError as e:
|
|
117
|
+
exc_info = sys.exc_info()
|
|
118
|
+
log_exception(exception_id, func_name, FileExistsError, e, exc_info, logged_args)
|
|
119
|
+
raise
|
|
120
|
+
|
|
121
|
+
except IsADirectoryError as e:
|
|
122
|
+
exc_info = sys.exc_info()
|
|
123
|
+
log_exception(exception_id, func_name, IsADirectoryError, e, exc_info, logged_args)
|
|
124
|
+
raise
|
|
125
|
+
|
|
126
|
+
except NotADirectoryError as e:
|
|
127
|
+
exc_info = sys.exc_info()
|
|
128
|
+
log_exception(exception_id, func_name, NotADirectoryError, e, exc_info, logged_args)
|
|
129
|
+
raise
|
|
130
|
+
|
|
131
|
+
except PermissionError as e:
|
|
132
|
+
exc_info = sys.exc_info()
|
|
133
|
+
log_exception(exception_id, func_name, PermissionError, e, exc_info, logged_args)
|
|
134
|
+
raise
|
|
135
|
+
|
|
136
|
+
except ProcessLookupError as e:
|
|
137
|
+
exc_info = sys.exc_info()
|
|
138
|
+
log_exception(exception_id, func_name, ProcessLookupError, e, exc_info, logged_args)
|
|
139
|
+
raise
|
|
140
|
+
|
|
141
|
+
except TimeoutError as e:
|
|
142
|
+
exc_info = sys.exc_info()
|
|
143
|
+
log_exception(exception_id, func_name, TimeoutError, e, exc_info, logged_args)
|
|
144
|
+
raise
|
|
145
|
+
|
|
146
|
+
except InterruptedError as e:
|
|
147
|
+
exc_info = sys.exc_info()
|
|
148
|
+
log_exception(exception_id, func_name, InterruptedError, e, exc_info, logged_args)
|
|
149
|
+
raise
|
|
150
|
+
|
|
151
|
+
except ChildProcessError as e:
|
|
152
|
+
exc_info = sys.exc_info()
|
|
153
|
+
log_exception(exception_id, func_name, ChildProcessError, e, exc_info, logged_args)
|
|
154
|
+
raise
|
|
155
|
+
|
|
156
|
+
except BlockingIOError as e:
|
|
157
|
+
exc_info = sys.exc_info()
|
|
158
|
+
log_exception(exception_id, func_name, BlockingIOError, e, exc_info, logged_args)
|
|
159
|
+
raise
|
|
160
|
+
|
|
161
|
+
except ConnectionError as e:
|
|
162
|
+
exc_info = sys.exc_info()
|
|
163
|
+
log_exception(exception_id, func_name, ConnectionError, e, exc_info, logged_args)
|
|
164
|
+
raise
|
|
165
|
+
|
|
166
|
+
except BrokenPipeError as e:
|
|
167
|
+
exc_info = sys.exc_info()
|
|
168
|
+
log_exception(exception_id, func_name, BrokenPipeError, e, exc_info, logged_args)
|
|
169
|
+
raise
|
|
170
|
+
|
|
171
|
+
except ConnectionAbortedError as e:
|
|
172
|
+
exc_info = sys.exc_info()
|
|
173
|
+
log_exception(exception_id, func_name, ConnectionAbortedError, e, exc_info, logged_args)
|
|
174
|
+
raise
|
|
175
|
+
|
|
176
|
+
except ConnectionRefusedError as e:
|
|
177
|
+
exc_info = sys.exc_info()
|
|
178
|
+
log_exception(exception_id, func_name, ConnectionRefusedError, e, exc_info, logged_args)
|
|
179
|
+
raise
|
|
180
|
+
|
|
181
|
+
except ConnectionResetError as e:
|
|
182
|
+
exc_info = sys.exc_info()
|
|
183
|
+
log_exception(exception_id, func_name, ConnectionResetError, e, exc_info, logged_args)
|
|
184
|
+
raise
|
|
185
|
+
|
|
186
|
+
except OSError as e:
|
|
187
|
+
exc_info = sys.exc_info()
|
|
188
|
+
log_exception(exception_id, func_name, OSError, e, exc_info, logged_args)
|
|
189
|
+
raise
|
|
190
|
+
|
|
191
|
+
# Arithmetic Exceptions
|
|
192
|
+
except ZeroDivisionError as e:
|
|
193
|
+
exc_info = sys.exc_info()
|
|
194
|
+
log_exception(exception_id, func_name, ZeroDivisionError, e, exc_info, logged_args)
|
|
195
|
+
raise
|
|
196
|
+
|
|
197
|
+
except FloatingPointError as e:
|
|
198
|
+
exc_info = sys.exc_info()
|
|
199
|
+
log_exception(exception_id, func_name, FloatingPointError, e, exc_info, logged_args)
|
|
200
|
+
raise
|
|
201
|
+
|
|
202
|
+
except OverflowError as e:
|
|
203
|
+
exc_info = sys.exc_info()
|
|
204
|
+
log_exception(exception_id, func_name, OverflowError, e, exc_info, logged_args)
|
|
205
|
+
raise
|
|
206
|
+
|
|
207
|
+
# Type and Value Exceptions
|
|
208
|
+
except TypeError as e:
|
|
209
|
+
exc_info = sys.exc_info()
|
|
210
|
+
log_exception(exception_id, func_name, TypeError, e, exc_info, logged_args)
|
|
211
|
+
raise
|
|
212
|
+
|
|
213
|
+
except ValueError as e:
|
|
214
|
+
exc_info = sys.exc_info()
|
|
215
|
+
log_exception(exception_id, func_name, ValueError, e, exc_info, logged_args)
|
|
216
|
+
raise
|
|
217
|
+
|
|
218
|
+
except UnicodeError as e:
|
|
219
|
+
exc_info = sys.exc_info()
|
|
220
|
+
log_exception(exception_id, func_name, UnicodeError, e, exc_info, logged_args)
|
|
221
|
+
raise
|
|
222
|
+
|
|
223
|
+
except UnicodeDecodeError as e:
|
|
224
|
+
exc_info = sys.exc_info()
|
|
225
|
+
log_exception(exception_id, func_name, UnicodeDecodeError, e, exc_info, logged_args)
|
|
226
|
+
raise
|
|
227
|
+
|
|
228
|
+
except UnicodeEncodeError as e:
|
|
229
|
+
exc_info = sys.exc_info()
|
|
230
|
+
log_exception(exception_id, func_name, UnicodeEncodeError, e, exc_info, logged_args)
|
|
231
|
+
raise
|
|
232
|
+
|
|
233
|
+
except UnicodeTranslateError as e:
|
|
234
|
+
exc_info = sys.exc_info()
|
|
235
|
+
log_exception(exception_id, func_name, UnicodeTranslateError, e, exc_info, logged_args)
|
|
236
|
+
raise
|
|
237
|
+
|
|
238
|
+
# Lookup Exceptions
|
|
239
|
+
except KeyError as e:
|
|
240
|
+
exc_info = sys.exc_info()
|
|
241
|
+
log_exception(exception_id, func_name, KeyError, e, exc_info, logged_args)
|
|
242
|
+
raise
|
|
243
|
+
|
|
244
|
+
except IndexError as e:
|
|
245
|
+
exc_info = sys.exc_info()
|
|
246
|
+
log_exception(exception_id, func_name, IndexError, e, exc_info, logged_args)
|
|
247
|
+
raise
|
|
248
|
+
|
|
249
|
+
except AttributeError as e:
|
|
250
|
+
exc_info = sys.exc_info()
|
|
251
|
+
log_exception(exception_id, func_name, AttributeError, e, exc_info, logged_args)
|
|
252
|
+
raise
|
|
253
|
+
|
|
254
|
+
except NameError as e:
|
|
255
|
+
exc_info = sys.exc_info()
|
|
256
|
+
log_exception(exception_id, func_name, NameError, e, exc_info, logged_args)
|
|
257
|
+
raise
|
|
258
|
+
|
|
259
|
+
except UnboundLocalError as e:
|
|
260
|
+
exc_info = sys.exc_info()
|
|
261
|
+
log_exception(exception_id, func_name, UnboundLocalError, e, exc_info, logged_args)
|
|
262
|
+
raise
|
|
263
|
+
|
|
264
|
+
# Import Exceptions
|
|
265
|
+
except ModuleNotFoundError as e:
|
|
266
|
+
exc_info = sys.exc_info()
|
|
267
|
+
log_exception(exception_id, func_name, ModuleNotFoundError, e, exc_info, logged_args)
|
|
268
|
+
raise
|
|
269
|
+
|
|
270
|
+
except ImportError as e:
|
|
271
|
+
exc_info = sys.exc_info()
|
|
272
|
+
log_exception(exception_id, func_name, ImportError, e, exc_info, logged_args)
|
|
273
|
+
raise
|
|
274
|
+
|
|
275
|
+
# Memory and Resource Exceptions
|
|
276
|
+
except MemoryError as e:
|
|
277
|
+
exc_info = sys.exc_info()
|
|
278
|
+
log_exception(exception_id, func_name, MemoryError, e, exc_info, logged_args)
|
|
279
|
+
raise
|
|
280
|
+
|
|
281
|
+
except RecursionError as e:
|
|
282
|
+
exc_info = sys.exc_info()
|
|
283
|
+
log_exception(exception_id, func_name, RecursionError, e, exc_info, logged_args)
|
|
284
|
+
raise
|
|
285
|
+
|
|
286
|
+
# Runtime Exceptions
|
|
287
|
+
except NotImplementedError as e:
|
|
288
|
+
exc_info = sys.exc_info()
|
|
289
|
+
log_exception(exception_id, func_name, NotImplementedError, e, exc_info, logged_args)
|
|
290
|
+
raise
|
|
291
|
+
|
|
292
|
+
except StopIteration as e:
|
|
293
|
+
exc_info = sys.exc_info()
|
|
294
|
+
log_exception(exception_id, func_name, StopIteration, e, exc_info, logged_args)
|
|
295
|
+
raise
|
|
296
|
+
|
|
297
|
+
except StopAsyncIteration as e:
|
|
298
|
+
exc_info = sys.exc_info()
|
|
299
|
+
log_exception(exception_id, func_name, StopAsyncIteration, e, exc_info, logged_args)
|
|
300
|
+
raise
|
|
301
|
+
|
|
302
|
+
except GeneratorExit as e:
|
|
303
|
+
exc_info = sys.exc_info()
|
|
304
|
+
log_exception(exception_id, func_name, GeneratorExit, e, exc_info, logged_args)
|
|
305
|
+
raise
|
|
306
|
+
|
|
307
|
+
# Syntax and Indentation Exceptions
|
|
308
|
+
except SyntaxError as e:
|
|
309
|
+
exc_info = sys.exc_info()
|
|
310
|
+
log_exception(exception_id, func_name, SyntaxError, e, exc_info, logged_args)
|
|
311
|
+
raise
|
|
312
|
+
|
|
313
|
+
except IndentationError as e:
|
|
314
|
+
exc_info = sys.exc_info()
|
|
315
|
+
log_exception(exception_id, func_name, IndentationError, e, exc_info, logged_args)
|
|
316
|
+
raise
|
|
317
|
+
|
|
318
|
+
except TabError as e:
|
|
319
|
+
exc_info = sys.exc_info()
|
|
320
|
+
log_exception(exception_id, func_name, TabError, e, exc_info, logged_args)
|
|
321
|
+
raise
|
|
322
|
+
|
|
323
|
+
# System Exceptions
|
|
324
|
+
except SystemError as e:
|
|
325
|
+
exc_info = sys.exc_info()
|
|
326
|
+
log_exception(exception_id, func_name, SystemError, e, exc_info, logged_args)
|
|
327
|
+
raise
|
|
328
|
+
|
|
329
|
+
except ReferenceError as e:
|
|
330
|
+
exc_info = sys.exc_info()
|
|
331
|
+
log_exception(exception_id, func_name, ReferenceError, e, exc_info, logged_args)
|
|
332
|
+
raise
|
|
333
|
+
|
|
334
|
+
# Buffer and EOFError
|
|
335
|
+
except BufferError as e:
|
|
336
|
+
exc_info = sys.exc_info()
|
|
337
|
+
log_exception(exception_id, func_name, BufferError, e, exc_info, logged_args)
|
|
338
|
+
raise
|
|
339
|
+
|
|
340
|
+
except EOFError as e:
|
|
341
|
+
exc_info = sys.exc_info()
|
|
342
|
+
log_exception(exception_id, func_name, EOFError, e, exc_info, logged_args)
|
|
343
|
+
raise
|
|
344
|
+
|
|
345
|
+
# Assertion Error
|
|
346
|
+
except AssertionError as e:
|
|
347
|
+
exc_info = sys.exc_info()
|
|
348
|
+
log_exception(exception_id, func_name, AssertionError, e, exc_info, logged_args)
|
|
349
|
+
raise
|
|
350
|
+
|
|
351
|
+
# Runtime Error and Warning
|
|
352
|
+
except RuntimeError as e:
|
|
353
|
+
exc_info = sys.exc_info()
|
|
354
|
+
log_exception(exception_id, func_name, RuntimeError, e, exc_info, logged_args)
|
|
355
|
+
raise
|
|
356
|
+
|
|
357
|
+
except RuntimeWarning as e:
|
|
358
|
+
exc_info = sys.exc_info()
|
|
359
|
+
log_exception(exception_id, func_name, RuntimeWarning, e, exc_info, logged_args)
|
|
360
|
+
raise
|
|
361
|
+
|
|
362
|
+
# Lookup Error (parent class - catch after specific lookup errors)
|
|
363
|
+
except LookupError as e:
|
|
364
|
+
exc_info = sys.exc_info()
|
|
365
|
+
log_exception(exception_id, func_name, LookupError, e, exc_info, logged_args)
|
|
366
|
+
raise
|
|
367
|
+
|
|
368
|
+
# Arithmetic Error (parent class - catch after specific arithmetic errors)
|
|
369
|
+
except ArithmeticError as e:
|
|
370
|
+
exc_info = sys.exc_info()
|
|
371
|
+
log_exception(exception_id, func_name, ArithmeticError, e, exc_info, logged_args)
|
|
372
|
+
raise
|
|
373
|
+
|
|
374
|
+
# Base Exception classes (catch last)
|
|
375
|
+
except Exception as e:
|
|
376
|
+
exc_info = sys.exc_info()
|
|
377
|
+
log_exception(exception_id, func_name, Exception, e, exc_info, logged_args)
|
|
378
|
+
raise
|
|
379
|
+
|
|
380
|
+
except BaseException as e:
|
|
381
|
+
exc_info = sys.exc_info()
|
|
382
|
+
log_exception(exception_id, func_name, BaseException, e, exc_info, logged_args)
|
|
383
|
+
raise
|
|
384
|
+
|
|
385
|
+
return wrapper
|
|
386
|
+
|
|
387
|
+
|
|
388
|
+
# Convenience function for manual exception handling
|
|
389
|
+
def handle_exception(
|
|
390
|
+
exception_id: Optional[str] = None,
|
|
391
|
+
func_name: Optional[str] = None,
|
|
392
|
+
**logged_args
|
|
393
|
+
) -> None:
|
|
394
|
+
"""
|
|
395
|
+
Manually log the current exception.
|
|
396
|
+
|
|
397
|
+
Call this within an except block to log the exception with the same
|
|
398
|
+
format as the decorator.
|
|
399
|
+
|
|
400
|
+
Args:
|
|
401
|
+
exception_id: Optional UUID for tracking. Generated if not provided.
|
|
402
|
+
func_name: Optional function name. Detected from caller if not provided.
|
|
403
|
+
**logged_args: Any additional context to log (e.g., user_id=123, rate=0.5)
|
|
404
|
+
|
|
405
|
+
Example:
|
|
406
|
+
try:
|
|
407
|
+
risky_operation()
|
|
408
|
+
except Exception:
|
|
409
|
+
handle_exception(
|
|
410
|
+
exception_id="custom-uuid",
|
|
411
|
+
func_name="my_function",
|
|
412
|
+
user_id=12345,
|
|
413
|
+
request_id="abc-123"
|
|
414
|
+
)
|
|
415
|
+
raise
|
|
416
|
+
"""
|
|
417
|
+
import inspect
|
|
418
|
+
|
|
419
|
+
exc_info = sys.exc_info()
|
|
420
|
+
if exc_info[0] is None:
|
|
421
|
+
print("Warning: handle_exception called outside of exception context",
|
|
422
|
+
file=sys.stderr)
|
|
423
|
+
return
|
|
424
|
+
|
|
425
|
+
if exception_id is None:
|
|
426
|
+
exception_id = str(uuid.uuid4())
|
|
427
|
+
|
|
428
|
+
if func_name is None:
|
|
429
|
+
frame = inspect.currentframe()
|
|
430
|
+
if frame and frame.f_back:
|
|
431
|
+
func_name = frame.f_back.f_code.co_name
|
|
432
|
+
else:
|
|
433
|
+
func_name = "unknown"
|
|
434
|
+
|
|
435
|
+
log_exception(exception_id, func_name, exc_info[0], exc_info[1], exc_info, logged_args)
|
|
436
|
+
|
|
437
|
+
|
|
438
|
+
if __name__ == "__main__":
|
|
439
|
+
# Example usage and testing
|
|
440
|
+
|
|
441
|
+
@exception_handler
|
|
442
|
+
def test_division_by_zero():
|
|
443
|
+
"""Test ZeroDivisionError handling"""
|
|
444
|
+
return 1 / 0
|
|
445
|
+
|
|
446
|
+
@exception_handler
|
|
447
|
+
def test_file_not_found():
|
|
448
|
+
"""Test FileNotFoundError handling"""
|
|
449
|
+
with open("/nonexistent/file.txt", "r") as f:
|
|
450
|
+
return f.read()
|
|
451
|
+
|
|
452
|
+
@exception_handler
|
|
453
|
+
def test_key_error():
|
|
454
|
+
"""Test KeyError handling"""
|
|
455
|
+
d = {"a": 1}
|
|
456
|
+
return d["b"]
|
|
457
|
+
|
|
458
|
+
@exception_handler
|
|
459
|
+
def test_with_custom_id(data, exception_id=None, func_name=None, log_this_user=None, log_this_rate=None):
|
|
460
|
+
"""Test with custom exception_id, func_name, and log_this_* arguments"""
|
|
461
|
+
return data[10] # Will raise IndexError
|
|
462
|
+
|
|
463
|
+
print("Testing exception_logger module...\n")
|
|
464
|
+
|
|
465
|
+
# Test 1: ZeroDivisionError
|
|
466
|
+
print("Test 1: Division by zero")
|
|
467
|
+
try:
|
|
468
|
+
test_division_by_zero()
|
|
469
|
+
except ZeroDivisionError:
|
|
470
|
+
print("Caught and re-raised as expected\n")
|
|
471
|
+
|
|
472
|
+
# Test 2: FileNotFoundError
|
|
473
|
+
print("Test 2: File not found")
|
|
474
|
+
try:
|
|
475
|
+
test_file_not_found()
|
|
476
|
+
except FileNotFoundError:
|
|
477
|
+
print("Caught and re-raised as expected\n")
|
|
478
|
+
|
|
479
|
+
# Test 3: KeyError
|
|
480
|
+
print("Test 3: Key error")
|
|
481
|
+
try:
|
|
482
|
+
test_key_error()
|
|
483
|
+
except KeyError:
|
|
484
|
+
print("Caught and re-raised as expected\n")
|
|
485
|
+
|
|
486
|
+
# Test 4: Custom exception_id and func_name
|
|
487
|
+
print("Test 4: Custom tracking info")
|
|
488
|
+
custom_uuid = str(uuid.uuid4())
|
|
489
|
+
try:
|
|
490
|
+
test_with_custom_id([1, 2, 3],
|
|
491
|
+
exception_id=custom_uuid,
|
|
492
|
+
func_name="custom_function_name",
|
|
493
|
+
log_this_user="frank",
|
|
494
|
+
log_this_rate=0.125)
|
|
495
|
+
except IndexError:
|
|
496
|
+
print("Caught and re-raised as expected\n")
|
|
497
|
+
|
|
498
|
+
print("All tests completed!")
|