Skip to content
This repository was archived by the owner on Mar 26, 2026. It is now read-only.

Commit 8f11e85

Browse files
Made exception handling framework with customizable output formatting
0 parents  commit 8f11e85

4 files changed

Lines changed: 192 additions & 0 deletions

File tree

exception/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
from .handler import Handler
2+
from .colors import Colors, Format

exception/colors.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
class Colors:
2+
RESET = "\033[0m"
3+
BLACK = "\033[30m"
4+
RED = "\033[31m"
5+
GREEN = "\033[32m"
6+
YELLOW = "\033[33m"
7+
BLUE = "\033[34m"
8+
MAGENTA = "\033[35m"
9+
CYAN = "\033[36m"
10+
WHITE = "\033[37m"
11+
12+
13+
class Format:
14+
NORMAL = ""
15+
BOLD = "\033[1m"
16+
DIM = "\033[2m"
17+
UNDERLINE = "\033[4m"
18+
BLINK = "\033[5m"
19+
INVERT = "\033[7m"

exception/handler.py

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
import traceback
2+
import datetime
3+
import sys
4+
import re
5+
from .colors import Colors, Format
6+
from .messages import GENERIC_MESSAGES
7+
8+
9+
class Handler:
10+
def __init__(self,
11+
show_line: bool = False,
12+
trace: bool = False,
13+
use_timestamp: bool = False,
14+
exit_script: bool = False,
15+
print_function: callable = print,
16+
return_string_rather_than_print: bool = False
17+
):
18+
# Handler defaults
19+
self.show_line: bool = show_line
20+
self.trace: bool = trace
21+
self.use_timestamp: bool = use_timestamp
22+
self.exit_script: bool = exit_script
23+
self.print_function: callable = print_function
24+
self.return_string_rather_than_print: bool = return_string_rather_than_print
25+
26+
# Formatter defaults
27+
# # Color wise
28+
self.main_color: Colors = Colors.WHITE
29+
self.message_color: Colors = self.main_color
30+
self.trace_color: Colors = self.main_color
31+
self.timestamps_color: Colors = self.main_color
32+
# # Format wise
33+
self.main_format: Format = Format.NORMAL
34+
self.message_text_format: Format = self.main_format
35+
self.trace_text_format: Format = self.main_format
36+
self.timestamps_text_format: Format = self.main_format
37+
# # # Datetime wise
38+
self.datetime_format: str = "%Y-%m-%d %H:%M:%S"
39+
40+
def formatter(self,
41+
main_format: Format = None,
42+
timestamps_format: Format = None,
43+
trace_format: Format = None,
44+
message_format: Format = None,
45+
main_color: Colors = None,
46+
timestamps_color: Colors = None,
47+
trace_color: Colors = None,
48+
message_color: Colors = None,
49+
datetime_format: str = None
50+
):
51+
# Format wise
52+
self.main_format: Format = main_format or self.main_format # Default to the main format
53+
self.timestamps_text_format: Format = timestamps_format or self.main_format
54+
self.trace_text_format: Format = trace_format or self.main_format
55+
self.message_text_format: Format = message_format or self.main_format
56+
57+
# Color wise
58+
self.main_color: Colors = main_color or self.main_color # Default to the main main_color
59+
self.timestamps_color: Colors = timestamps_color or self.main_color
60+
self.trace_color: Colors = trace_color or self.main_color
61+
self.message_color: Colors = message_color or self.main_color
62+
63+
# Datetime format
64+
self.datetime_format: str = datetime_format if datetime_format else self.datetime_format
65+
66+
@staticmethod
67+
def _fallback_message(exc_type):
68+
exc_name = exc_type.__name__
69+
readable = re.sub(r'(?<!^)(?=[A-Z])', ' ', exc_name)
70+
return f"{readable} occurred [Unknown Exception for handler],"
71+
72+
def exception(self,
73+
msg=None,
74+
exit_script=None,
75+
quit_code=1,
76+
return_string_rather_than_print: bool = False
77+
):
78+
exc_type, exc_obj, tb = sys.exc_info()
79+
line: str = tb.tb_lineno if tb and self.show_line else ''
80+
trace_str: str = ''.join(traceback.format_exception(exc_type, exc_obj, tb)) if self.trace else ''
81+
82+
readable: str = GENERIC_MESSAGES.get(exc_type, self._fallback_message(exc_type))
83+
time_str: str = datetime.datetime.now().strftime(self.datetime_format) if self.use_timestamp else ''
84+
85+
final_msg: str = (
86+
f"{self.timestamps_text_format}{self.timestamps_color}{time_str}{Colors.RESET} > "
87+
f"{self.message_text_format}{self.message_color}{readable}"
88+
f"{'' if line == '' else f' on line {line}'}"
89+
f"{'' if not msg else f' in-detailed info: {msg}'}{Colors.RESET}"
90+
)
91+
92+
if self.trace:
93+
final_msg += (
94+
f"\n{self.trace_text_format}{self.trace_color}{trace_str}{Colors.RESET}"
95+
)
96+
97+
if (return_string_rather_than_print is None and self.return_string_rather_than_print) or return_string_rather_than_print:
98+
return final_msg
99+
self.print_function(final_msg)
100+
101+
if (exit_script is None and self.exit_script) or exit_script:
102+
sys.exit(quit_code)

