This notebook is another 🔪 at an api to handle custom exceptions. This one does some smart healing. When a module name is used, but is not found then that object is imported.
from deathbeds.__SyntaxError_Fallbacks import fallback
import traceback, abc, fnmatch, contextlib
ip = get_ipython()
swap_exception
will temporarily permit a custom exception after it is raised.
@contextmanager
def swap_exception(Exception):
ip.custom_exceptions = tuple(x for x in ip.custom_exceptions if not issubclass(x, Exception)); yield
ip.custom_exceptions += (Exception,)
BaseExceptions
are a stateless object oriented handling different exceptions. Each of the
ip.custom_exceptions
must be handled by a single object.
class BaseExceptions(abc.ABCMeta):
def __call__(self, ip, type, Exception, tb, **kwargs):
excepts = getattr(self, type.__name__, None)
if excepts:
with swap_exception(type):
return getattr(self, type.__name__)(ip, type, Exception, tb, **kwargs)
Exceptions
uses Exception
attributes names to define customized behaviors.
When a NameError
is raised we try to import that name.
When an AttributeError
while trying to access an attrbute we import that too.
class Exceptions(metaclass=BaseExceptions):
def NameError(ip, type, Exception, tb, **kwargs):
msg = Exception.args[0]
pat = "name '*' is not defined"
if fnmatch.fnmatch(msg, pat):
left, right = pat.split('*')
result = ip.run_cell(f"import {msg[len(left):-len(right)]}", store_history=False)
if not any((result.error_in_exec, result.error_before_exec)):
result = ip.run_cell(In[-1])
return traceback.format_exception_only(type, Exception)
def AttributeError(ip, type, Exception, tb, **kwargs):
msg = Exception.args[0]
pat = "module '*' has no attribute '*'"
if fnmatch.fnmatch(msg, pat):
left, middle, right = pat.split('*')
mstart = msg.index(middle)
mend = mstart + len(middle)
result = ip.run_cell(f"import {msg[len(left):mstart]}.{msg[mend:-len(right)]}", store_history=False)
if not any((result.error_in_exec, result.error_before_exec)):
result = ip.run_cell(In[-1])
return traceback.format_exception_only(type, Exception)
fallback
reuses our markdown transformer Exception
.
Exceptions.SyntaxError = fallback
Loading the extensions.
def load_ipython_extension(ip):
ip.set_custom_exc(
tuple(getattr(__builtin__, x) for x in dir(Exceptions)
if x not in dir(abc.ABC)), Exceptions)
def unload_ipython_extension(ip): ip.set_custom_exc(tuple(), Exception)
def test_the_extension():
eval("""IPython, sklearn.preprocessing, requests, collections""")