Подтвердить что ты не робот

Есть ли способ `source()` и продолжить после ошибки?

У меня есть большой R script, скажем, 142 небольших раздела. Если один раздел завершился с ошибкой, я бы хотел, чтобы script продолжал, а не останавливался. Секции не обязательно зависят друг от друга, но некоторые делают. Если кто-то посередине терпит неудачу, это нормально. Я бы предпочел не перенести этот script на вызовы try(). И я бы предпочел не разделить файл на несколько небольших файлов, так как каждый раздел довольно короткий.

Если source() можно заставить работать так, как если бы он был скопирован и вставлен в консоль R, это было бы здорово. Или, если есть способ понизить ошибку до предупреждения, это тоже будет хорошо.

После запуска script я намерен grep (или аналогичный) вывод для текста с ошибкой или предупреждением, чтобы я мог видеть все ошибки или предупреждения, которые произошли, а не только то, что он остановился на первой ошибке.

Я прочитал ?source и искал тег Qaru [R]. Я нашел следующие похожие вопросы, но ответы try и tryCatch были предоставлены:

R script - Как продолжить выполнение кода при ошибке
Есть ли способ, чтобы R script продолжался после получения сообщений об ошибках вместо остановки выполнения?

Я не ищу try или tryCatch по указанным выше причинам. Это не для тестирования пакетов R, где я знаю рамки тестирования и где многие вызовы try() или test_that() (или аналогичные) являются полностью подходящими. Это для чего-то еще, где у меня есть script, как описано.

Спасибо!

4b9b3361

Ответ 1

Чтобы сделать это более конкретным, как насчет следующего?

Во-первых, чтобы проверить подход, создайте файл (назовите его "script.R"), содержащий несколько операторов, первый из которых будет вызывать ошибку при оценке.

## script.R

rnorm("a")
x <- 1:10
y <- 2*x

Затем проанализируйте его в списке выражений и оцените каждый элемент в свою очередь, обернув оценку внутри вызова tryCatch(), чтобы ошибки не наносили слишком большого ущерба:

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

Ответ 2

Пакет оценивать предоставляет еще одну опцию с помощью функции evaluate(). Это не так легко, как мое другое предложение, но - как одна из функций, лежащих в основе knitr, - она ​​была также проверена так, как вы могли надеяться!

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

Для вывода, который больше похож на то, что вы действительно написали инструкции в командной строке, используйте replay(). (Спасибо hadley за подсказку):

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

Изменить

replay() также предлагает лучший способ воспроизвести только ошибки и предупреждения, если это все, что вам нужно:

## 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
# > 

Ответ 3

Это неудобно и не использует друга eval(parse(, но может быть несколько полезным. Ответ на josh намного чище.

# 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 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 an actual error and needs to be just plain skipped.
    if ( !grepl( 'unexpected end of input' , err ) ) j <- i + 1

    # otherwise it an "end of line" error, which just means j alone.
}