I have a list of file to read. I wrote a loop, like this (it is only a example). However, some of these elements are missing and I got a message error interrupting the loop.I would like to skip the error and finish the loop, with the other elements of the list.
list<- c("ciao",
"miao",
"bau")
for (symbols in list){
a <- symbols
b <- as.Date(symbols)
c <- as.numeric(symbols)
d<- cbind(a,b,c)
write.csv(d)
}
As, far as I know, I could use the function try. I have already read some examples here, but they don't fit my need... or I don't know how to implement it.
Any idea to solve the problem?
Thank you
You can use tryCatch() for this and use the error = part to indicate what you want in the case of an error.
For example, in the below we can continue checking if the symbol == "bau" even after "miao" caused an error:
# error before it checks all args of list
list <- c("ciao", "miao", "bau")
for (symbols in list) {
if (symbols == "miao") stop("Er!")
print(symbols == "bau")
}
#> [1] FALSE
#> Error in eval(expr, envir, enclos): Er!
# now it will check all args even with error
for (symbols in list) {
tryCatch(
expr = {
if (symbols == "miao") stop("Er!")
print(symbols == "bau")
},
error = function(e) NA
)
}
#> [1] FALSE
#> [1] TRUE
Created on 2022-08-03 by the reprex package (v2.0.1)
Related
x = 1
simple <- function(p,q){
return(q)
}
test = simple(x,y)
Error in simple(x, y) : object 'y' not found
Please Note : Even if I don't create a variable "y", I should not get this error. Instead I want a message to be thrown saying "No data".
You can use try() (or the more elaborate tryCatch() to do this. For example,
x = 1
simple <- function(p,q){
q <- try(force(q), silent = TRUE)
if (inherits(q, "try-error")) {
warning("No data")
q <- NULL
}
return(q)
}
test = simple(x,y)
#> Warning in simple(x, y): No data
Created on 2021-01-28 by the reprex package (v0.3.0)
What the force() function does is evaluate the argument. If that fails, it returns an error: but try() catches that. (You don't actually need to call force(q), it would be enough to use try(q), but I think the explicit version is clearer.)
This question already has answers here:
How to write trycatch in R
(5 answers)
Closed 2 years ago.
I've tried multiple examples I found on here and elsewhere but it always fails to do what I want.
My R script is simply a configuration validation script, it checks to make sure the user has their environment setup correctly. So I want to try 5 different steps and report on the status of each so that the user can go and fix everything all at once. For example, my first step tests the connection to the database, if that fails I want to print a message and continue on to step 2. But it always halts execution when it errors out and so I only get to the failure and then no more.
I am running the script from command line using RScript.exe on W64. Here's my basic tryCatch, I tried it with the error function and without, it makes no difference, it always breaks on the error.
tryCatch(
expr = {
res<- dbGetQuery(con, sql)
print("SQL query results:")
print(res)
}
)
tryCatch catches nothing until you tell it what you want to catch. For instance,
tryCatch(
expr = {
res<- dbGetQuery(con, sql)
print("SQL query results:")
print(res)
},
error = function(e) NULL
)
will return NULL when there's an error. Without that line, it is catching nothing.
Side note: res's existence is not certain. Two scenarios:
res is never defined before now. If there's an error, res will not exist, and any code that follows it will fail with Error: object 'res' not found.
res was defined in a previous code block and is now likely unnecessary. However, if dbGetQuery fails then res will not have been redefined, so it is still present but not related to this query.
Both situations are problematic. I recommend something like:
res <- NULL
res <- tryCatch({
dbGetQuery(con, sql)
}, error = function(e) conditionMessage(e))
if (is.null(res)) {
print(paste("oops!", res))
} else {
print(res)
}
You're simply not handling your error when it occurs. Here's a reprex to show how to catch an error when it occurs:
function_that_always_fails <- function() stop("I failed")
exception_catcher <- function(e) "Carry on regardless"
tryCatch(expr = function_that_always_fails())
#> Error in function_that_always_fails(): I failed
tryCatch(expr = function_that_always_fails(),
error = exception_catcher)
#> [1] "Carry on regardless"
Or, if you wanted to run a bunch of tests in sequence like in your example, you could have something like:
function_that_sometimes_fails <- function(x)
{
if(x %% 2 == 0) stop("function ", x, " failed")
print(paste("test", x, "passed"))
}
exception_catcher <- function(e) print(paste(e$message, "but never mind"))
do_tests <- function() {
for(i in 1:5)
tryCatch(expr = function_that_sometimes_fails(i),
error = exception_catcher)
}
do_tests()
#> [1] "test 1 passed"
#> [1] "function 2 failed but never mind"
#> [1] "test 3 passed"
#> [1] "function 4 failed but never mind"
#> [1] "test 5 passed"
Created on 2020-08-17 by the reprex package (v0.3.0)
Summary: Why does the fourth block below (with parentheses around the if block) work correctly to give the error, but the third does not?
I want to have a conditional warning/error based on the date for code that I'm working on. Specifically, I have an expensive operation to save some excel files that takes several minutes and is rarely required. If I don't do it, I want to be reminded, and if I don't do it after a date that I expect to have new data, I want an error to remind me.
The first block of code below works reasonably, but I wanted not to duplicate the message. I tried the second block of code which accurately generates the warning as desired, but when it should be an error (the third block), it returns the function stop instead of calling stop with the argument as it did for warning.
However, when I wrap the if block in parentheses (the fourth block below), it works correctly. Why does the output of if differ between stop and warning?
today <- Sys.Date()
if (Sys.Date() > today) {
stop("Not saving excel files")
} else {
warning("Not saving excel files")
}
#> Warning: Not saving excel files
if (Sys.Date() > today) {
stop
} else {
warning
}("Not saving excel files")
#> Warning: Not saving excel files
if (Sys.Date() > as.character(as.Date(today) - 1)) {
stop
} else {
warning
}("Not saving excel files")
#> function (..., call. = TRUE, domain = NULL)
#> {
#> args <- list(...)
#> if (length(args) == 1L && inherits(args[[1L]], "condition")) {
#> cond <- args[[1L]]
#> if (nargs() > 1L)
#> warning("additional arguments ignored in stop()")
#> message <- conditionMessage(cond)
#> call <- conditionCall(cond)
#> .Internal(.signalCondition(cond, message, call))
#> .Internal(.dfltStop(message, call))
#> }
#> else .Internal(stop(call., .makeMessage(..., domain = domain)))
#> }
#> <bytecode: 0x000000001c2fb4a0>
#> <environment: namespace:base>
(
if (Sys.Date() > as.character(as.Date(today) - 1)) {
stop
} else {
warning
}
)("Not saving excel files")
#> Error in eval(expr, envir, enclos): Not saving excel files
Created on 2018-10-29 by the reprex package (v0.2.0).
We can use the lobstr package on github to compare the abstract syntax trees returned when R parses these commands. Observe the difference.
lobstr::ast((if(FALSE) {stop} else {warning})("bad"))
# o-o-`(`
# | \-o-`if`
# | +-FALSE
# | +-o-`{`
# | | \-stop
# | \-o-`{`
# | \-warning
# \-"bad"
lobstr::ast(if(FALSE) {stop} else {warning}("bad"))
# o-`if`
# +-FALSE
# +-o-`{`
# | \-stop
# \-o-o-`{`
# | \-warning
# \-"bad"
Notice that in the case without the parenthesis, the () to call the function is only bound to the block passed in the else statement. The () associates more strongly to the {} than it does the result of the if statement. Adding in the parenthesis helps you override the default operator precedence.
The {} just wrap multiple statements. Consider what it looks like without the braces (which are not required in if statements)
if(FALSE) stop else warning("bad")
# vs
(if(FALSE) stop else warning)("bad")
You can see how it looks like the "bad" should only be passed to warning in the first case
I'm using R's assertthat package and am wanting to (temporarily) output a warning instead of an error on assertion failure. What's the easiest way to do that with the assertthat package?
I realize that wanting warnings instead of errors kind of goes against what assertions are supposed to be used for. In the long term, we indeed want to be outputting errors on assertion failure. In the short term, we still want the code to function even with bad input, since the output with bad inputs is still "good enough" for now.
A simple example: suppose I have a function that takes x as input and outputs x+5. I want to output a warning if x!=3. Since we will be using assert_that ultimately, it would be nice if we can use assertthat package for the warning.
In the long term, we'll use this:
> x <- 3
> fn <- function(x) {assert_that(x==3); return(x+5)}
> fn(3)
[1] 8
> fn(4)
Error: x not equal to 3
In the short term, here's the best I have so far:
> fn <- function(x) {if(!see_if(x==3)) warning(validate_that(x==3)); return(x+5)}
> fn(3)
[1] 8
> fn(4)
[1] 9
Warning message:
In fn(4) : x not equal to 3
I'm looking for a more concise solution, if possible (best case would be passing an "output_warning" parameter to assert_that, but I don't think that exists).
I created a user defined function which accepts a string corresponding to an expression against which you would like to run validate_that() (ultimately assert_that()). The function prints a warning if the assertion fails and remains silent otherwise. See below for usage. You could easily extend this custom function to accept more than one expression if necessary. Note that I also use sys.calls() to obtain the name of the function which called this helper function. This is an important piece of information so you can correlate your warnings with the code that actually generated them.
assert_that_soft <- function(exp) {
if (!exp) {
print (paste("Error in function:",
parse(sys.calls()[[sys.nframe()-1]])) ) # name of caller
}
}
Usage:
> fn <- function(x) { assert_that_soft(x==3); return(x+5) }
> fn(3)
[1] 8
> fn(8)
[1] "Error in function: fn(8)"
[1] 13
Another option is to wrap assert_that in tryCatch.
fn <- function(x) tryCatch(assert_that(x == 3), error = function(e) warning(e), finally = return(x+5))
fn(3)
# [1] 8
fn(8)
# [1] 13
# Warning message:
# x not equal to 3
I think the easiest way to overwrite the function would be to copy most of the assert_that function as is, and call the new function by the same name so you don't need to change all the code when you go into error mode.
assert_that <- function(..., env=parent.frame()) {
res <- see_if(..., env=env)
if (res)
return(TRUE)
warning(attr(res, "msg"))
TRUE
}
fn <- function(x) { assert_that(x==3); return(x+5) }
fn(3)
# [1] 8
fn(8)
# [1] 13
# Warning message:
# In assert_that(x == 3) : x not equal to 3
I am proposing an extension of the assertthat package to allow for simple warnings, see
https://github.com/hadley/assertthat/issues/69
any feedback is welcome!
I am using stopifnot and I understand it just returns the first value that was not TRUE. I f that is some freaky dynamic expression someone who is not into the custom function cannot really make something out of that. So I would love to add a custom error message. Any suggestions?
Error: length(unique(nchar(check))) == 1 is not TRUE
Basically states that the elements of the vector check do not have the same length.
Is there a way of saying: Error: Elements of your input vector do not have the same length!?
Use stop and an if statement:
if(length(unique(nchar(check))) != 1)
stop("Error: Elements of your input vector do not have the same length!")
Just remember that stopifnot has the convenience of stating the negative, so your condition in the if needs to be the negation of your stop condition.
This is what the error message looks like:
> check = c("x", "xx", "xxx")
> if(length(unique(nchar(check))) != 1)
+ stop("Error: Elements of your input vector do not have the same length!")
Error in eval(expr, envir, enclos) :
Error: Elements of your input vector do not have the same length!
A custom message can be added as a label to your expression:
stopifnot("Elements of your input vector do not have the same length!" =
length(unique(nchar(check))) == 1)
# Error: Elements of your input vector do not have the same length!
The assertive and assertthat packages have more readable check functions.
library(assertthat)
assert_that(length(unique(nchar(check))) == 1)
## Error: length(unique(nchar(check))) == 1 are not all true.
library(assertive)
assert_is_scalar(unique(nchar(check)))
## Error: unique(nchar(check)) does not have length one.
if(!is_scalar(unique(nchar(check))))
{
stop("Elements of check have different numbers of characters.")
}
## Error: Elements of check have different numbers of characters.
Or you could package it up.
assert <- function (expr, error) {
if (! expr) stop(error, call. = FALSE)
}
So you have:
> check = c("x", "xx", "xxx")
> assert(length(unique(nchar(check))) == 1, "Elements of your input vector do not have the same length!")
Error: Elements of your input vector do not have the same length!
What about embedding the stopifnot into tryCatch and then recasting the exception with stop using customized message?
Something like:
tryCatch(stopifnot(...,error=stop("Your customized error message"))
Unlike some other solutions this does not require additional packages. Compared to using if statement combined with stop you retain the performance advantages of stopifnot, when you use new R versions. Since R version 3.5.0 stopifnot evaluates expressions sequentially and stops on first failure.
I would recommend you check out Hadley's testthat package. It allows for intuitive testing: the names of the functions are great and the way you write them is like a sentence -- "I expect that length(unique(nchar(check))) is [exactly|approximately] 1". The errors produced are informative.
See here:
http://journal.r-project.org/archive/2011-1/RJournal_2011-1_Wickham.pdf
In your case,
> library(testthat)
> check = c("x", "xx", "xxx")
> expect_that(length(unique(nchar(check))), equals(1))
Error: length(unique(nchar(check))) not equal to 1
Mean relative difference: 2
Also note that you don't have the problem that #Andrie referenced with sometimes having to think about double negatives with stopifnot. I know it seems simple, but it caused me many headaches!
The answers already provided are quite good, and mine is just an addition to that collection. For some people it could be more convenient to use one-liner in form of the following function:
stopifnotinform <- function(..., message = "err") {
args <- list(...)
if (length(args) == 0) {
return(NULL)
}
for (i in 1:length(args)) {
result <- args[[i]]
if (is.atomic(result) && result == FALSE) {
stop(message)
}
}
}
# throws an error
stopifnotinform(is.integer(1L), is.integer(2), message = "Some number(s) provided is not an integer")
# continues with execution
stopifnotinform(is.integer(1L), is.integer(2L), message = "Some number(s) provided is not an integer")
Bear in mind that this solution provides you with only one (common) error message for all parameters in ....
Try this:
same_length <- FALSE
stopifnot("Elements of your input vector do not have the same length!" = same_length)
#> Error : Elements of your input vector do not have the same length!