Listing functions with debug flag set in R

Viewed 2673

I am trying to find a global counterpart to isdebugged() in R. My scenario is that I have functions that make calls to other functions, all of which I've written, and I am turning debug() on and off for different functions during my debugging. However, I may lose track of which functions are set to be debugged. When I forget and start a loop, I may get a lot more output (nuisance, but not terrible) or I may get no output when some is desired (bad).

My current approach is to use a function similar to the one below, and I can call it with listDebugged(ls()) or list the items in a loaded library (examples below). This could suffice, but it requires that I call it with the list of every function in the workspace or in the packages that are loaded. I can wrap another function that obtains these. It seems like there should be an easier way to just directly "ask" the debug function or to query some obscure part of the environment where it is stashing the list of functions with the debug flag set.

So, a two part question:

  1. Is there a simpler call that exists to query the functions with the debug flag set?
  2. If not, then is there any trickery that I've overlooked? For instance, if a function in one package masks another, I suspect I may return a misleading result.

I realize that there is another method I could try and that is to wrap debug and undebug within functions that also maintain a hidden list of debugged function names. I'm not yet convinced that's a safe thing to do.

UPDATE (8/5/11): I searched SO, and didn't find earlier questions. However, SO's "related questions" list has shown that an earlier question that is similar, though the function in the answer for that question is both more verbose and slower than the function offered by @cbeleites. The older question also doesn't provide any code, while I did. :)

The code:

listDebugged    <- function(items){
    isFunction  <- vector(length = length(items))
    isDebugged  <- vector(length = length(items))

    for(ix in seq_along(items)){
        isFunction[ix]  <- is.function(eval(parse(text = items[ix])))
    }

    for(ix in which(isFunction == 1)){
        isDebugged[ix]  <- isdebugged(eval(parse(text = items[ix])))
    }
    names(isDebugged)   <- items
    return(isDebugged)
}

# Example usage
listDebugged(ls())
library(MASS)
debug(write.matrix)
listDebugged(ls("package:MASS"))
5 Answers

I constantly get caught in the browser window frame because of failing to undebug functions. So I have created two functions and added them to my .Rprofile. The helper functions are pretty straight forward.

require(logging)

# Returns a vector of functions on which the debug flag is set
debuggedFuns <- function() {
  envs <- search()
  debug_vars <- sapply(envs, function(each_env) {
    funs <- names(Filter(is.function, sapply(ls(each_env), get, each_env)))
    debug_funs <- Filter(isdebugged, funs)
    debug_funs
  })
  return(as.vector(unlist(debug_vars)))
}

# Removes the debug flag from all the functions returned by `debuggedFuns`
unDebugAll <- function(verbose = TRUE) {
  toUnDebug <- debuggedFuns()
  if (length(toUnDebug) == 0) {
    if (verbose) loginfo('no Functions to `undebug`')
    return(invisible())
  } else {
    if (verbose) loginfo('undebugging [%s]', paste0(toUnDebug, collapse = ', '))
    for (each_fn in toUnDebug) {
      undebug(each_fn)
    }
    return(invisible())
  }
}

I have tested them out, and it works pretty well. Hope this helps!

Related