R отладить все функции
Считайте, что мы назвали debug()
для нескольких функций, чтобы сделать точку останова на них. Когда мы найдем и исправим ошибку, undebug()
все функции уже отмечены debug()
одной командой?
Вот хороший тест, чтобы увидеть, действительно ли ваш предложенный метод работает идеально:
> library(limma) # bioconductor
> debug(read.ilmn)
> read.ilmn("a.txt") # No problem if this file does not exist
Browse[2]> debug(.read.oneilmnfile) # This is the debug browser for read.ilmn()
Browse[2]> Q # To exit debug browser
> undebug.all() # Here run your proposed function to undebug everything!
> read.ilmn("a.txt")
# Now if the debug browser is not started, you are lucky to pass this test!
Вы можете увидеть принятый ответ ниже. В любом случае, если этот ответ не работает или более чистые версии приветствуются.
3 ответа
Это было мое решение...
редактировать: исправлено для поиска объектов в пространствах имен. Код уже становится немного грубоватым, так как я не очень хорошо понимаю методы манипулирования / запроса пространств имен, и так как я работал методом проб и ошибок. Более чистые версии будут приветствоваться. Есть почти наверняка другие угловые случаи, которые потерпят неудачу.
## 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))
}
Код также размещен на http://www.math.mcmaster.ca/bolker/R/misc/undebug_all.R
Пример:
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
В этом случае lme
работает без входа в отладчик.
Другой, более сложный пример:
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")
Обратите внимание, что read.ilmn()
а также read.ilmn("a.txt")
похоже, ведут себя по-разному с точки зрения отладки (я не понимаю, почему...)
Нет, не существует абсолютно надежного способа undebug()
все функции. (Я говорю это только потому, что несколько раз обсуждал это на тему R-devel и R-help.)
В этой дискуссии взвесился Брайан Рипли, отметив, что:
Отладка - это свойство функционального объекта (немного в sxpinfo), и поэтому вам придется пройти через все достижимые объекты (как это делает gc), чтобы найти их все.
Вот фрагмент, в котором Роберт Джентльмен отвечает (отрицательно) на вопрос о том, "есть ли удобный способ узнать в любое время, какая функция помечена debug()
или же trace()
в сеансе R ":
Вы, вероятно, не получили ответ, потому что ответ - нет, простого пути нет.
Вот один из вариантов, если предположить, что отлаживаемые функции находятся в рабочей области или глобальной среде. Можно указать любую конкретную среду, чтобы она была адаптируемой, но это не будет работать для любой функции во всех загруженных пакетах за один раз.
Сначала проиллюстрируем через пару функций в глобальной среде:
> bar <- function() {}
> foo <- function() {}
использование lsf.str()
вернуть функции в рабочем пространстве (для использования позже мы unclass()
это и преобразовать его в список):
> funlist <- as.list(unclass(lsf.str()))
> funlist
[[1]]
[1] "bar"
[[2]]
[1] "foo"
Затем создайте индикатор для этих функций относительно того, отлажены ли они:
> debugged <- sapply(funlist, isdebugged)
> debugged
[1] FALSE FALSE
Итак debug()
одну из функций и перезапустите:
> debug(bar)
>
> debugged <- sapply(funlist, isdebugged)
> debugged
[1] TRUE FALSE
в заключение sapply()
над funlist
функции, которые отлажены, применяя undebug()
им:
> sapply(funlist[debugged], undebug)
[[1]]
NULL
Это, конечно, может быть включено в функцию
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
Один тип отладки, не поднятый isdebugged()
это принято через debugonce()
:
> debug(bar)
> isdebugged(bar)
[1] TRUE
> undebugFuns()
Un-debugging: bar
> debugonce(bar)
> isdebugged(bar)
[1] FALSE
Который просто повторяет точку зрения Джоша в его Ответе.