How can I check whether a function call results in a warning?
If you want to use the try
constructs, you can set the options for warn. See also ?options
. Better is to use tryCatch()
:
x <- function(i){
if (i < 10) warning("A warning")
i
}
tt <- tryCatch(x(5),error=function(e) e, warning=function(w) w)
tt2 <- tryCatch(x(15),error=function(e) e, warning=function(w) w)
tt
## <simpleWarning in x(5): A warning>
tt2
## [1] 15
if(is(tt,"warning")) print("KOOKOO")
## [1] "KOOKOO"
if(is(tt2,"warning")) print("KOOKOO")
To get both the result and the warning :
tryCatch(x(5),warning=function(w) return(list(x(5),w)))
## [[1]]
## [1] 5
##
## [[2]]
## <simpleWarning in x(5): A warning>
Using try
op <- options(warn=2)
tt <- try(x())
ifelse(is(tt,"try-error"),"There was a warning or an error","OK")
options(op)
Catch warnings from functions in R and still get their return-value?
Borrowing some poorly documented R magic demonstrated in this post, I think the following revised laus()
function will do the trick:
laus <- function(x) {
r <-
tryCatch(
withCallingHandlers(
{
error_text <- "No error."
list(value = hurz(x), error_text = error_text)
},
warning = function(e) {
error_text <<- trimws(paste0("WARNING: ", e))
invokeRestart("muffleWarning")
}
),
error = function(e) {
return(list(value = NA, error_text = trimws(paste0("ERROR: ", e))))
},
finally = {
}
)
return(r)
}
Now I can call laus(3)
and get:
$value
[1] 12345
$error_text
[1] "No error."
or laus(NULL)
and get:
$value
[1] 12345
$error_text
[1] "WARNING: simpleWarning in max(x): no non-missing arguments to max; returning -Inf"
or laus(foo)
and get:
$value
[1] NA
$error_text
[1] "ERROR: Error in hurz(x): object 'foo' not found"
Note the use of <<-
in the warning
function. This searches the enclosing frames of the warning
function and overwrites the error_text
value in the environment of the anonymous function that calls hurz
.
I had to use a debugger with a breakpoint in the warning
function to figure out the enclosing frames. If you don't understand environments and frames in R, just trust that using <<-
in this context will overwrite that error_text
variable that is initialized to "No error."
To understand this code a bit better, realize that withCallingHandlers()
is itself a stand-alone function. This is illustrated by the following variation of the function, which will trap and recover from warnings, but will NOT handle errors:
lausOnlyHandleWarnings <- function(x) {
r <-
withCallingHandlers(
{
error_text <- "No error."
list(value = hurz(x), error_text = error_text)
},
warning = function(e) {
error_text <<- trimws(paste0("WARNING: ", e))
invokeRestart("muffleWarning")
}
)
return(r)
}
The output from this function will be identical to the laus()
function, unless there is an error. In the case of an error, it will simply fail and report the error, as would any other function that lacks a tryCatch
. For instance, lausOnlyHandleWarnings(foo)
yields:
Error in hurz(x) : object 'foo' not found
How to detect warnings in R and have a while loop run on a function as along as warnings are outputted?
You can use tryCatch() function to catch errors and warnings and adjust your workflow based on the result, i.e:
x = -3.5
repeat{
x <- x + 0.6
print( paste("Current value of x is", x) )
result <- tryCatch( log( x ),
error = function(e) e,
warning = function(w) w )
if (inherits(result,"warning")) next # For warnings - continue the next iteration
if (inherits(result,"error")) stop( result ) # For errors - stop
print( paste0(" log(",x,")=", result))
break
}
# [1] "Current value of x is -2.9"
# [1] "Current value of x is -2.3"
# [1] "Current value of x is -1.7"
# [1] "Current value of x is -1.1"
# [1] "Current value of x is -0.5"
# [1] "Current value of x is 0.1"
# [1] " log(0.1)=-2.30258509299404"
However, be very careful with repeat and while loops as you might end up creating an infinite loop. It might be a good idea to check how many iterations the loop has executed and abort it in case there have been too many iterations:
x = -3.5
iter <- 0
while (iter < 100) {
x <- x + 0.6
iter <- iter + 1
print( paste("Current value of x is", x) )
result <- tryCatch( log( x ),
error = function(e) e,
warning = function(w) w )
if (inherits(result,"warning")) next # For warnings - continue the next iteration
if (inherits(result,"error")) stop( result ) # For errors - stop
print( paste0(" log(",x,")=", result))
break
}
How do I save warnings and errors as output from a function?
Maybe this is the same as your solution, but I wrote a factory
to convert plain old functions into functions that capture their values, errors, and warnings, so I can
test <- function(i)
switch(i, "1"=stop("oops"), "2"={ warning("hmm"); i }, i)
res <- lapply(1:3, factory(test))
with each element of the result containing the value, error, and / or warnings. This would work with user functions, system functions, or anonymous functions (factory(function(i) ...)
). Here's the factory
factory <- function(fun)
function(...) {
warn <- err <- NULL
res <- withCallingHandlers(
tryCatch(fun(...), error=function(e) {
err <<- conditionMessage(e)
NULL
}), warning=function(w) {
warn <<- append(warn, conditionMessage(w))
invokeRestart("muffleWarning")
})
list(res, warn=warn, err=err)
}
and some helpers for dealing with the result list
.has <- function(x, what)
!sapply(lapply(x, "[[", what), is.null)
hasWarning <- function(x) .has(x, "warn")
hasError <- function(x) .has(x, "err")
isClean <- function(x) !(hasError(x) | hasWarning(x))
value <- function(x) sapply(x, "[[", 1)
cleanv <- function(x) sapply(x[isClean(x)], "[[", 1)
Check whether certain function is used inside a nested function in R
You could use the all.names
function. It pulls out the names of all the variables/function defined inside the function
all.names(body(foo))
# [1] "{" "select" "df" "!" "!" "sym"
# [7] "x"
Part of the problem with your specific example is that !!sym
isn't really a simple variable. It's more like a call to !(!(sym))
to the parser. The !!
stuff really isn't a special operator to the R parser, it's just two calls to the negation operator which rlang re-interprets via non-standard evaluation.
How to test whether a function called from within a tkinter GUI yields a RunTimeWarning?
If the warning extended Warning
(which RuntimeWarning
should), you should be able to catch it with the catch_warnings
context manager, see here for an example.
But you should be able to do something like:
import warnings
with warnings.catch_warnings(record=True) as w:
outside_function(...)
# code to check if there was a warning
if len(w) > 0:
# do something, e.g. check to see the warning type/whatnot
R Error Handling - how to ask whether user wants to proceed when a Warning appears
You can use tryCatch
.
Suppose I want to convert character strings to numbers. Ordinarily, if a character vector contains some strings that can't be coerced into numbers, then calling as.numeric
on the vector will proceed without error, but will emit a warning saying that NA
values have been introduced by coercion.
If I want more control over this process by being explicitly asked whether to go ahead with the conversion when NAs are going to be produced by coercion, then I could do:
convert_to_numeric <- function(x) {
tryCatch({
as.numeric(x)
},
warning = function(w) {
cat("Warning!", w$message, '\n')
cont <- readline('Do you wish to continue? [Y/N] ')
if(cont != 'Y') stop('Aborted by user')
return(suppressWarnings(as.numeric(x)))
}
)
}
Which results in the following behaviour:
convert_to_numeric(c('1', '2', '3'))
#> [1] 1 2 3
convert_to_numeric(c('1', '2', 'banana'))
#> Warning! NAs introduced by coercion
Do you wish to continue? [Y/N] Y
#> [1] 1 2 NA
convert_to_numeric(c('1', '2', 'banana'))
#> Warning! NAs introduced by coercion
Do you wish to continue? [Y/N] N
#> Error in value[[3L]](cond) : Aborted by user
Related Topics
How to Use R with Google Colaboratory
How to Add a Cumulative Column to an R Dataframe Using Dplyr
Linear Regression Loop for Each Independent Variable Individually Against Dependent
Generate an Incrementally Increasing Sequence Like 112123123412345
Find Duplicated Rows (Based on 2 Columns) in Data Frame in R
How to Order the Months Chronologically in Ggplot2 Short of Writing the Months Out
Can't Print to PDF Ggplot Charts
Passing Command Line Arguments to R Cmd Batch
Plot 4 Curves in a Single Plot with 3 Y-Axes
Converting Geo Coordinates from Degree to Decimal
Cannot Install an R Package from Github
Split Code Over Multiple Lines in an R Script
Drawing Pyramid Plot Using R and Ggplot2
Error in Grid.Call(L_Textbounds, As.Graphicsannot(X$Label), X$X, X$Y,:Polygon Edge Not Found
Collapse Rows with Overlapping Ranges