Is it possible to change the Error label inside the stop() function?
For example:
stop("This is a error!")
Error: This is a error!
change to:
Incorrect: This is a error!
I need to use stop function, not warning or message functions.
There's a risk that this could be confusing for users seeing something that's an stopping the code without explicitly announcing that it's an error.
If you can guarantee that the user is using English, you can hack it a bit using the backspace character (\b) with:
stop("\b\b\b\b\b\b\bIncorrect: This is a error!")
but this relies on knowing how long the word "Error" is in English, a version that also works in other languages would be trickier.
Edited to add that even in English this doesn't work from inside a function:
throw_an_error <- function()stop("\b\b\b\b\b\b\bIncorrect: This is a error!")
throw_an_error()
# Error in throw_an_errIncorrect: This is a error!
Related
I am coding in R and due to stability purposes when I have to deploy something, I call every function with the syntax package::function(arguments) just to avoid conflicts that as you know may happen when using a lot of packages. It helped me a lot over the years.
I know that if is a reserved word so technically speaking it is impossible (or at least it should be in my knowledge) for someone to define an object and name it if.
I am also aware that it belongs to control flow statement (which I think are a different "thing") and due to the previous consideration I am also aware that the following questions might be useless. My pure technical doubts are:
Why if I embrace it in back-ticks the function class returns "function" as a result?
Why without back-ticks I get an error? and last but most important
Why I am unable to access it via the usual base::if() syntax?
As I said, most likely useless questions but at this point I am curious about the details underneath it.
> class(if)
Error: unexpected ')' in "class(if)"
> class(`if`)
[1] "function"
> base::if(T) T
Error: unexpected 'if' in "base::if"
> if(T) T
[1] TRUE
> base::if(`T`) T
Error: unexpected 'if' in "base::if"
if-with-backticks actually returns .Primitive("if")
The R language definition section on "Internal vs Primitive" specifies that .Primitive objects include
“Special functions” which really are language elements, but implemented as primitive functions:
{ ( if for while repeat break next
return function quote switch
The reason that a naked "if" without backticks or base::if don't work is that the "language elements" above are treated as special cases by R's parser. Once you have typed base::, R's parser expects the next symbol to be a regular symbol that can be looked up in the base namespace. base::if, base::for, and base::( all return errors because R does not expect these special elements to occur at this position in the input stream; they are syntactically incorrect.
I have a function that used to accept unquoted input back when I was first learning about NSE and now I hate it in this use case. I want to force the function to only take a string, but provide a clear error message on what happened back to the user.
My problem is testing for what type of input is being passed along. I can use rlang::quo_is_symbol(rlang::enquo(str_x)), but this will fail when chaining together multiple functions. Here is my cut at a reprex.
fun1 <- function(str_x) {
depr_str_x(str_x)
paste("this is x", str_x)
}
depr_str_x <- function(str_x) {
if (rlang::quo_is_symbol(rlang::enquo(str_x))) {
stop("this is a clear error message to the user")
}
invisible(NULL)
}
So when I run this, I get what I want.
depr_str_x("test") # nothing (which I want)
depr_str_x(test) # my custom error (which I want)
But when I run this, I get the error both times. How do I get it to recognize that "test" being passed through is a string? I have also tried rlang::is_scalar_character() but that fails for the symbol case. I was hoping there was a quick and easy way to do this without forcing evaluation and seeing if it fails or something.
fun1("test") # my custom error (which I don't want)
fun1(test) # my custom error (which I want)
Further, this should work when the function gets used inside of other functions. This is where I keep running into problems with my approaches.
fun2 <- function(str_x) fun1(str_x)
fun2("test") # my custom error (which I don't want)
fun2(test) # my custom error (which I want)
I have it working (but am not sure this won't have bugs creeping up) by crudely trapping the error object 'x' not found. I am leaving the question open and welcome better solutions.
depr_str_x <- function(str_x) {
is_valid <- tryCatch(rlang::is_scalar_character(str_x),
error = function(e) {
if (grepl("not found", e, fixed = TRUE)) {
return(FALSE)
} else {
stop(e)
}
})
if (!is_valid)
stop("this is a clear error message to the user")
}
NSE arguments and arguments that may or may not be NSE require quasiquotation to be properly passed from one function to the next. The most straightforward way is to use {{:
fun1 <- function(str_x) {
depr_str_x({{str_x}}) # <-- Note the {{ operator
paste("this is x", str_x)
}
fun1("test") # [1] "this is x test"
fun1(test) # Error in depr_str_x({ : this is a clear error message to the user
The same holds for fun2:
fun2 <- function(str_x) fun1({{str_x}}) # <---- Ditto on {{
fun2("test") # [1] "this is x test"
fun2(test) # Error in depr_str_x({ : this is a clear error message to the user
EDIT: Something to keep in mind is that by allowing arguments that may or may not be NSE, you are creating ambiguity. Consider,
test <- "This is a string"
fun2(test) # What should happen here?
My general advice for your situation would be to drop NSE support altogether and document the change. NSE input will then fail automatically, but with an error that says "Variable test not found", which should be enough for most users to figure what the issue is.
I have an expression that spits out multiple errors:
stop("first")
stop("second")
stop("third")
print("success")
Is there a way to make this expression run all the way to the end (and, if possible, store all of the errors)?
The problem with tryCatch is that it stops execution on the first handled condition (so this will print "There was an error" exactly once).
tryCatch({
stop("first")
stop("second")
stop("third")
print("success")
}, error = function(e) print("There was an error"))
I read that withCallingHandlers will capture conditions and continue execution, so I tried something like this...
withCallingHandlers(
{...},
error = function(e) print("There was an error")
)
...but, although this does print the message, it also fails after the first error, which, as far as I can tell, is because the default restart just runs the current line again.
I think what I need to do is write a custom restart that simply skips the current expression and jumps to the next one, but I'm at a bit of a loss about how to go about that.
(Background: Basically, I'm trying to replicate what happens inside testthat::test_that, which is that even though each failing expectation throws an error, all expectations are run before quitting).
I have made a progress bar using the winProgressBar method in R. What I want to do is if someone instantiates my program while it is doing all of its processing, I want the current progress bar to close. I tried using a statement that says
if(exists(progressBar)) {
close(progressBar);
}
but I get an error from the console that says
Error in exists(progressBar) : object 'progressBar' not found
I know that it will not exist during the first iteration of my program, but there is no reason that I can find that would make an if statement cause the program to crash.
If you read the help for exists you will see the following under Arguments
x a variable name (given as a character string).
So
exists('progressBar')
will return TRUE or FALSE.
Sometimes R throws me errors such as
Error in if (ncol(x) != 2) { : argument is of length zero
with no additional information, when I've written no such code. Is there a general way for finding which function in which package causes an error?
Since most packages come compressed, it isn't trivial to grep /usr/lib/R/library.
You can use traceback() to locate where the last error occurred. Usually it will point you to a call you make in your function. Then I typically put browser() at that point, run the function again and see what is going wrong.
For example, here are two functions:
f2 <- function(x)
{
if (x==1) "foo"
}
f <- function(x)
{
f2(x)
}
Note that f2() assumes an argument of length 1. We can misuse f:
> f(NULL)
Error in if (x == 1) "foo" : argument is of length zero
Now we can use traceback() to locate what went wrong:
> traceback()
2: f2(x) at #3
1: f(NULL)
The number means how deep we are in the nested functions. So we see that f calls f2 and that gives an error at line 3. Pretty clear. We could reassign f with browser placed just before the f2 call now to check it's input. browser() simply allows you to stop executing a function and look around in its environment. Similar to debug and debugonce except that you don't have to execute every line up until the point you know something goes wrong.
Just to add to what #SachaEpskamp has already suggested, setting options(error=recover) and options(show.error.locations=TRUE) can be extremely helpful when debugging unfamiliar code. The first causes R to launch a debugging session on error, giving you the option to invoke the browser at any point in the call stack up to that error. The second option will tell R to include the source line number in the error.