Closed DavisVaughan closed 1 year ago
To solve this problem we need something like:
with_indexed_errors <- function(expr, i, error_call = caller_env()) {
if (something) {
expr
} else {
withCallingHandlers(
expr,
error = function(cnd) {
if (i == 0L) {
# Error happened before or after loop
} else {
cli::cli_abort(
c(i = "In index: {i}."),
parent = cnd,
call = error_call,
class = "purrr_error_iteration"
)
}
}
)
}
}
But what should something
be? I think there are three possibilities:
with_no_indexed_errors()
or similar.error_call
argument in map()
with some sentinel value (e.g. zap()
)map()
.Since it seems like map()
and friends are going to need error_call
anyway, the second option seems the most parsimonious (even though it introduces a new error call pattern that we haven't used before).
OTOH if you want an error to come from map()
, the chances are that you'll want to customise "In index {i}"
to something problem specific, so maybe error_call
isn't that generally useful for map()
functions?
It just occurred to me that there's another approach: deliberately unwrap the error.
with_no_indexed_errors <- function(expr) {
tryCatch(expr,
purrr_indexed_error = function(err) stop(err$parent)
)
}
This is probably the sort of wrapping we'd want to do in tidyr, so we can change from "index {i}" to "column {col}".
In https://github.com/tidyverse/tidyr/pull/1430 we had an issue where the chained error of
map()
results in a confusing error message.It seems like any case where we need to pass
error_call
through to.f
can result in an "inverted" chained error. Reallyfn()
is the one callingmap()
here, but it is reported likemap()
calledfn()
, which is quite confusing.The current hack is to avoid
map()
altogether and switch back tolapply()
, but that is obviously not great.We might need something like
with_no_indexed_errors()
that we can wrap themap()
with to turn off the error chaining. In the tidyr case I don't think we'd ever want to report the index of the failure, and we wouldn't wantmap()
mentioned in the error at all.With
lapply()
: