Disregarding Simple Warnings/Errors in Trycatch()

Disregarding simple warnings/errors in tryCatch()

I think you're looking for the difference between tryCatch, which catches a condition and continues evaluation from the environment where the tryCatch was defined, versus withCallingHandlers, which allows you to 'handle' a condition and then continue on from the location where the condition occurred. Take a look at warning (or the help page for warning, but that's less fun), especially the lines

    withRestarts({
.Internal(.signalCondition(cond, message, call))
.Internal(.dfltWarn(message, call))
}, muffleWarning = function() NULL)

This says -- signal a condtion, but insert a 'restart' where the condition was signaled from. Then you'd

withCallingHandlers({
warning("curves ahead")
2
}, warning = function(w) {
## what are you going to do with the warning?
message("warning occurred: ", conditionMessage(w))
invokeRestart("muffleWarning")
})

Although withCallingHandlers is often used with warnings and tryCatch with errors, there is nothing to stop one from 'handling' an error or catching a warning if that is the appropriate action.

Store errors and warnings with tryCatch() in a list

Here's a version that puts the tryCatch within the loop, and saves the errors and warnings that were generated:

  hospitals_url <- "https://services1.arcgis.com/Hp6G80Pky0om7QvQ/arcgis/rest/services/Hospitals_1/FeatureServer/0/query?where=1%3D1&outFields=*&outSR=4326&f=json"
hospitals_num <- c(0, 2000, 4000, 6000)
hosp_e <- list()
hosp_w <- list()

hosget <- lapply(hospitals_num, function(num) {
tryCatch({
hospitals_url_loop <- paste(hospitals_url, "&resultOffset=", num)
hospitals_json <- fromJSON(hospitals_url_loop)
hospitals_df <- as.data.frame(hospitals_json$features$attributes)},
error = function(e){
hosp_e <<- c(hosp_e, list(e))
print(e)},

warning = function(w){
hosp_w <<- c(hosp_w, list(w))
print(w)}
) })

hospitals_df <- do.call(rbind, hosget)

I didn't adapt your finally code to this rearrangement; I'll leave that to you. But at the end, hosp_e will be a list holding all the errors, and hosp_w will be a list holding all the warnings.

Catch specific warning and ignore others

I believe withCallingHandlers is what you want: Disregarding simple warnings/errors in tryCatch()

withCallingHandlers(myfun(),
warning = function(w){
if(grepl("right", w$message)){
stop("I have you now")
} else {
message(w$message)
}
})

Handling errors before warnings in tryCatch

This relates to the "is it possible to process the warning and then have the function continue while still catching errors?" question.

I had a similar issue where I wanted to bind my logging functions for warnings and errors to the try catch and always continue after warnings and also be able to perform multiple attempts at try catch, e.g. for accessing a flimsy network drive. This is what I ended up using. This or a more simplified version could help with what your after.

MyLibrary.Sys.Try <- function(
expr, # Expression that will be evaluated by the call to Try
errorMessage="", # Optional prepended string to add to error output
warningMessage="", # Optional prepended string to add to warning output
failureMessage="", # Optional prepended string to add to failing all attempts
finally=NULL, # Optional expression to be executed at the end of tryCatch
attempts=1, # Number of attempts to try evaluating the expression
suppressError=TRUE, # Should the call just log the error or raise it if all attempts fail
quiet=FALSE # Return expression normally or as invisible
) {
tryNumber <- 0
while(tryNumber<attempts) {
tryNumber <- tryNumber + 1

# If not suppressing the error and this is the last
# attempt then just evaluate the expression straight out
if(tryNumber == attempts && !suppressError){
# NOTE: I think some warnings might be lost here when
# running in non-interactive mode. But I think it should be okay
# because even nested dispatch seems to pick them up:
# MyLibrary.Sys.Try(MyLibrary.Sys.Try(function(),suppressError=F))
return(expr)
}

tryCatch({
# Set the warning handler to an empty function
# so it won't be raised by tryCatch but will
# be executed by withCallingHandlers
options(warning.expression=quote(function(){}))
withCallingHandlers({
if(quiet) {
return(invisible(expr))
} else {
return(expr)
}
},error=function(ex){
MyLibrary.Sys.Log.Error(errorMessage,ex)
}, warning=function(warn){
# Had issues with identical warning messages being
# issued here so to avoid that only log it the first
# time it happens in a given minute.
warnStamp <- paste(Sys.time(),warn,collapse="_",sep="")
if(!identical(warnStamp,getOption("MyLibrary.LAST.WARNING"))) {
if(!(interactive() && is.null(getOption("warning.expression")))){
MyLibrary.Sys.Log.Warning(warningMessage,warn)
}
options(MyLibrary.LAST.WARNING=warnStamp)
}
})
},error=function(ex){
# Suppressing the error since it's been logged
# by the handler above. Needs to be suppressed
# to not invoke the stop directly since the
# handler above passes it through.
},finally={
# Set the warning handler to the default value
# of NULL which will cause it to revert to it's
# normal behaviour. If a custom handler is normally
# attached it would make sense to store it above
# and then restore it here. But don't need that now
options(warning.expression=NULL)
if(!is.null(finally)){
if(quiet) {
return(invisible(finally))
} else {
return(finally)
}
}
})
}

msg <- paste(ifelse(nchar(failureMessage)>0," - ",""),"Failed to call expression after ",attempts," attempt(s)",sep="")
MyLibrary.Sys.Log.Error(failureMessage,msg)
}

