
stop_() is an enhanced version of stop() to generate meaningful error
with error-recoverable glue interpolation and translation.
error_class(), stop_top_call(), object_info() and `lbl()“ are support
functions that help building contextual and explicit error messages.
stop_(
...,
domain = NULL,
class = error_class(call, class_id = class_id),
class_id = .op$class_id,
call = NULL,
parent = NULL,
.inherit = TRUE,
.internal = FALSE,
.file = NULL,
.envir = parent.frame(),
.frame = .envir,
.trace_bottom = NULL,
.last_call = sys.call(-1L)
)
stop_top_call(nframe = 1L)
error_class(call = parent.frame(), class_id = NULL)
object_info(x)
lbl(expr, width = 30L, nlines = 1L)One or more character strings with the error or warning
messages to be translated. Name them '*' =, 'i' =, 'v' =, 'x' = or
'!' = to format a bullet-list with the message items. First message item
is considered to use the '!' bullet by default. The messages also support
glue interpolation and inline markups, see Formatting messages with cli
and cli::format_inline().
The translation. domain, see gettext(). If NA or "",
messages are not translated (use this with messages that are already
translated).
The subclass of the error condition message. By default, it is
computed by error_class(), using the name of the function in call
(plus, optionally, the class_id), or "svAssert_error" by default.
An optional identifier to append to the error subclass.
The execution environment of a currently running function where the error should be reported from ( called the relevant function).
Give a condition object when an error is rethrown from a
condition handler, such as withCallingHandlers() or rlang::try_fetch()
to chain errors (see
Including contextual information with error chains.
Indicate NA for an unchained rethrow, in case you want to rethrow with a
custom error message (do not abuse this, and never hide errors).
Logical, whether to inherit parent conditions when chaining
errors. Default is TRUE.
Logical, whether the error is internal to the package. If
TRUE, a footer bullet is added to indicate it to invite the user to
report the error to the package authors. Default is FALSE.
A connection or a string where to print the message. The default
is context-dependent, see the stdout vs stderr section in
[rlang::abort().
The environment where to evaluate the glue expressions.
The environment to use for the backtrace (usually the same as
.envir).
An optional environment to truncate the backtrace in
order to display only the most relevant part of it. Default is NULL and
it uses callif it is an environment, or .frame otherwise.
The last call issued by the user. Different from call
when a first argument with dot (.) (e.g., data = (.)) was automatically
injected in the call (so-called "data-dot mechanism). In this case, extra
information is added to the error message, except if .last_call is NULL
(use it to suppress these extra messages).
The number of frames to go up the call stack to start finding
the top call (as soon as .__to_call__. is found in the environment,
look in its parent frame).
An R object to describe.
An R expression to deparse
Maximum width of the deparsed expression
Maximum number of lines for the deparsed expression
stop_() is invoked for its side-effects, to stop execution of the
current code.
stop_top_call() returns the top call to be used for stop condition messages
(to be used as call argument of stop_()).
call for stop condition messages.
error_class() returns a character string with the error class name computed
for stop_(), that is, "fun_id_error", or "svAssert_error", by default.
object_info() returns a character string describing the R object provided.
lbl() returns a deparsed version of an expression suitable for
{<format> could be .var, .arg, or .code.
stop_() is a wrapper around rlang::abort() that provides more control
on the stop message thanks to cli::cli_abort() glue interpolation and
gettext() translation. It can recover from errors in the formatting
processes. In this case, it throws the raw error message with a
warning. It also adds a class to the error message, with a default one
automatically computed by error_class(). It uses stop_top_call() to
provide a simple mechanism to point to the execution environment of the
running function that is relevant in the context. Add a variable
.__top_call__. <- TRUE in the relevant function, or
.__top_call__. <- FALSE in an helper function, to be sure to point to the
function of interest (most of the time, the function called by the user, see
examples).
A reminder message inviting to access the backtrace of the error is displayed
depending on the svAssert_backtrace_on_error option. Set it to "none"
(disable it), "reminder" (default in interactive sessions, show the
reminder message), "branch" (display a simplified backtrace) or "full"
(default in non-interactive sessions, display the full tree). You rarely need
to change the default. It synchronizes with rlang_backtrace_on_error option
used in rlang::abort() when needed.
You can use rlang::global_entrace() to display classical base R stop()
messages in a similar way as stop_() and rlang::abort() do. You can also
use rlang::last_error() to revisit the last error message, or
rlang::last_trace() to inspect the backtrace of the message.
Finally, the display of the error message is customisable. See
Customising condition messages.
# If you want to include the error messages in the translation strings in
# your package, you have to rename `stop_()` into `stop()` because
# [tools::xgettext2pot()] will only pick up messages in the later ones.
library(svAssert)
stop <- stop_
# Note: the |> try() are there to catch error. Do not use them in your code!
# Correctly formatted stop messages
n <- "some text"
stop("{.var n} must be a numeric vector",
x = "You've supplied a {.cls {class(n)}} vector.") |> try()
#> Error in eval(expr, envir) : `n` must be a numeric vector
#> ✖ You've supplied a <character> vector.
# Incorrectly formatted stop messages (error in glue formatting: missing
# second closing `}` in `{.cls{class(n)}`
stop("{.var n} must be a numeric vector",
x = "You've supplied a {.cls {class(n)} vector.") |> try()
#> Warning: Cannot format error message (signal it to package authors):
#> Expecting '}'
#> Error in eval(expr, envir) : `n` must be a numeric vector
#> ✖ You've supplied a {.cls {class(n)} vector.
# Automatic pluralisation
n <- 1:18
stop("{.var n} must be a scalar numeric:",
i = "There {?is/are} {length(n)} element{?s}.",
x = "Provide a single numeric, not {object_info(n)}.") |> try()
#> Error in eval(expr, envir) : `n` must be a scalar numeric:
#> ℹ There are 18 elements.
#> ✖ Provide a single numeric, not a vector of type <integer> and 18 elements.
# When issued from within a function, the function call is indicated
test1 <- function(x) {
stop("{.var x} must be a scalar numeric:",
i = "There {?is/are} {length(x)} element{?s} in {.var x}.")
}
test1(1:3) |> try()
#> Error in test1(1:3) : `x` must be a scalar numeric:
#> ℹ There are 3 elements in `x`.
# If another function calls `test1()`, error is still reported from test1:
test2 <- function(x) {
test1(x)
}
test2(1:3) |> try()
#> Error in test1(x) : `x` must be a scalar numeric:
#> ℹ There are 3 elements in `x`.
# In such a case, it is better to report the error from `test2()`.
# You can do that by stating `._top_call_. <- TRUE` in the body of `test2()`.
test2 <- function(x) {
.__top_call__. <- TRUE
test1(x)
}
test2(1:3) |> try()
#> Error in test2(1:3) : `x` must be a scalar numeric:
#> ℹ There are 3 elements in `x`.
# When you design an helper function (a function that is always called from
# another function), you can set `.__top_call__. <- FALSE` to force pointing
# to the calling function. In this case, .__top_call___. <- TRUE is not
# needed in the calling function.
stop_is_scalar_numeric <- function(x) {
.__top_call__. <- FALSE
stop("{.var {lbl(substitute(x))}} must be a scalar numeric")
}
test3 <- function(y) {# A function with a proper assertion on y
(is.numeric(y) && length(y) == 1L) || stop_is_scalar_numeric(y)
# Do something with y here...
}
test3(1:4) |> try()
#> Error in test3(1:4) : `y` must be a scalar numeric
# If test3() is called by another function, test4(), focus depends on the
# presence of .__top_call__. in test4()
test4 <- function(y) test3(y)
test4(1:4) |> try()
#> Error in test3(y) : `y` must be a scalar numeric
# or:
test4 <- function(y) {
.__top_call__. <- TRUE
test3(y)
}
test4(1:4) |> try()
#> Error in test4(1:4) : `y` must be a scalar numeric
rm(stop)