Skip to content

Instantly share code, notes, and snippets.

@dankrause
Last active March 15, 2023 13:51
Show Gist options
  • Select an option

  • Save dankrause/85d5388dfcb8868aa070375df8645e4f to your computer and use it in GitHub Desktop.

Select an option

Save dankrause/85d5388dfcb8868aa070375df8645e4f to your computer and use it in GitHub Desktop.
class ExceptionHandler:
def __init__(self, callback, *classes):
self._classes = [
c for c in classes if isinstance(c, type) and issubclass(c, Exception)
]
self._callback = callback
self._wrapped_func = None
def __call__(self, func):
self._wrapped_func = func
def wrapper(*args, **kwargs):
with self:
self._wrapped_func(*args, **kwargs)
return wrapper
def __enter__(self):
pass
def __exit__(self, exc_class, exc_instance, traceback):
if exc_class in self._classes:
return self._callback(exc_instance)
@classmethod
def catches(cls, *classes):
def wrapper(callback):
return cls(callback, *classes)
return wrapper
# Example usage:
class FooException(Exception):
pass
class BarException(Exception):
pass
# we can use the "catches" class method as a decorator to create an exception handler
@ExceptionHandler.catches(FooException)
def foo_handler(e):
print(f"Caught {type(e).__name__}: {e}")
return True # we return True to swallow the exception, False to let it raise
def handle_foo_and_bar(e):
print(f"Caught {type(e).__name__}: {e}")
return True
# we can create an exception handler using the class directly
foo_bar_handler = ExceptionHandler(handle_foo_and_bar, FooException, BarException)
# we can use the exception handler as a decorator to handle exceptions within the function
@foo_handler
def raise_foo(text):
raise FooException(text)
@foo_bar_handler
def raise_bar(text):
raise BarException(text)
raise_foo("in raise_foo function")
raise_bar("in raise_bar function")
# we can also use the exception handler as a context manager to handle exceptions within it's block
with foo_bar_handler:
raise FooException("inside context manager")
with foo_handler:
raise BarException("This will not be handled")
# output:
# Caught FooException: in raise_foo function
# Caught BarException: in raise_bar function
# Caught FooException: inside context manager
# Traceback (most recent call last):
# File "exception_handler.py", line 77, in <module>
# raise BarException("This will not be handled")
# __main__.BarException: This will not be handled
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment