undebug all functions

前端 未结 3 1839
暗喜
暗喜 2021-02-03 22:27

Consider we have called debug() for several functions to make a breakpoint on them. When we find and solve the bug, is there anyway to undebug() all fu

相关标签:
3条回答
  • 2021-02-03 23:02

    This was my solution ...

    edit: revised to deal with finding objects in namespaces. The code is already getting a little bit crufty, since I don't really understand the methods for manipulating/querying namespaces all that well, and since I was working by trial and error. Cleaner versions would be welcome. There are almost certainly other corner cases that will fail.

    ## return the names of the objects (from a vector of list of
    ## names of objects) that are functions and have debug flag set
    isdebugged_safe <- function(x,ns=NULL)  {
        g <- if (is.null(ns)) get(x) else getFromNamespace(x,ns)
        is.function(g) && isdebugged(g)
    }
    
    which_debugged <- function(objnames,ns=NULL) {
        if (!length(objnames)) return(character(0))
        objnames[sapply(objnames,isdebugged_safe,ns=ns)]
    }
    
    all_debugged <- function(where=search(), show_empty=FALSE) {
        ss <- setNames(lapply(where,function(x) {
            which_debugged(ls(x,all.names=TRUE))
            }),gsub("package:","",where))
        ## find attached namespaces
        ## (is there a better way to test whether a 
        ##    namespace exists with a given name??)
        ns <- unlist(sapply(gsub("package:","",where),
                     function(x) {
                         if (inherits({n <- try(getNamespace(x),silent=TRUE)},
                             "try-error")) NULL else x
                     }))
        ss_ns <- setNames(lapply(ns,function(x) {
            objects <- ls(getNamespace(x),all.names=TRUE)
            which_debugged(objects,ns=x)
            }),ns)
        if (!show_empty) {
            ss <- ss[sapply(ss,length)>0]
            ss_ns <- ss_ns[sapply(ss_ns,length)>0]
        }
        ## drop overlaps
        for (i in names(ss))
            ss_ns[[i]] <- setdiff(ss_ns[[i]],ss[[i]])
        list(env=ss,ns=ss_ns)
    }
    
    undebug_all <- function(where=search()) {
        aa <- all_debugged(where)
        lapply(aa$env,undebug)
        ## now debug namespaces
        invisible(mapply(function(ns,fun) {
            undebug(getFromNamespace(fun,ns))
        },names(aa$ns),aa$ns))
    }
    

    The code is also posted at http://www.math.mcmaster.ca/bolker/R/misc/undebug_all.R

    Example:

    library(nlme)
    debug(lme)
    ## define functions
    source(url("http://www.math.mcmaster.ca/bolker/R/misc/undebug_all.R"))
    undebug_all()
    fm1 <- lme(distance ~ age, data = Orthodont) # from ?lme
    

    In this case lme runs without entering the debugger.

    Another, harder example:

    library(limma)
    source(url("http://www.math.mcmaster.ca/bolker/R/misc/undebug_all.R"))
    debug(read.ilmn)
    debug(limma:::.read.oneilmnfile)
    all_debugged()
    undebug_all()
    read.ilmn()
    read.ilmn("a.txt")
    

    Note that read.ilmn() and read.ilmn("a.txt") appear to behave differently from a debugging standpoint (I don't understand why ...)

    0 讨论(0)
  • 2021-02-03 23:06

    Here is one option, assuming that the functions you are debugging are in the workspace or global environment. Any particular environment can be specified so it is adaptable but this isn't going to be something that works for any function in all loaded packages in a single go.

    First illustrate via a couple of functions in the global environment:

    > bar <- function() {}
    > foo <- function() {}
    

    Use lsf.str() to return the functions in the workspace (for use later we unclass() this and convert it to a list):

    > funlist <- as.list(unclass(lsf.str()))
    > funlist
    [[1]]
    [1] "bar"
    
    [[2]]
    [1] "foo"
    

    Next, produce an indicator for these functions as to whether they are debugged:

    > debugged <- sapply(funlist, isdebugged)
    > debugged
    [1] FALSE FALSE
    

    OK, so debug() one of the functions and rerun:

    > debug(bar)
    > 
    > debugged <- sapply(funlist, isdebugged)
    > debugged
    [1]  TRUE FALSE
    

    Finally sapply() over funlist functions that are debugged applying undebug() to them:

    > sapply(funlist[debugged], undebug)
    [[1]]
    NULL
    

    This of course could be encapsulated into a function

    undebugFuns <- function() {
        funs <- unclass(lsf.str())
        dbg <- sapply(funs, isdebugged)
        if(isTRUE(any(dbg))) {
            writeLines(paste("Un-debugging:", funs[dbg]))
            sapply(funs[dbg], undebug)
        } else {
            writeLines(paste("Nothing to debug"))
        }
        invisible()
    }
    
    > debug(bar)
    > undebugFuns()
    Un-debugging: bar
    

    One type of debugging not picked up by isdebugged() is that enacted via debugonce():

    > debug(bar)
    > isdebugged(bar)
    [1] TRUE
    > undebugFuns()
    Un-debugging: bar
    > debugonce(bar)
    > isdebugged(bar)
    [1] FALSE
    

    Which just goes to make Josh's point in his Answer again.

    0 讨论(0)
  • 2021-02-03 23:12

    No, there is no completely reliable way to undebug() all functions. (I only say this because I've seen it discussed several times on R-devel and R-help.)

    In this discussion, Brian Ripley weighed in, noting that:

    Debugging is a property of a function object (a bit in the sxpinfo) and so you would have to traverse all reachable objects (as gc does) to find them all.

    Here's a snippet in which Robert Gentleman answers (in the negative) a question about whether "there is a convenient way to know at any time which are the function flagged with debug() or trace() in a R session":

    You probably didn't get an answer because the answer is no, there is no easy way.

    0 讨论(0)
提交回复
热议问题