La connaissance et la capacité à utiliser les outils de débogage de base de R est une première étape essentielle dans l'apprentissage du débogage rapide du code R. Si vous savez comment utiliser les outils de base, vous pouvez déboguer du code n'importe où sans avoir besoin de tous les outils supplémentaires fournis dans les packages d'extension.
traceback()
permet de voir la pile d'appels menant à une erreur
foo <- function(x) {
d <- bar(x)
x[1]
}
bar <- function(x) {
stopifnot(is.matrix(x))
dim(x)
}
foo(1:10)
traceback()
les rendements :
> foo(1:10)
Error: is.matrix(x) is not TRUE
> traceback()
4: stop(paste(ch, " is not ", if (length(r) > 1L) "all ", "TRUE",
sep = ""), call. = FALSE)
3: stopifnot(is.matrix(x))
2: bar(x)
1: foo(1:10)
Nous pouvons donc voir clairement que l'erreur s'est produite dans la fonction bar()
; nous avons réduit le champ de la chasse aux bugs. Mais que se passe-t-il si le code génère des avertissements et non des erreurs ? Cela peut être géré en transformant les avertissements en erreurs via l'option warn
option :
options(warn = 2)
transformera les avertissements en erreurs. Vous pouvez alors utiliser traceback()
pour les retrouver.
Il s'agit également de faire en sorte que R se remette d'une erreur dans le code afin de pouvoir déboguer ce qui n'a pas fonctionné. options(error = recover)
nous fera entrer dans un cadre de débogage chaque fois qu'une erreur sera soulevée :
> options(error = recover)
> foo(1:10)
Error: is.matrix(x) is not TRUE
Enter a frame number, or 0 to exit
1: foo(1:10)
2: bar(x)
3: stopifnot(is.matrix(x))
Selection: 2
Called from: bar(x)
Browse[1]> x
[1] 1 2 3 4 5 6 7 8 9 10
Browse[1]> is.matrix(x)
[1] FALSE
Vous voyez, nous pouvons aller dans chaque cadre de la pile d'appels et voir comment les fonctions ont été appelées, quels sont les arguments, etc. Dans l'exemple ci-dessus, nous voyons que bar()
a reçu un vecteur et non une matrice, d'où l'erreur. options(error = NULL)
rétablit ce comportement à la normale.
Une autre fonction clé est trace()
qui permet d'insérer des appels de débogage dans une fonction existante. L'avantage est que vous pouvez demander à R de déboguer à partir d'une ligne particulière du code source :
> x <- 1:10; y <- rnorm(10)
> trace(lm, tracer = browser, at = 10) ## debug from line 10 of the source
Tracing function "lm" in package "stats"
[1] "lm"
> lm(y ~ x)
Tracing lm(y ~ x) step 10
Called from: eval(expr, envir, enclos)
Browse[1]> n ## must press n <return> to get the next line step
debug: mf <- eval(mf, parent.frame())
Browse[2]>
debug: if (method == "model.frame") return(mf) else if (method != "qr") warning(gettextf("method = '%s' is not supported. Using 'qr'",
method), domain = NA)
Browse[2]>
debug: if (method != "qr") warning(gettextf("method = '%s' is not supported. Using 'qr'",
method), domain = NA)
Browse[2]>
debug: NULL
Browse[2]> Q
> untrace(lm)
Untracing function "lm" in package "stats"
Cela vous permet d'insérer les appels de débogage au bon endroit dans le code sans avoir à passer par les appels de fonctions qui suivent.
Si vous souhaitez parcourir une fonction au fur et à mesure de son exécution, alors debug(foo)
activera le débogueur pour la fonction foo()
, tandis que undebug(foo)
désactivera le débogueur.
Un point essentiel de ces options est que je n'ai pas eu besoin de modifier/éditer le code source pour insérer des appels de débogage, etc. Je peux essayer des choses et voir quel est le problème directement à partir de la session où l'erreur s'est produite.
Pour une approche différente du débogage en R, voir l'article de Mark Bravington intitulé débogage sur le CRAN