loading...

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)

Arguments

...

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().

domain

The translation. domain, see gettext(). If NA or "", messages are not translated (use this with messages that are already translated).

class

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.

class_id

An optional identifier to append to the error subclass.

call

The execution environment of a currently running function where the error should be reported from ( called the relevant function).

parent

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).

.inherit

Logical, whether to inherit parent conditions when chaining errors. Default is TRUE.

.internal

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.

.file

A connection or a string where to print the message. The default is context-dependent, see the stdout vs stderr section in [rlang::abort().

.envir

The environment where to evaluate the glue expressions.

.frame

The environment to use for the backtrace (usually the same as .envir).

.trace_bottom

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.

.last_call

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).

nframe

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).

x

An R object to describe.

expr

An R expression to deparse

width

Maximum width of the deparsed expression

nlines

Maximum number of lines for the deparsed expression

Value

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 { {lbl(x)}} where <format> could be .var, .arg, or .code.

Details

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.

Examples

# 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)