Is there a way to `source()` and continue after an error?

前端 未结 3 695
南方客
南方客 2020-11-28 05:45

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

相关标签:
3条回答
  • 2020-11-28 06:03

    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.
    }
    
    0 讨论(0)
  • 2020-11-28 06:19

    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
    # > 
    
    0 讨论(0)
  • 2020-11-28 06:20

    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
    
    0 讨论(0)
提交回复
热议问题