def debug(victim=None, ignore_exceptions=(), catch_exception=None, depth=0):
    """A decorator function to catch exceptions and enter debug mode.

    Args:
        victim (typing.Union(type, function)): either a class or function to
            wrap and debug.
        ignore_exceptions (list): list of classes of exceptions not to catch.
        catch_exception (type): class of exception to catch and debug.
            default is None, meaning catch all exceptions.
        depth (number): how many levels of inner function calls to propagate.

    Returns:
        object. wrapped class or function.

    Note:
        This wrapper avoids recursion by setting a flag to each wrapped item.
    """
    if victim is None:
        # Debug is used as a decorator so we need to return wrap function to
        # get the real victim
        def wrapper(real_victim):
            return debug(real_victim, ignore_exceptions,
                         catch_exception, depth)

        return wrapper

    if inspect.isfunction(victim):
        if hasattr(victim, '_ipdebug_wrapped'):
            # Don't wrap the function more than once
            return victim

        _transformer = ErrorsCatchTransformer(
            ignore_exceptions=ignore_exceptions,
            catch_exception=catch_exception,
            depth=depth)

        try:
            # Try to get the source code of the wrapped object.
            sourcelines, start_num = inspect.getsourcelines(victim.__code__)
            indent = re.match(r'\s*', sourcelines[0]).group()
            source = ''.join(l.replace(indent, '', 1) for l in sourcelines)

        except IOError:
            # Worst-case scenario we can only catch errors at a granularity
            # of the whole function
            return victim

        else:
            # If we have access to the source, we can silence errors on a
            # per-expression basis, which is "better"

            old_code_tree = ast.parse(source)
            # Reposition the line numbers to their original value
            ast.increment_lineno(old_code_tree, start_num - 1)
            tree = _transformer.visit(old_code_tree)

            import_debug_cmd = ast.ImportFrom(
                __name__, [ast.alias("start_debugging", None),
                           ast.alias("debug", None)], 0)

            # Add import to the debugger as first command
            tree.body[0].body.insert(0, import_debug_cmd)

            # Add import to the exception classes
            if catch_exception is not None:
                import_exception_cmd = ast.ImportFrom(
                    catch_exception.__module__,
                    [ast.alias(catch_exception.__name__, None)], 0)

                tree.body[0].body.insert(1, import_exception_cmd)

            if ignore_exceptions is not None:
                for exception_class in ignore_exceptions:
                    import_exception_cmd = ast.ImportFrom(
                        exception_class.__module__,
                        [ast.alias(exception_class.__name__, None)], 0)

                    tree.body[0].body.insert(1, import_exception_cmd)

            # Delete the debugger decorator of the function
            del tree.body[0].decorator_list[:]

            # Add pass at the end (to enable debugging the last command)
            pass_cmd = ast.Pass()
            func_body = tree.body[0].body
            pass_cmd.lineno = get_last_lineno(func_body[-1]) + 1
            pass_cmd.col_offset = func_body[-1].col_offset
            func_body.append(pass_cmd)

            # Fix missing line numbers and column offsets before compiling
            for node in ast.walk(tree):
                if not hasattr(node, 'lineno'):
                    node.lineno = 0

            ast.fix_missing_locations(tree)

            # Define the wrapping function object
            function_definition = "def _free_vars_wrapper(): pass"
            wrapping_function = ast.parse(function_definition).body[0]

            # Initialize closure's variables to None
            body_list = [ast.parse("{var} = None".format(var=free_var)).body[0]
                         for free_var in victim.__code__.co_freevars]

            # Add the original function ("victim") to the wrapping function
            body_list.append(tree.body[0])

            wrapping_function.body = body_list

            # Replace original function ("victim") with the wrapping function
            tree.body[0] = wrapping_function

            # Create a new runnable code object to replace the original code
            code = compile(tree, victim.__code__.co_filename, 'exec')
            victim.__code__ = code.co_consts[0].co_consts[1]

            # Set a flag to indicate that the method was wrapped
            victim._ipdebug_wrapped = True

            return victim

    elif inspect.ismethod(victim):
        debug(victim.__func__, ignore_exceptions, catch_exception)
        return victim

    elif isinstance(victim, type):
        # Wrap each method of the class with the debugger
        for name, member in vars(victim).items():
            if isinstance(member, (type, types.FunctionType,
                                   types.LambdaType, types.MethodType)):
                setattr(victim, name,
                        debug(member, ignore_exceptions, catch_exception))

        return victim

    else:
        raise TypeError(
            "Debugger can only wrap functions and classes. "
            "Got object {!r} of type {}".format(victim, type(victim).__name__))
