31

debug()それらにブレークポイントを作成するためにいくつかの関数を呼び出したと考えてください。バグを見つけて解決するとき、1つのコマンドで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!

受け入れられた回答が以下に表示される場合があります。この回答が機能しない場合、またはよりクリーンなバージョンは大歓迎です。

4

3 に答える 3

16

これが私の解決策でした...

edit : 名前空間内のオブジェクトの検索に対処するように改訂されました。名前空間を操作/クエリする方法がよくわからず、試行錯誤して作業していたため、コードはすでに少し粗雑になっています。よりクリーンなバージョンは大歓迎です。ほとんどの場合、失敗する他のコーナー ケースがあります。

## 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")(理由はわかりません...)

于 2012-10-09T20:06:04.360 に答える
16

undebug()いいえ、すべての機能に対して完全に信頼できる方法はありません。(私がこれを言うのは、R-devel と R-help で何度か議論されているのを見たからです。)

このディスカッションでは、Brian Ripley が次のように述べています。

デバッグは関数オブジェクト (sxpinfo の一部) のプロパティであるため、(gc のように) 到達可能なすべてのオブジェクトを走査してすべてを見つける必要があります。

次のスニペットでは、Robert Gentleman が「R セッションで、またはR セッションでフラグが立てられた関数をいつでも知る便利な方法があるか」という質問に (否定的に) 答えています。debug()trace()

答えはノーです。簡単な方法はありません。

于 2012-10-09T20:04:17.697 に答える
8

デバッグしている関数がワークスペースまたはグローバル環境にあると仮定して、1 つのオプションを次に示します。任意の特定の環境を指定できるため、適応性がありますが、これは、ロードされたすべてのパッケージの任意の機能に対して一度に機能するものではありません。

最初に、グローバル環境でいくつかの関数を使用して説明します。

> 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

OK、debug()関数の 1 つを再実行します。

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

最後に、それらに適用されてデバッグされる関数sapply()について:funlistundebug()

> 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

によってピックアップされないデバッグの 1 つのタイプは、次の方法で実行isdebugged()されdebugonce()ます。

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

これは、ジョシュのアンサーでのポイントをもう一度強調するだけです。

于 2012-10-09T20:02:37.110 に答える