<- function(x) {
internal_checker if (any(x < 0)) {
::cli_abort("x must be positive.")
cli
}
}
<- function(x) {
user_facing_function internal_checker(x)
sqrt(x)
}
user_facing_function(-5)
Making better
error messages
with cli
The tidymodels framework is a collection of packages for modeling and machine learning using tidyverse principles.
And we throw a LOT of errors
#> # A tibble: 12 × 10
#> package cli_abort cli_warn cli_inform abort warn inform stop warning message
#> <chr> <int> <int> <int> <int> <int> <int> <int> <int> <int>
#> 1 dials 0 0 0 68 6 1 1 0 0
#> 2 hardhat 18 0 0 52 4 0 0 0 0
#> 3 infer 0 0 0 0 0 0 1 1 1
#> 4 modeldata 0 0 0 3 0 0 0 0 0
#> 5 parsnip 3 3 0 230 46 0 13 0 9
#> 6 recipes 3 0 0 185 40 0 16 0 2
#> 7 rsample 5 0 0 133 14 0 0 0 0
#> 8 tune 13 1 2 146 23 2 0 5 9
#> 9 workflows 0 0 0 65 10 0 0 0 0
#> 10 workflowsets 0 0 0 17 8 0 0 1 7
#> 11 yardstick 0 0 0 111 12 0 4 0 2
#> 12 tidymodels 0 0 0 2 0 0 0 0 3
Photo by Wojciech Then on Unsplash
Photo by Stefan Wagener on Unsplash
Helpers for Developing Command Line Interfaces
A suite of tools to build attractive command line interfaces (CLIs), from semantic elements: headers, lists, alerts, paragraphs, etc. Supports theming via a CSS-like language. It also contains a number of lower level CLI elements: rules, boxes, trees, and Unicode symbols with ASCII alternatives. It supports ANSI markup for terminal colors and font styles.
It can do a lot, not just error messages
It follows rlang::abort()
with cli::cli_abort()
the checks should happen as early as possible
the checks should be as fast as possible
constructing the error doesn’t have to be that fast
indicators <- tryCatch(
model.matrix(object = levels, data = indicators),
error = function(cnd) {
if (grepl("(vector memory|cannot allocate)", cnd$message)) {
n_levels <- length(attr(levels, "values"))
cli::cli_abort(
"{.var {col_name}} contains too many levels ({n_levels}), \\
which would result in a data.frame too large to fit in memory.",
call = NULL
)
}
stop(cnd)
}
)
if (nrow(needs_tuning) > 0) {
args <- vctrs::vec_split(needs_tuning$arg, needs_tuning$step)
msg <- c(
x = "You cannot {.fun prep} a tunable recipe.",
i = "{cli::qty(nrow(args))}The following step{?s} \\
{?no/has/have} {.fun tune}:"
)
step_msg <- paste0(
"{needs_tuning$step[",
seq_len(nrow(needs_tuning)),
"]}: {.and {.arg {needs_tuning$arg[",
seq_len(nrow(needs_tuning)),
"]}}}"
)
names(step_msg) <- rep("*", nrow(needs_tuning))
cli::cli_abort(c(msg, step_msg))
}