Skip to content

Instantly share code, notes, and snippets.

@outofmbufs
Last active January 3, 2021 23:16
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save outofmbufs/906178bab109ac7e4cab210c27687ea7 to your computer and use it in GitHub Desktop.
Save outofmbufs/906178bab109ac7e4cab210c27687ea7 to your computer and use it in GitHub Desktop.
Python decorator to convert exception into function return value
import functools
__IGX_SENTINEL = object() # sentinel for a "default argument" see below
def IgnoreExceptionsDecorator(excepts, *, exception_result=__IGX_SENTINEL):
"""Decorator - catch exceptions and convert to a return value.
'excepts' - exceptions (as a tuple, or a single exception) to catch
'exception_result' - if specified, the return value to use when
any of the 'excepts' happens.
If no exception_result is given, then the exception info itself
is returned if one of the 'excepts' occurs.
"""
# determine whether an explicit exception return was given or not...
return_the_exception = exception_result is __IGX_SENTINEL
# _deco is the outer/callable decorator object that will be called
# to decorate the function, and will (at that time) return the inner
# _ig() function which represents the wrapped/decorated function.
def _deco(f):
@functools.wraps(f)
def _ig(*args, **kwargs):
try:
return f(*args, **kwargs)
except excepts as e:
return e if return_the_exception else exception_result
return _ig
return _deco
# test code and example of how to use
if __name__ == "__main__":
import unittest
import math
class Foo:
pass
@IgnoreExceptionsDecorator(AttributeError, exception_result=42)
def return_bar(x):
return x.bar
@IgnoreExceptionsDecorator(AttributeError)
def return_e(x):
return x.bar
@IgnoreExceptionsDecorator((TypeError, ZeroDivisionError),
exception_result=math.nan)
def divideby(a, b):
return a/b
# the point here is to show that uncaught exceptions still work
@IgnoreExceptionsDecorator(AttributeError)
def div0():
return 1 / 0
class TestMethods(unittest.TestCase):
def test_1(self):
f = Foo()
self.assertEqual(return_bar(f), 42)
def test_2(self):
f = Foo()
f.bar = 17
self.assertEqual(return_bar(f), 17)
def test_3(self):
f = Foo()
e = return_e(f)
self.assertTrue(isinstance(e, AttributeError))
def test_4(self):
f = Foo()
f.bar = 17
e = return_e(f)
self.assertEqual(e, 17)
def test_5(self):
self.assertTrue(math.isnan(divideby(6, 0)))
def test_6(self):
self.assertTrue(math.isnan(divideby(6, '!')))
def test_7(self):
self.assertRaises(ZeroDivisionError, div0)
unittest.main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment