def set_custom_exc(self, exc_tuple, handler):
    "set_custom_exc(exc_tuple, handler)\n\n        Set a custom exception handler, which will be called if any of the\n        exceptions in exc_tuple occur in the mainloop (specifically, in the\n        run_code() method).\n\n        Parameters\n        ----------\n        exc_tuple : tuple of exception classes\n            A *tuple* of exception classes, for which to call the defined\n            handler.  It is very important that you use a tuple, and NOT A\n            LIST here, because of the way Python's except statement works.  If\n            you only want to trap a single exception, use a singleton tuple::\n\n                exc_tuple == (MyCustomException,)\n\n        handler : callable\n            handler must have the following signature::\n\n                def my_handler(self, etype, value, tb, tb_offset=None):\n                    ...\n                    return structured_traceback\n\n            Your handler must return a structured traceback (a list of strings),\n            or None.\n\n            This will be made into an instance method (via types.MethodType)\n            of IPython itself, and it will be called if any of the exceptions\n            listed in the exc_tuple are caught. If the handler is None, an\n            internal basic one is used, which just prints basic info.\n\n            To protect IPython from crashes, if your handler ever raises an\n            exception or returns an invalid result, it will be immediately\n            disabled.\n\n        Notes\n        -----\n        WARNING: by putting in your own exception handler into IPython's main\n        execution loop, you run a very good chance of nasty crashes.  This\n        facility should only be used if you really know what you are doing.\n        "
    if (not isinstance(exc_tuple, tuple)):
        raise TypeError('The custom exceptions must be given as a tuple.')

    def dummy_handler(self, etype, value, tb, tb_offset=None):
        print('*** Simple custom exception handler ***')
        print('Exception type :', etype)
        print('Exception value:', value)
        print('Traceback      :', tb)

    def validate_stb(stb):
        'validate structured traceback return type\n\n            return type of CustomTB *should* be a list of strings, but allow\n            single strings or None, which are harmless.\n\n            This function will *always* return a list of strings,\n            and will raise a TypeError if stb is inappropriate.\n            '
        msg = ('CustomTB must return list of strings, not %r' % stb)
        if (stb is None):
            return []
        elif isinstance(stb, str):
            return [stb]
        elif (not isinstance(stb, list)):
            raise TypeError(msg)
        for line in stb:
            if (not isinstance(line, str)):
                raise TypeError(msg)
        return stb
    if (handler is None):
        wrapped = dummy_handler
    else:

        def wrapped(self, etype, value, tb, tb_offset=None):
            'wrap CustomTB handler, to protect IPython from user code\n\n                This makes it harder (but not impossible) for custom exception\n                handlers to crash IPython.\n                '
            try:
                stb = handler(self, etype, value, tb, tb_offset=tb_offset)
                return validate_stb(stb)
            except:
                self.set_custom_exc((), None)
                print('Custom TB Handler failed, unregistering', file=sys.stderr)
                stb = self.InteractiveTB.structured_traceback(*sys.exc_info())
                print(self.InteractiveTB.stb2text(stb))
                print('The original exception:')
                stb = self.InteractiveTB.structured_traceback((etype, value, tb), tb_offset=tb_offset)
            return stb
    self.CustomTB = types.MethodType(wrapped, self)
    self.custom_exceptions = exc_tuple
set_custom_exc(exc_tuple, handler)

Set a custom exception handler, which will be called if any of the
exceptions in exc_tuple occur in the mainloop (specifically, in the
run_code() method).

Parameters
----------
exc_tuple : tuple of exception classes
    A *tuple* of exception classes, for which to call the defined
    handler.  It is very important that you use a tuple, and NOT A
    LIST here, because of the way Python's except statement works.  If
    you only want to trap a single exception, use a singleton tuple::

        exc_tuple == (MyCustomException,)

