I have a large R script of, say, 142 small sections. If one section fails with an error I\'d like the script to continue rather than halt. The sections don\'t necessarily de
this is clunky and uses nobody's friend eval(parse(
but might be somewhat helpful.. josh's answer is much cleaner.
# assign the filepath
fn <- "c:/path/to your/script.R"
# read in the whole script
z <- readLines( fn )
# set a starting j counter
j <- 1
# loop through each line in your script..
for ( i in seq(length(z)) ) {
# catch errors
err <- try( eval( parse( text = z[j:i] ) ) , silent = TRUE )
# if it's not an error, move your j counter up to one past i
if ( class( err ) != 'try-error' ) j <- i + 1 else
# otherwise, if the error isn't an "end of input" error,
# then it's an actual error and needs to be just plain skipped.
if ( !grepl( 'unexpected end of input' , err ) ) j <- i + 1
# otherwise it's an "end of line" error, which just means j alone.
}
The evaluate package supplies another option with its evaluate()
function. It's not as light-weight as my other suggestion, but -- as one of the functions underpinning knitr -- its been as well tested as you could hope for!
library(evaluate)
rapply((evaluate(file("script.R"))), cat) # For "script.R", see my other answer
# rnorm("a")
# NAs introduced by coercionError in rnorm("a") : invalid arguments
# In addition: Warning message:
# In rnorm("a") : NAs introduced by coercion
x
# [1] 1 2 3 4 5 6 7 8 9 10
y
# [1] 2 4 6 8 10 12 14 16 18 20
For output that looks more like you had actually typed the statements in at the command-line, use replay()
. (Thanks to hadley for the tip):
replay(evaluate(file("script.R")))
# >
# > rnorm("a")
# Warning message:
# NAs introduced by coercion
# Error in rnorm("a"): invalid arguments
# > x <- 1:10
# > y <- 2*x
Edit
replay()
also offers a better way to play back just the errors and warnings, if those are all that you need:
## Capture the output of evaluate()
res <- evaluate(file("script.R"))
## Identify those elements inheriting from "error" or "warning
ii <- grepl("error|warning", sapply(res, class))
## Replay the errors and warnings
replay(res[ii])
# Warning message:
# NAs introduced by coercion
# Error in rnorm("a"): invalid arguments
# >
To make this more concrete, how about the following?
First, to test the approach, create a file (call it "script.R"
) containing several statements, the first of which will throw an error when evaluated.
## script.R
rnorm("a")
x <- 1:10
y <- 2*x
Then parse it into a expression list, and evaluate each element in turn, wrapping the evaluation inside a call to tryCatch()
so that errors won't cause too much damage:
ll <- parse(file = "script.R")
for (i in seq_along(ll)) {
tryCatch(eval(ll[[i]]),
error = function(e) message("Oops! ", as.character(e)))
}
# Oops! Error in rnorm("a"): invalid arguments
#
# Warning message:
# In rnorm("a") : NAs introduced by coercion
x
# [1] 1 2 3 4 5 6 7 8 9 10
y
# [1] 2 4 6 8 10 12 14 16 18 20