def debug ( victim = None , ignore_exceptions = ( ) , catch_exception = None , depth = 0 ) : if victim is None : def wrapper ( real_victim ) : return debug ( real_victim , ignore_exceptions , catch_exception , depth ) return wrapper if inspect . isfunction ( victim ) : if hasattr ( victim , '_ipdebug_wrapped' ) : return victim _transformer = ErrorsCatchTransformer ( ignore_exceptions = ignore_exceptions , catch_exception = catch_exception , depth = depth ) try : sourcelines , start_num = inspect . getsourcelines ( victim . __code__ ) indent = re . match ( r'\s*' , sourcelines [ 0 ] ) . group ( ) source = '' . join ( l . replace ( indent , '' , 1 ) for l in sourcelines ) except IOError : return victim else : old_code_tree = ast . parse ( source ) ast . increment_lineno ( old_code_tree , start_num - 1 ) tree = _transformer . visit ( old_code_tree ) import_debug_cmd = ast . ImportFrom ( __name__ , [ ast . alias ( "start_debugging" , None ) , ast . alias ( "debug" , None ) ] , 0 ) tree . body [ 0 ] . body . insert ( 0 , import_debug_cmd ) if catch_exception is not None : import_exception_cmd = ast . ImportFrom ( catch_exception . __module__ , [ ast . alias ( catch_exception . __name__ , None ) ] , 0 ) tree . body [ 0 ] . body . insert ( 1 , import_exception_cmd ) if ignore_exceptions is not None : for exception_class in ignore_exceptions : import_exception_cmd = ast . ImportFrom ( exception_class . __module__ , [ ast . alias ( exception_class . __name__ , None ) ] , 0 ) tree . body [ 0 ] . body . insert ( 1 , import_exception_cmd ) del tree . body [ 0 ] . decorator_list [ : ] pass_cmd = ast . Pass ( ) func_body = tree . body [ 0 ] . body pass_cmd . lineno = get_last_lineno ( func_body [ - 1 ] ) + 1 pass_cmd . col_offset = func_body [ - 1 ] . col_offset func_body . append ( pass_cmd ) for node in ast . walk ( tree ) : if not hasattr ( node , 'lineno' ) : node . lineno = 0 ast . fix_missing_locations ( tree ) function_definition = "def _free_vars_wrapper(): pass" wrapping_function = ast . parse ( function_definition ) . body [ 0 ] body_list = [ ast . parse ( "{var} = None" . format ( var = free_var ) ) . body [ 0 ] for free_var in victim . __code__ . co_freevars ] body_list . append ( tree . body [ 0 ] ) wrapping_function . body = body_list tree . body [ 0 ] = wrapping_function code = compile ( tree , victim . __code__ . co_filename , 'exec' ) victim . __code__ = code . co_consts [ 0 ] . co_consts [ 1 ] victim . _ipdebug_wrapped = True return victim elif inspect . ismethod ( victim ) : debug ( victim . __func__ , ignore_exceptions , catch_exception ) return victim elif isinstance ( victim , type ) : for name , member in vars ( victim ) . items ( ) : if isinstance ( member , ( type , types . FunctionType , types . LambdaType , types . MethodType ) ) : setattr ( victim , name , debug ( member , ignore_exceptions , catch_exception ) ) return victim else : raise TypeError ( "Debugger can only wrap functions and classes. " "Got object {!r} of type {}" . format ( victim , type ( victim ) . __name__ ) )
A decorator function to catch exceptions and enter debug mode.

    Args:
        victim (typing.Union(type, function)): either a class or function to
            wrap and debug.
        ignore_exceptions (list): list of classes of exceptions not to catch.
        catch_exception (type): class of exception to catch and debug.
            default is None, meaning catch all exceptions.
        depth (number): how many levels of inner function calls to propagate.

    Returns:
        object. wrapped class or function.

    Note:
        This wrapper avoids recursion by setting a flag to each wrapped item.