Dear expeRts, I am struggling with warning/error handling. I would like to call a function which can produce either a) normal output b) a warning c) an error Since the function is called several (thousand) times in a loop, I would like to proceed "quietly" and collect the warnings and errors [to deal with them at a later point]. I have seen constructs with tryCatch (which can deal with errors) and with withCallingHandlers (which can deal with warnings), but I cannot figure out how to catch *both* warnings and errors. Below is a minimal example of the function that is called several times in a large loop. The function should catch warnings and errors; the former work fine, but with the latter I do not know how to proceed. The function should *always* return the list with the three components. How can I achieve this? Cheers, Marius Ps: How can I get the warning/error message in a nice string (as it is printed in a normal warning/error message)? The approach shown below is somehow ugly. Basically, I had trouble converting the call w$call to a string. ## based on http://tolstoy.newcastle.edu.au/R/help/04/06/0217.html ## and http://www.mail-archive.com/r-help at r-project.org/msg81380.html f <- function(x){ ## warnings w.list <- NULL # init warning w.handler <- function(w){ # warning handler warn <- simpleWarning(w$message, w$call) # build warning w.list <<- c(w.list, paste(warn, collapse = " ")) # save warning invokeRestart("muffleWarning") } ## errors e.list <- NULL # init errors e.handler <- function(e){ # error handler err <- simpleError(e$message, e$call) e.list <<- c(e.list, paste(err, collapse = " ")) # save error } ## execute command res <- withCallingHandlers(log(x), warning = w.handler, error = e.handler) ## return result with warnings and errors list(result = res, warning = w.list, error = e.list) } f(1) f(-1) f("a")
How to catch both warnings and errors?
6 messages · David Winsemius, Marius Hofert, Martin Maechler
On Dec 5, 2010, at 3:13 PM, Marius Hofert wrote:
Dear expeRts, I am struggling with warning/error handling. I would like to call a function which can produce either a) normal output b) a warning c) an error Since the function is called several (thousand) times in a loop, I would like to proceed "quietly" and collect the warnings and errors [to deal with them at a later point].
I do not see the function warnings() being used below: ?warnings It delivers the stored warnings with different default behavior for interactive and non-interactive sessions.
I have seen constructs with tryCatch (which can deal with errors) and with withCallingHandlers (which can deal with warnings), but I cannot figure out how to catch *both* warnings and errors. Below is a minimal example of the function that is called several times in a large loop. The function should catch warnings and errors; the former work fine, but with the latter I do not know how to proceed.
Made some changes in you code but don't know if it is what you were
hoping for:
f <- function(x){
## warnings
w.list <- NULL # init warning
w.handler <- function(w){ # warning handler
warn <- simpleWarning(w$message, w$call) # build warning
# first change here
w.list <<- c(w.list, paste(warnings(), collapse = " ")) # save
warning
invokeRestart("muffleWarning")
}
## errors
e.list <- NULL # init errors # not sure this is good idea
e.handler <- function(e){ # error handler
err <- c(e.list, e$message, e$call) # save error
return( err)
}
## execute command
# wrapped cal in try()
res <- withCallingHandlers(try(log(x)), warning = w.handler, error
= e.handler)
## return result with warnings and errors
list(result = res, warning = w.list, error = e.list)
}
The function should *always* return the list with the three components. How can I achieve this? Cheers, Marius Ps: How can I get the warning/error message in a nice string (as it is printed in a normal warning/error message)? The approach shown below is somehow ugly. Basically, I had trouble converting the call w$call to a string. ## based on http://tolstoy.newcastle.edu.au/R/help/04/06/0217.html ## and http://www.mail-archive.com/r-help at r-project.org/msg81380.html f <- function(x){ ## warnings w.list <- NULL # init warning w.handler <- function(w){ # warning handler warn <- simpleWarning(w$message, w$call) # build warning w.list <<- c(w.list, paste(warn, collapse = " ")) # save warning invokeRestart("muffleWarning") } ## errors e.list <- NULL # init errors e.handler <- function(e){ # error handler err <- simpleError(e$message, e$call) e.list <<- c(e.list, paste(err, collapse = " ")) # save error } ## execute command res <- withCallingHandlers(log(x), warning = w.handler, error = e.handler) ## return result with warnings and errors list(result = res, warning = w.list, error = e.list) } f(1) f(-1) f("a")
______________________________________________ R-help at r-project.org mailing list https://stat.ethz.ch/mailman/listinfo/r-help PLEASE do read the posting guide http://www.R-project.org/posting-guide.html and provide commented, minimal, self-contained, reproducible code.
David Winsemius, MD West Hartford, CT
On 2010-12-06, at 01:07 , David Winsemius wrote:
On Dec 5, 2010, at 3:13 PM, Marius Hofert wrote:
Dear expeRts, I am struggling with warning/error handling. I would like to call a function which can produce either a) normal output b) a warning c) an error Since the function is called several (thousand) times in a loop, I would like to proceed "quietly" and collect the warnings and errors [to deal with them at a later point].
I do not see the function warnings() being used below: ?warnings It delivers the stored warnings with different default behavior for interactive and non-interactive sessions.
I have seen constructs with tryCatch (which can deal with errors) and with withCallingHandlers (which can deal with warnings), but I cannot figure out how to catch *both* warnings and errors. Below is a minimal example of the function that is called several times in a large loop. The function should catch warnings and errors; the former work fine, but with the latter I do not know how to proceed.
Made some changes in you code but don't know if it is what you were hoping for:
f <- function(x){
## warnings
w.list <- NULL # init warning
w.handler <- function(w){ # warning handler
warn <- simpleWarning(w$message, w$call) # build warning
# first change here
w.list <<- c(w.list, paste(warnings(), collapse = " ")) # save warning
invokeRestart("muffleWarning")
}
## errors
e.list <- NULL # init errors # not sure this is good idea
e.handler <- function(e){ # error handler
err <- c(e.list, e$message, e$call) # save error
return( err)
}
## execute command
# wrapped cal in try()
res <- withCallingHandlers(try(log(x)), warning = w.handler, error = e.handler)
## return result with warnings and errors
list(result = res, warning = w.list, error = e.list)
}
Dear David,
many thanks for your help.
If I call your code with f(-1) and f("a"), I obtain:
f(-1)
$result [1] NaN $warning [1] "" $error NULL => The problem is that the warning is not given.
f("a")
Error in log(x) : Non-numeric argument to mathematical function $result [1] "Error in log(x) : Non-numeric argument to mathematical function\n" attr(,"class") [1] "try-error" $warning NULL $error NULL => The problem is that the error message is printed to the R console instead of suppressed (setting silent = TRUE didn't help either). Further, the $error component is empty (the error message should appear there -- if possible) Do you know a solution? Cheers, Marius
On Dec 5, 2010, at 7:35 PM, Marius Hofert wrote:
On 2010-12-06, at 01:07 , David Winsemius wrote:
On Dec 5, 2010, at 3:13 PM, Marius Hofert wrote:
Dear expeRts, I am struggling with warning/error handling. I would like to call a function which can produce either a) normal output b) a warning c) an error Since the function is called several (thousand) times in a loop, I would like to proceed "quietly" and collect the warnings and errors [to deal with them at a later point].
I do not see the function warnings() being used below: ?warnings It delivers the stored warnings with different default behavior for interactive and non-interactive sessions.
I have seen constructs with tryCatch (which can deal with errors) and with withCallingHandlers (which can deal with warnings), but I cannot figure out how to catch *both* warnings and errors. Below is a minimal example of the function that is called several times in a large loop. The function should catch warnings and errors; the former work fine, but with the latter I do not know how to proceed.
Made some changes in you code but don't know if it is what you were
hoping for:
f <- function(x){
## warnings
w.list <- NULL # init warning
w.handler <- function(w){ # warning handler
warn <- simpleWarning(w$message, w$call) # build warning
# first change here
w.list <<- c(w.list, paste(warnings(), collapse = " ")) # save
warning
invokeRestart("muffleWarning")
}
## errors
e.list <- NULL # init errors # not sure this is good idea
e.handler <- function(e){ # error handler
err <- c(e.list, e$message, e$call) # save error
return( err)
}
## execute command
# wrapped cal in try()
res <- withCallingHandlers(try(log(x)), warning = w.handler, error
= e.handler)
## return result with warnings and errors
list(result = res, warning = w.list, error = e.list)
}
Dear David,
many thanks for your help.
If I call your code with f(-1) and f("a"), I obtain:
f(-1)
$result [1] NaN $warning [1] "" $error NULL
=> The problem is that the warning is not given.
f("a")
Error in log(x) : Non-numeric argument to mathematical function $result [1] "Error in log(x) : Non-numeric argument to mathematical function \n" attr(,"class") [1] "try-error" $warning NULL $error NULL => The problem is that the error message is printed to the R console instead of suppressed (setting silent = TRUE didn't help either). Further, the $error component is empty (the error message should appear there -- if possible)
Sorry. I was being misled by warnings that existed at my global level
into thinking i had succeeded. This modification will suppress warning
and error but will not populate the lists as we had hoped:
f <- function(expr){
## warnings
w.list <- NULL # init warning
w.handler <- function(w){ # warning handler
warn <- c(w$message, w$call) # build warning
# first change here
muffleWarning <<- c(w.list, warn, collapse = " ") # save warning
invokeRestart("muffleWarning")}
## errors
e.list <- NULL # init errors # not sure this is good idea
e.handler <- function(e){ # error handler
e.list <<- c(e.list, e$message, e$call) # save error
return( e.list)
}
## execute command
# wrapped cal in try()
res <- withCallingHandlers(try(expr, silent=TRUE), warning =
w.handler, error = e.handler)
## return result with warnings and errors
list(result = res, warning = w.list, error = e.list)
}
> test <- f(log(-1))
> test
$result
[1] NaN
$warning
NULL
$error
NULL
> test <- f(log("a"))
> test
$result
[1] "Error in log(\"a\") : Non-numeric argument to mathematical
function\n"
attr(,"class")
[1] "try-error"
$warning
NULL
$error
NULL
Do you know a solution?
Cheers, Marius
David Winsemius, MD West Hartford, CT
Hmm... still not quite what I was hoping for... but thanks anyway. I would like to have the output in the following form:
f(1)
$result [1] 0 $warning [1] NULL # or "" $error [1] NULL # or ""
f(-1)
$result [1] NaN $warning [1] "Warning in log(-1) : NaNs produced" # or something similar $error [1] NULL # or ""
f("a")
$result
[1] NULL # or NA
$warning
[1] NULL # or ""
$error
[1] "Error in log("a") : Non-numeric argument to mathematical function"
Has anyone done that before? I think it's quite a natural problem although I could not find a solution online (dealing with *both* warnings *and* errors).
Cheers,
Marius
3 days later
Marius Hofert <m_hofert at web.de>
on Mon, 6 Dec 2010 11:10:17 +0100 writes:
> Hmm... still not quite what I was hoping for...
indeed.
We (Marius and I) now sat together,
and have constructed the following quite nice,
quite general solution:
With thanks to Luke Tierney's explanation (from 2004 !)
http://tolstoy.newcastle.edu.au/R/help/04/06/0217.html
and Bill Dunlap's note (mentioned in Marius' original post):
##' We want to catch *and* save both errors and warnings, and in the case of
##' a warning, also keep the computed result.
##'
##' @title tryCatch both warnings and errors
##' @param expr
##' @return a list with 'value' and 'warning', where
##' 'value' may be an error caught.
##' @author Martin Maechler
tryCatch.W.E <- function(expr)
{
W <- NULL
w.handler <- function(w){ # warning handler
W <<- w
invokeRestart("muffleWarning")
}
list(value = withCallingHandlers(tryCatch(expr, error = function(e) e),
warning = w.handler),
warning = W)
}
Testing it here for Marius' three cases :
str( tryCatch.W.E( log( 2 ) ) )
List of 2 $ value : num 0.693 $ warning: NULL
str( tryCatch.W.E( log( -1) ) )
List of 2 $ value : num NaN $ warning:List of 2 ..$ message: chr "NaNs wurden erzeugt" ..$ call : language log(-1) ..- attr(*, "class")= chr [1:3] "simpleWarning" "warning" "condition"
str( tryCatch.W.E( log("a") ) )
List of 2
$ value :List of 2
..$ message: chr "Nicht-numerisches Argument f?r mathematische Funktion"
..$ call : language log("a")
..- attr(*, "class")= chr [1:3] "simpleError" "error" "condition"
$ warning: NULL
---
Martin Maechler, ETH Zurich