Надежно распознавать и обрабатывать определенные условия, такие как ошибки или предупреждения - PullRequest
0 голосов
/ 22 октября 2018

Я хочу улучшить обработку ошибок R, предоставив функцию для обработки определенных (выбранных) условий в сочетании с функцией повторных попыток.

Например, циклическая загрузка должна повторяться после истечения времени ожидания или ошибок подключения, но немедленно останавливаться в случаедругих ошибок.

Я не могу найти надежный способ идентифицировать конкретное условие.

Под «надежным» я подразумеваю что-то вроде идентификатора условия или хотя бы других классов условий.Моя проблема:

  1. Состояния ошибок, генерируемых базой R (а также многими пакетами, использующими stop), похоже, не используют подклассы, но (почти) всегда возвращают simpleError, error и condition как class.

  2. Сообщения об ошибках могут быть локализованы (на разных языках) и даже могут изменяться со временем в новых выпусках.

Как можно надежно распознать определенное состояние базовых пакетов R или пакетов сторонних производителей независимо от версий R, платформы (Win, OSX, Linux) и языковых настроек?

Я предполагаю, что не могу изменить источниккод, который выбрасывает условия (например, для добавления подкласса).

examine_condition <- function(exp) {
  cnd <- tryCatch(exp, error = function(e) e)
  str(cnd)  # show the internals
  invisible(cnd)
}

examine_condition(base::log("a"))
# List of 2
# $ message: chr "non-numeric argument to mathematical function"
# $ call   : language log("a")
# - attr(*, "class")= chr [1:3] "simpleError" "error" "condition"

examine_condition(base::colSums("a"))
# List of 2
# $ message: chr "'x' must be an array of at least two dimensions"
# $ call   : language base::colSums("a")
# - attr(*, "class")= chr [1:3] "simpleError" "error" "condition"

examine_condition(utils::read.csv(file = "this file does not exist.csv"))                  
# List of 2
# $ message: chr "cannot open the connection"
# $ call   : language file(file, "rt")
# - attr(*, "class")= chr [1:3] "simpleError" "error" "condition"

examine_condition(stop("my error"))
# List of 2
# $ message: chr "my error"
# $ call   : language doTryCatch(return(expr), name, parentenv, handler)
# - attr(*, "class")= chr [1:3] "simpleError" "error" "condition"

library(data.table)
data <- as.data.frame(mtcars)
examine_condition(data[, new_col := 99])  #  ":=" is data.table syntax!
# List of 2
# $ message: chr "Check that is.data.table(DT) == TRUE. Otherwise, := and `:=`(...) are defined for use in j, once only and in pa"| __truncated__
# $ call   : language `:=`(new_col, 99)
# - attr(*, "class")= chr [1:3] "simpleError" "error" "condition"

См. также:

1 Ответ

0 голосов
/ 02 ноября 2018

Вы можете получить класс cnd и проверить тип ошибки.Вот небольшой пример о загрузке файлов и о том, как бороться с различными ошибками:

# Get your items to download
downlodables <- c(paste0('https://www.google.com/', paste0(c('search?q=', '' ), month.name)))

# Iterate over them
for( i in 1:length(downlodables)){

  #Set a 
  dwnl <- tryCatch(download.file(url = downlodables[i], 
                                 destfile = paste0(getwd(),'/', i, '.htm'), 
                                 mode = 'wb'),
                   error = function (e) {e})


  # Check kind of error. Even numbers of 'i'
  class(dwnl) 

  # Check if some error appears
  if (any(class(dwnl) == 'error')){
    # or: any(class(dwnl) %in% c('error', 'warning'))

    # Print your error
    cat(paste0('\n Error found \n', dwnl, '\n'))
    write.csv(cbind(x = i, error = paste0(as.character(dwnl))), file = paste0(i, '.csv'), row.names = FALSE)

    # Conver to string your error
    detailedError <- as.character(dwnl$message) # not necessary

    # Make som in case of denied permisson
    if (any(grep('Permis', detailedError))){
      warning('U shall no pass!')
    }

    # Make som in case of time out conections. In this examlpe try 3 more times the download
    if (any(grep('time', detailedError))){
      count <- 0
      while(count =< 3){

        dwnl <- tryCatch(download.file(url = downlodables[i], 
                                       destfile = paste0(getwd(),'/', i, '.htm'), 
                                       mode = 'wb'),
                         error = function (e) {e})
        if(any(class(dwnl) == 'error')){
          count <- count + 1
        } else { 
          break() 
        }
      }
    }
  }
}
...