11import logging
22from functools import wraps
3- from typing import Callable , Literal , Optional , ParamSpec , Tuple , TypeAlias , TypeVar , Union , overload
3+ from typing import Any , Callable , Literal , Optional , ParamSpec , Tuple , Type , TypeAlias , TypeVar , Union , overload
44
55LOG_LEVEL : TypeAlias = Literal ['CRITICAL' , 'ERROR' , 'WARNING' , 'INFO' , 'DEBUG' , 'NOTSET' , 'DEFAULT' ]
66
77P = ParamSpec ("P" )
88R = TypeVar ("R" )
9+ T = TypeVar ("T" )
910
1011def logwrap (
1112 before : Optional [Tuple [LOG_LEVEL , str ]] | str | bool = None ,
@@ -33,25 +34,25 @@ def logwrap(
3334 after: Tuple of log level and message to log after function call or string with default of `INFO` level.
3435
3536 Examples:
36- >>> @logwrap(before=('INFO', '{func} starting, args={args} kwargs={kwargs}'), after=('INFO', '{func} ended'))
37- ... def my_func(my_arg, my_kwarg=None):
38- ... ...
39- ... my_func('hello', my_kwarg=123)
40- Info - my_func Starting, args=('hello',), kwargs={'my_kwarg': 123}
41- Info - my_func Ended
42-
43- >>> @logwrap(before=True, after=True)
44- ... def my_new_func():
45- ... ...
46- ... my_new_func()
47- Debug - Calling my_new_func - args:(), kwargs:{}
48- Info - Function my_new_func ended
49-
50- >>> @logwrap(on_exception=True)
51- ... def error_func():
52- ... raise Exception('My exception msg')
53- ... error_func()
54- Error - Error on error_func: My exception msg
37+ >>> @logwrap(before=('INFO', '{func} starting, args={args} kwargs={kwargs}'), after=('INFO', '{func} ended'))
38+ ... def my_func(my_arg, my_kwarg=None):
39+ ... ...
40+ ... my_func('hello', my_kwarg=123)
41+ Info - my_func Starting, args=('hello',), kwargs={'my_kwarg': 123}
42+ Info - my_func Ended
43+
44+ >>> @logwrap(before=True, after=True)
45+ ... def my_new_func():
46+ ... ...
47+ ... my_new_func()
48+ Debug - Calling my_new_func - args:(), kwargs:{}
49+ Info - Function my_new_func ended
50+
51+ >>> @logwrap(on_exception=True)
52+ ... def error_func():
53+ ... raise Exception('My exception msg')
54+ ... error_func()
55+ Error - Error on error_func: My exception msg
5556 """
5657 def normalize (
5758 default_level : LOG_LEVEL ,
@@ -121,75 +122,49 @@ def wrapper(*args: P.args, **kwargs: P.kwargs) -> R:
121122
122123
123124@overload
124- def suppress_errors (mode : Literal [ "exception" ]) -> Callable [[Callable [..., R ]], Callable [..., Union [R , Exception ]]]: ...
125+ def suppress_errors (fallback : type [ Exception ]) -> Callable [[Callable [..., R ]], Callable [..., Union [R , Exception ]]]: ...
125126@overload
126- def suppress_errors (mode : Literal ["true" ]) -> Callable [[Callable [..., R ]], Callable [..., Union [R , Literal [True ]]]]: ...
127- @overload
128- def suppress_errors (mode : Literal ["false" ]) -> Callable [[Callable [..., R ]], Callable [..., Union [R , Literal [False ]]]]: ...
129- @overload
130- def suppress_errors (mode : Literal ["exception" , "true" , "false" ]): ...
131- def suppress_errors (
132- mode : Literal ["exception" , "true" , "false" ]
133- ) -> Callable [
134- [Callable [..., R ]],
135- Callable [..., Union [R , bool , Exception ]]
136- ]:
127+ def suppress_errors (fallback : T ) -> Callable [[Callable [..., R ]], Callable [..., Union [R , T ]]]: ...
128+
129+ def suppress_errors (fallback : Any ) -> Callable [[Callable [..., R ]], Callable [..., Union [R , Any ]]]:
137130 """
138131 A decorator that suppresses exceptions raised by the wrapped function and returns
139- a fallback value instead, based on the selected mode.
140-
141- This decorator is useful when you want to avoid raising exceptions and handle errors
142- gracefully by returning a consistent fallback value.
132+ a fallback value instead.
143133
144134 Parameters:
145- mode (Literal["true", "false", "exception"]): Determines what to return when an exception is caught.
146- - "true": Returns `True` if an exception occurs.
147- - "false": Returns `False` if an exception occurs.
148- - "exception": Returns the caught exception object instead of raising it.
135+ fallback: Determines what to return when an exception is caught.
136+ - Exception class (like Exception): Returns the caught exception object
137+ - Any other value: Returns that value when exception occurs
149138
150139 Returns:
151- Callable: A decorated version of the original function, with modified error behavior.
152- The return type becomes a union of the original return type and the fallback.
140+ Callable: A decorated version of the original function that returns either:
141+ - The original return value, or
142+ - The fallback value/exception
153143
154144 Example:
155- >>> @suppress_exception("exception")
156- ... def is_connected() -> bool:
157- ... socket.sendall(b'', MSG_DONTWAIT)
158- ... return True
159- >>> is_connected()
160- OSError(...)
161-
162- >>> @suppress_exception("true")
163- ... def has_problems() -> bool:
164- ... device.test_connection()
165- ... return false
166- >>> has_problems()
167- True
168-
169- >>> @suppress_exception("false")
170- ... def is_connected() -> bool:
171- ... socket.sendall(b'', MSG_DONTWAIT)
172- ... return True
173- >>> is_connected()
174- True
145+ >>> @suppress_errors(Exception)
146+ ... def risky_op() -> int:
147+ ... return 1 / 0
148+ >>> result = risky_op() # Returns ZeroDivisionError
149+
150+ >>> @suppress_errors(False)
151+ ... def safe_op() -> bool:
152+ ... raise ValueError("error")
153+ >>> result = safe_op() # Returns False
175154
176155 Notes:
177156 - Only standard Python exceptions (derived from `Exception`) are caught.
178157 - Does not suppress `KeyboardInterrupt`, `SystemExit`, or `GeneratorExit`.
179158 - The decorator preserves the original function's metadata (name, docstring, etc.).
180-
181- Raises:
182- ValueError: If the provided mode is not one of the allowed values.
183159 """
184- def decorator (func : Callable [..., R ]) -> Callable [..., Union [R , bool , Exception ]]:
160+ def decorator (func : Callable [..., R ]) -> Callable [..., Union [R , Any ]]:
185161 @wraps (func )
186- def wrapper (* args , ** kwargs ):
187- try : return func (* args , ** kwargs )
162+ def wrapper (* args : Any , ** kwargs : Any ) -> Union [R , Any ]:
163+ try :
164+ return func (* args , ** kwargs )
188165 except Exception as e :
189- if mode == "exception" : return e
190- elif mode == "true" : return True
191- elif mode == "false" : return False
192- else : raise ValueError (f"Invalid mode: { mode } " )
193-
166+ if fallback is Exception :
167+ return e
168+ return fallback
194169 return wrapper
195170 return decorator
0 commit comments