Reputation: 8750
I want to improve the R error handling by providing a function to handle specific (selected) conditions combined with a retry feature.
For example looped downloads should retry after timeouts or connection errors but stop immediately in case of other errors.
I cannot find a reliable way to identify a specific condition.
With "reliable" I mean something like a condition ID or at least different condition classes. My problem is:
Error conditions thrown by base R (and also many packages using stop
)
seem not to use sub classes but (almost) always return simpleError
, error
and condition
as class
.
Error messages may be localized (different languages) and could even change over time with new releases.
How can I reliably recognize a specific condition of base R or 3rd party packages independently of the R versions, platform (Win, OSX, Linux) and language setting?
I assume that I cannot modify the source code that throws the conditions (e. g. to add a sub class).
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"
See also:
Upvotes: 6
Views: 514
Reputation: 1360
You can get the class of cnd
and check the kind of error.
Here a little example about download files and how to deal with diferent errors:
# 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()
}
}
}
}
}
Upvotes: 2