handler : callable
    handler must have the following signature::

        def my_handler(self, etype, value, tb, tb_offset=None):
            ...
            return structured_traceback

    Your handler must return a structured traceback (a list of strings),
    or None.

    This will be made into an instance method (via types.MethodType)
    of IPython itself, and it will be called if any of the exceptions
    listed in the exc_tuple are caught. If the handler is None, an
    internal basic one is used, which just prints basic info.

    To protect IPython from crashes, if your handler ever raises an
    exception or returns an invalid result, it will be immediately
    disabled.

Notes
-----
WARNING: by putting in your own exception handler into IPython's main
execution loop, you run a very good chance of nasty crashes.  This
facility should only be used if you really know what you are doing.
def set_custom_exc(self, exc_tuple, handler):
    "set_custom_exc(exc_tuple, handler)\n\n        Set a custom exception handler, which will be called if any of the\n        exceptions in exc_tuple occur in the mainloop (specifically, in the\n        run_code() method).\n\n        Parameters\n        ----------\n        exc_tuple : tuple of exception classes\n            A *tuple* of exception classes, for which to call the defined\n            handler.  It is very important that you use a tuple, and NOT A\n            LIST here, because of the way Python's except statement works.  If\n            you only want to trap a single exception, use a singleton tuple::\n\n                exc_tuple == (MyCustomException,)\n\n        handler : callable\n            handler must have the following signature::\n\n                def my_handler(self, etype, value, tb, tb_offset=None):\n                    ...\n                    return structured_traceback\n\n            Your handler must return a structured traceback (a list of strings),\n            or None.\n\n            This will be made into an instance method (via types.MethodType)\n            of IPython itself, and it will be called if any of the exceptions\n            listed in the exc_tuple are caught. If the handler is None, an\n            internal basic one is used, which just prints basic info.\n\n            To protect IPython from crashes, if your handler ever raises an\n            exception or returns an invalid result, it will be immediately\n            disabled.\n\n        Notes\n        -----\n        WARNING: by putting in your own exception handler into IPython's main\n        execution loop, you run a very good chance of nasty crashes.  This\n        facility should only be used if you really know what you are doing.\n        "
    if (not isinstance(exc_tuple, tuple)):
        raise TypeError('The custom exceptions must be given as a tuple.')

    def dummy_handler(self, etype, value, tb, tb_offset=None):
        print('*** Simple custom exception handler ***')
        print('Exception type :', etype)
        print('Exception value:', value)
        print('Traceback      :', tb)

    def validate_stb(stb):
        'validate structured traceback return type\n\n            return type of CustomTB *should* be a list of strings, but allow\n            single strings or None, which are harmless.\n\n            This function will *always* return a list of strings,\n            and will raise a TypeError if stb is inappropriate.\n            '
        msg = ('CustomTB must return list of strings, not %r' % stb)
        if (stb is None):
            return []
        elif isinstance(stb, str):
            return [stb]
        elif (not isinstance(stb, list)):
            raise TypeError(msg)
        for line in stb:
            if (not isinstance(line, str)):
                raise TypeError(msg)
        return stb
    if (handler is None):
        wrapped = dummy_handler
    else:

        def wrapped(self, etype, value, tb, tb_offset=None):
            'wrap CustomTB handler, to protect IPython from user code\n\n                This makes it harder (but not impossible) for custom exception\n                handlers to crash IPython.\n                '
            try:
                stb = handler(self, etype, value, tb, tb_offset=tb_offset)
                return validate_stb(stb)
            except:
                self.set_custom_exc((), None)
                print('Custom TB Handler failed, unregistering', file=sys.stderr)
                stb = self.InteractiveTB.structured_traceback(*sys.exc_info())
                print(self.InteractiveTB.stb2text(stb))
                print('The original exception:')
                stb = self.InteractiveTB.structured_traceback((etype, value, tb), tb_offset=tb_offset)
            return stb
    self.CustomTB = types.MethodType(wrapped, self)
    self.custom_exceptions = exc_tuple