exception/messages.py

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
GENERIC_MESSAGES = {
2+
BaseException: "A critical error occurred at the base exception level,",
3+
BaseExceptionGroup: "A group of exceptions was raised simultaneously,",
4+
Exception: "An unexpected error occurred,",
5+
GeneratorExit: "A generator was closed before completing,",
6+
KeyboardInterrupt: "Execution was stopped manually — usually by pressing Ctrl+C,",
7+
SystemExit: "The program was told to exit,",
8+
ArithmeticError: "A mathematical operation has gone wrong,",
9+
AssertionError: "An internal check failed — something unexpected happened,",
10+
AttributeError: "You tried to access an attribute that doesn't exist on this object,",
11+
BufferError: "A buffer-related operation failed,",
12+
EOFError: "Unexpected end of input — likely reading past the end of a file or input stream,",
13+
ImportError: "Python couldn't import the requested module or object,",
14+
LookupError: "A generic lookup operation failed (e,g,, index or key lookup),",
15+
MemoryError: "The system ran out of memory while trying to complete the operation,",
16+
NameError: "You tried to use a variable or function that hasn’t been defined,",
17+
OSError: "A system-related operation failed — like accessing a file or device,",
18+
ReferenceError: "A failed reference was used after the object was deleted,",
19+
RuntimeError: "Something unexpected happened during runtime,",
20+
StopAsyncIteration: "Async iteration finished — nothing more to yield,",
21+
StopIteration: "Iteration has finished — the loop is done,",
22+
SyntaxError: "There's a syntax error in your Python code,",
23+
SystemError: "A low-level internal error occurred,",
24+
TypeError: "An operation received a value of the wrong type,",
25+
ValueError: "The value was the right type but made no sense,",
26+
Warning: "A generic warning was raised,",
27+
FloatingPointError: "A floating point calculation failed,",
28+
OverflowError: "A number became too large to handle,",
29+
ZeroDivisionError: "You tried to divide by zero — that's not allowed,",
30+
BytesWarning: "Warning related to bytes or bytecode operations,",
31+
DeprecationWarning: "You're using a deprecated feature that will be removed soon,",
32+
EncodingWarning: "Warning related to encoding operations,",
33+
FutureWarning: "You're using a feature that will change in future versions,",
34+
ImportWarning: "There was something suspicious during an import,",
35+
PendingDeprecationWarning: "This feature is going away soon — but not just yet,",
36+
ResourceWarning: "A resource was not properly managed (e,g, file left open),",
37+
RuntimeWarning: "A runtime condition was suspicious but not fatal,",
38+
SyntaxWarning: "Something is wrong in the code's syntax but not fatal,",
39+
UnicodeWarning: "Detected problematic Unicode operation,",
40+
UserWarning: "A custom warning generated by the user,",
41+
BlockingIOError: "A non-blocking operation couldn’t proceed immediately,",
42+
ChildProcessError: "A child process operation failed,",
43+
ConnectionError: "A connection-related issue occurred,",
44+
FileExistsError: "The file already exists and can't be created again,",
45+
FileNotFoundError: "The specified file was not found,",
46+
InterruptedError: "A system call was interrupted by a signal,",
47+
IsADirectoryError: "Tried to treat a directory like a file,",
48+
NotADirectoryError: "Tried to access something as a directory but it's a file,",
49+
PermissionError: "You don't have permission to perform this action,",
50+
ProcessLookupError: "The specified process does not exist,",
51+
TimeoutError: "An operation took too long and timed out,",
52+
IndentationError: "Your code indentation is incorrect,",
53+
IndexError: "You're trying to access a list or array index that doesn’t exist,",
54+
KeyError: "You're using a key that isn’t present in the dictionary,",
55+
ModuleNotFoundError: "Tried to import a module that doesn’t exist,",
56+
NotImplementedError: "A feature was called that hasn’t been implemented yet,",
57+
RecursionError: "Your code called itself too many times — infinite recursion?",
58+
UnboundLocalError: "You tried to use a local variable before giving it a value,",
59+
UnicodeError: "A Unicode-related error occurred,",
60+
BrokenPipeError: "Tried writing to a pipe that's no longer open,",
61+
ConnectionAbortedError: "The connection was closed by the remote host,",
62+
ConnectionRefusedError: "The remote host actively refused the connection,",
63+
ConnectionResetError: "The connection was forcibly closed by the remote host,",
64+
TabError: "You mixed tabs and spaces — Python doesn't allow that,",
65+
UnicodeDecodeError: "Failed to decode a byte sequence,",
66+
UnicodeEncodeError: "Failed to encode text into bytes,",
67+
UnicodeTranslateError: "Failed to translate characters during encoding,",
68+
ExceptionGroup: "Multiple exceptions occurred simultaneously,"
69+
}

0 commit comments

Comments
 (0)