tryCatch() apparently ignoring a warning

If you look in binning I think you'll find that the "warning" you see is not generated via warning() but with cat(), which is why tryCatch isn't picking it up. The author of binning probably deserves a few lashings with a wet noodle for this oversight. ;) (Or it could be on purpose due to the particular way that rattle works, I'm not sure.)

It appears to return NULL when this happens, so you could simply handle it manually. Not ideal, but possibly the only way to go.

How do I save warnings and errors as output from a function?

Maybe this is the same as your solution, but I wrote a factory to convert plain old functions into functions that capture their values, errors, and warnings, so I can

test <- function(i)
switch(i, "1"=stop("oops"), "2"={ warning("hmm"); i }, i)
res <- lapply(1:3, factory(test))

with each element of the result containing the value, error, and / or warnings. This would work with user functions, system functions, or anonymous functions (factory(function(i) ...)). Here's the factory

factory <- function(fun)
function(...) {
warn <- err <- NULL
res <- withCallingHandlers(
tryCatch(fun(...), error=function(e) {
err <<- conditionMessage(e)
NULL
}), warning=function(w) {
warn <<- append(warn, conditionMessage(w))
invokeRestart("muffleWarning")
})
list(res, warn=warn, err=err)
}

and some helpers for dealing with the result list

.has <- function(x, what)
!sapply(lapply(x, "[[", what), is.null)
hasWarning <- function(x) .has(x, "warn")
hasError <- function(x) .has(x, "err")
isClean <- function(x) !(hasError(x) | hasWarning(x))
value <- function(x) sapply(x, "[[", 1)
cleanv <- function(x) sapply(x[isClean(x)], "[[", 1)

tryCatch within for loop

Initialise y with NA and then run the for loop. Also since x is a vector and vector can hold only one class all the numbers in x turn to characters as you have non-numeric elements in x so you need to convert them to numbers before taking log.

x=c(-2,3,-1,4,'A')
y=rep(NA,5)

for(i in 1:5){
tryCatch(
expr = {
y[i]= log(as.numeric(x[i]))
},
error = function(e){
message('Caught an error!',i)
},
warning = function(w){
message('Caught a warning! ',i)
}
)
}
#Caught a warning! 1
#Caught a warning! 3
#Caught a warning! 5

y
#[1] NA 1.098612 NA 1.386294 NA

and then use is.na with which to get the index where error or warning happened.

which(is.na(y))
#[1] 1 3 5

Of course, you can do this without for loop as well

y <- log(as.numeric(x))
which(is.na(y))
#[1] 1 3 5

To return different value based on error or warning, we can make this into a function

run_fun <- function(x) {
tryCatch(
expr = {
return(log(as.numeric(x)))
},
error = function(e){
message('Caught an error!',i)
return(100)
},
warning = function(w){
message('Caught a warning! ',i)
return(200)
}
)
}

and then call it in for loop.

for (i in seq_along(x)) {
y[i] <- run_fun(x[i])
}

y
#[1] 200.0000 1.0986 200.0000 1.3863 200.0000


Related Topics



Leave a reply



Submit