knitr::opts_chunk$set(eval = TRUE, error = TRUE)
library(readr) log(-1) this_object_DNE readr::read_csv("inst/extdata/baxter.metadata.csv")
library(rlang) message("This is a benign message.") warning("Something could be wrong, but we can continue.") abort("The program can't go on, burn it all down!")
4th type of condition: Interrupt
: when you press "Stop" or ctrl-c
.
my_log <- function(x, base = exp(1)) { if (!is.numeric(x)) { abort(paste0( "`x` must be numeric; not ", typeof(x), "." )) } if (!is.numeric(base)) { abort(paste0( "`base` must be numeric; not ", typeof(base), "." )) } base::log(x, base = base) } my_log('abc')
tryCatch( error = function(cnd) { # do this if you catch an error code_to_run_when_error_is_thrown }, { # try this code_to_run_while_handlers_are_active } )
Why? When you want to modify the default behavior.
tryCatch doesn't return to the try
after Catch
ing an error
tryCatch( error = function(cnd) { # catch an error message("Oh no, there's an error!") }, { # try this bad_thing_happened = TRUE if( bad_thing_happened) { abort("We've gotta kill the program") } message("This code is never run!") } ) # the code outside the tryCatch block continues on afterward
You can access the condition message in the Catch
tryCatch( error = function(cnd) { # catch an error message("Oh no, there's an error!") message(conditionMessage(cnd)) }, { # try this bad_thing_happened = TRUE if( bad_thing_happened) { abort("We've gotta kill the program") } message("This code is never run!") } ) # the code outside the tryCatch block continues on afterward
withCallingHandlers( warning = function(cnd) { code_to_run_when_warning_is_signalled }, message = function(cnd) { code_to_run_when_message_is_signalled }, code_to_run_while_handlers_are_active )
withCallingHandlers returns to the try
after a Catch
withCallingHandlers( warning = function(cnd) { message("Caught a warning!") # do something special }, { warning("Something might be wrong.\n") message("But let's keep going anyway.") } )
library(glue) # Write a function that wraps `abort` abort_bad_argument <- function(arg, must, not = NULL) { # create a custom message msg <- glue::glue("`{arg}` must {must}") # append to the message if `not` was specified if (!is.null(not)) { not <- typeof(not) msg <- glue::glue("{msg}; not {not}.") } # pass custom metadata to abort abort("error_bad_argument", message = msg, arg = arg, must = must, not = not ) }
Using our custom condition
my_log <- function(x, base = exp(1)) { if (!is.numeric(x)) { abort_bad_argument("x", must = "be numeric", not = x) } if (!is.numeric(base)) { abort_bad_argument("base", must = "be numeric", not = base) } base::log(x, base = base) } my_log(3, 'abc')
"The best error messages tell you what is wrong and point you in the right direction to fix the problem."
"The goal is to make it as easy as possible for the user to find and fix the problem."
tryCatch
.if-else
).Let's write conditions for the code from the Riffomonas minimalR tutorial and work on a few exercises from AdvancedR.
R/baxter.R
get_metadata()
get_bmi()
get_bmi_category()
R/exercises.R
careful_remove()
check_dependencies()
bottles_of_beer()
{bash, eval=FALSE}
git clone https://github.com/SchlossLab/exception-handling
or if you previously cloned it, pull new commits:
{bash, eval=FALSE}
cd path/to/repo/ ; git pull
{bash, eval=FALSE}
git checkout -b descriptive-branch-name
{bash, eval=FALSE}
git add . ; git commit -m "descriptive commit message"
{bash, eval=FALSE}
git push -u origin descriptive-branch-name
Open a pull request on GitHub, mention your issue number(s), and merge it if there aren't conflicts.
{height=275px}
{height=275px}
Relevant XKCDs:
library(rmarkdown) rmarkdown::render('exception-handling.Rmd', output_file = 'docs/exception-handling.html')
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.