I'm using lapply
to run a complex function on a large number of items, and I'd like to save the output from each item (if any) together with any warnings/errors that were produced so that I can tell which item produced which warning/error.
I found a way to catch warnings using withCallingHandlers
(described here). However, I need to catch errors as well. I can do it by wrapping it in a tryCatch
(as in the code below), but is there a better way to do it?
catchToList <- function(expr) {
val <- NULL
myWarnings <- NULL
wHandler <- function(w) {
myWarnings <<- c(myWarnings, w$message)
invokeRestart("muffleWarning")
}
myError <- NULL
eHandler <- function(e) {
myError <<- e$message
NULL
}
val <- tryCatch(withCallingHandlers(expr, warning = wHandler), error = eHandler)
list(value = val, warnings = myWarnings, error=myError)
}
Sample output of this function is:
> catchToList({warning("warning 1");warning("warning 2");1})
$value
[1] 1
$warnings
[1] "warning 1" "warning 2"
$error
NULL
> catchToList({warning("my warning");stop("my error")})
$value
NULL
$warnings
[1] "my warning"
$error
[1] "my error"
There are several questions here on SO that discuss tryCatch
and error handling, but none that I found that address this particular issue. See How can I check whether a function call results in a warning?, warnings() does not work within a function? How can one work around this?, and How to tell lapply to ignore an error and process the next thing in the list? for the most relevant ones.
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 canwith 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 factoryand some helpers for dealing with the result list
I have merged Martins soulution (https://stackoverflow.com/a/4952908/2161065) and the one from the R-help mailing list you get with
demo(error.catching)
.The main idea is to keep both, the warning/error message as well as the command triggering this problem.
Examples:
Output:
Try the evaluate package.
It currently lacks a nice way of evaluating expression though - this is mainly because it's targetted towards reproducing exactly what R output's given text input at the console.
It also captures messages, output to the console, and ensures that everything is correctly interleaved in the order in which it occurred.
The purpose of my answer (and modification to Martin's excellent code) is so that the factory-ed function returns the data structure expected if all goes well. If a warning is experienced, it is attached to the result under the
factory-warning
attribute. data.table'ssetattr
function is used to allow for compatibility with that package. If an error is experienced, the result is the character element "An error occurred in the factory function" and thefactory-error
attribute will carry the error message.Because we don't wrap the result in an extra list we can't make the kind of assumptions that allow for some of his accessor functions, but we can write simple checks and decide how to handle the cases as is appropriate to our particular resulting data-structure.