Is there a function in R to check if there is an error in r script or in a log? - r

I'm trying to create an if statement to check whether there is any errors in my R script (or error displayed on the console) and also log files if there are to have "error" in a variable and if there isn't to have "no error" in the same variable.
I looked at is.error() however I want to check if an error is shown on the console or log file.

There is no single-stop solution to the best of my knowledge. There are several things you can try:
1) Incorporate your script into your code and use tryCatch or try to catch any errors. More information on error catching and debugging in R can be found here.
2) Execute your script in the system shell via the system command and inspect output caught by setting intern=TRUE.

You can source the script in a new environment :
testscript <- function(scriptpath) {
tryCatch({
# Tests is the script runs without error
source(scriptpath, local = new.env())
message("Script OK")
},
error = function(cond){
message('Script not OK')
message(cond)
})}
for example, content of script.R :
x <- 1
y <- 2
x + z
testscript('script.R')
Script not OK
object 'z' not found

Related

How to pass errors back to the Rmarkdown::render function?

I am trying to render an Rmarkdown file through an R script. (Code for both files below). What I would like to do is to pass information back to the render function depending on where the error is. This may be that the file can't read the input dataset. I would like to do this as I would like to run the script as a cron job and would like it to send me an email telling me why I might need to re run the code or what the error is.
I have read some of the other stackoverflow similar questions and couldn't see how it did what I wanted with some testing.
The r script: (I have attempted using something like the following)
rm(list = ls())
setwd("C:/Users/joel.kandiah/Downloads")
a <- print(try(rmarkdown::render("test.Rmd", quiet = T), TRUE))
#> [1] "C:/Users/joel.kandiah/Downloads/test.nb.html"
cat(eval(a))
#> C:/Users/joel.kandiah/Downloads/test.nb.html
The Rmarkdown document:
if(!exists("data_raw")) simpleError("Dataset has not been loaded")
#> <simpleError: Dataset has not been loaded>
What I would like is to see the simple error as an object in the R script. Something akin to an exit code might also be acceptable.
A possible approach, is the wrapping tryCatch around render in your R script.
R Script
# Render the markdown document; ####
tryCatch(
expr = rmarkdown::render(
"markdown.Rmd",
clean = TRUE
),
error = function(cond) {
message(cond)
},
warning = function(cond) {
message(cond)
}
)
R Markdown
# Force an error;
stop("You do not have permission to render. Admin password is needed.")
This will return the same error-message to your script.

Calling stop( ) within function causes R CMD Check to throw error

I am attempting to call stop( ) from within an internal package function (stop_quietly()) which should break the function and return to the topline. This works except that R CMD Check thinks this is an error because I am forcing stop.
How do I get around the R CMD check interpreting this as an error? The function needs to stop since it requires user input as a confirmation before it creates a file directory tree at a given location. The code currently produces a message and stops the function.
tryCatch({
path=normalizePath(path=where, winslash = "\\", mustWork = TRUE)
message(paste0("This will create research directories in the following directory: \n",path))
confirm=readline(prompt="Please confirm [y/n]:")
if(tolower(stringr::str_trim(confirm)) %in% c("y","yes","yes.","yes!","yes?")){
.....
dir.create(path, ... [directories])
.....
}
message("There, I did some work, now you do some work.")
}
else{
message("Okay, fine then. Don't do your research. See if I care.")
stop_quietly()
}
},error=function(e){message("This path does not work, please enter an appropriate path \n or set the working directory with setwd() and null the where parameter.")})
stop_quietly is an exit function I took from this post with the modification of error=NULL which suppresses R executing the error handler as a Browser. I do not want the function to terminate to a Browser I just want it to quit without throwing an error in the R CMD Check.
stop_quietly <- function() {
opt <- options(show.error.messages = FALSE, error=NULL)
on.exit(options(opt))
stop()
}
Here is the component of the error R CMD produces:
-- R CMD check results ------------------------------------------------ ResearchDirectoR 1.0.0 ----
Duration: 12.6s
> checking examples ... ERROR
Running examples in 'ResearchDirectoR-Ex.R' failed
The error most likely occurred in:
> base::assign(".ptime", proc.time(), pos = "CheckExEnv")
> ### Name: create_directories
> ### Title: Creates research directories
> ### Aliases: create_directories
>
> ### ** Examples
>
> create_directories()
This will create research directories in your current working directory:
C:/Users/Karnner/AppData/Local/Temp/RtmpUfqXvY/ResearchDirectoR.Rcheck
Please confirm [y/n]:
Okay, fine then. Don't do your research. See if I care.
Execution halted
Since your function has global side effects, I think check isn't going to like it. It would be different if you required the user to put tryCatch at the top level, and then let it catch the error. But think about this scenario: a user defines f() and calls it:
f <- function() {
call_your_function()
do_something_essential()
}
f()
If your function silently caused it to skip the second line of f(), it could cause a lot of trouble for the user.
What you could do is tell the user to wrap the call to your function in tryCatch(), and have it catch the error:
f <- function() {
tryCatch(call_your_function(), error = function(e) ...)
do_something_essential()
}
f()
This way the user will know that your function failed, and can decide whether or not to continue.
From discussion in the comments and your edit to the question, it seems like your function is only intended to be used interactively, so the above scenario isn't an issue. In that case, you can avoid the R CMD check problems by skipping the example unless it is being run interactively. This is fairly easy: in the help page for a function like create_directories(), set up your example as
if (interactive()) {
create_directories()
# other stuff if you want
}
The checks are run with interactive() returning FALSE, so this will stop the error from ever happening in the check. You could also use tryCatch within create_directories() to catch the error coming up from below if that makes more sense in your package.

Stopping R code execution upon error when run as non-interactive Rscript

How do I get an R (version 3.4.2, CentOS 6.9) script to stop on Error instead of happily continuing on? My file :
$ cat tmp.R
a = 9
print(a)
print(b)
print(d)
print("Should never get here")
Running tmp.R non-interactively it:
$ Rscript tmp.R
Looking for libraries in : ~/.R/3.4.2-lib
[1] 9
Error in print(b) : object 'b' not found
Error in print(d) : object 'd' not found
[1] "Should never get here"
Question : How do I get R to stop execution upon encountering an error?
I've tried things like options(error=stop) and options(error=browser) which work in the interactive case but not non-interactive Rscript example.
This is because I have set options(error=traceback) in my .Rprofile. Commenting it out in my .Rprofile leads to code termination at line 3 as expected. This raises issues with why this generates output. See related questions this and this.

testthat error on check() but not on test() because of ~/.Rprofile?

EDIT:
Is it possible that ~/.Rprofile is not loaded on within check(). It looks like my whole process fails since the ~/.Rprofile is not loaded.
DONE EDIT
I have a strange problem on automated testing with testthat. Actually, when I test my package with test() everything works fine. But when I test with check() I get an error message.
The error message says:
1. Failure (at test_DML_create_folder_start_MQ_script.R#43): DML create folder start MQ Script works with "../DML_IC_MQ_DATA/dummy_data" data
capture.output(messages <- source(basename(script_file))) threw an error
Error in sprintf("%s folder got created for each raw file.", subfolder_prefix) :
object 'subfolder_prefix' not found
Before this error I source a script which defines the subfolder_prefix variable and I guess this is why it works in the test() case. But I expected to get this running in the check() function as well.
I will post the complete test script here, hope it is not to complicated:
library(testthat)
context("testing DML create folder and start MQ script")
test_dir <- 'dml_ic_mq_test'
start_dir <- getwd()
# list of test file folders
data_folders <- list.dirs('../DML_IC_MQ_DATA', recursive=FALSE)
for(folder in data_folders) { # for each folder with test files
dir.create(test_dir)
setwd(test_dir)
script_file <- a.DML_prepare_IC.script(dbg_level=Inf) # returns filename I will source
test_that(sprintf('we could copy all files from "%s".',
folder), {
expect_that(
all(file.copy(list.files(file.path('..',folder), full.names=TRUE),
'.',
recursive=TRUE)),
is_true())
})
test_that(sprintf('DML create folder start MQ Script works with "%s" data', folder), {
expect_that(capture.output(messages <- source(basename(script_file))),
not(throws_error()))
})
count_rawfiles <- length(list.files(pattern='.raw$'))
created_folders <- list.dirs(recursive=FALSE)
test_that(sprintf('%s folder got created for each raw file.',
subfolder_prefix), {
expect_equal(length(grep(subfolder_prefix, created_folders)),
count_rawfiles)
})
setwd(start_dir)
unlink(test_dir, recursive=TRUE)
}
In my script I define the variable subfolder_prefix <- 'IC_' and within the test I check if the same number of folders are created for each raw file... This is what my script should do...
So as I said, I am not sure how to debug this problem here since test() works but check() fails during the testthat run.
Now that I know to look in devtools we can find the answer. Per the docs check "automatically builds and checks a source package, using all known best practices". That includes ignoring .Rprofile. It looks like check calls build and that all of that work is done is a separate (clean) R session. In contrast test appears to use your currently running session (in a new environment).

tryCatch does not catch an error if called though RScript

I'm facing a strange issue in R.
Consider the following code (a really simplified version of the real code but still having the problem) :
library(timeSeries)
tryCatch(
{
specificWeekDay <- 2
currTs <- timeSeries(c(1,2),c('2012-01-01','2012-01-02'),
format='%Y-%m-%d',units='A')
# just 2 dates out of range
start <- time(currTs)[2]+100*24*3600
end <- time(currTs)[2]+110*24*3600
# this line returns an empty timeSeries
currTs <- window(currTs,start=start,end=end)
message("Up to now, everything is OK")
# this is the line with the uncatchable error
currTs[!(as.POSIXlt(time(currTs))$wday %in% specificWeekDay),] <- NA
message("I'm after the bugged line !")
},error=function(e){message(e)})
message("End")
When I run that code in RGui, I correctly get the following output:
Up to now, everything is OK
error in evaluating the argument 'i' in
selecting a method for function '[<-': Error in
as.POSIXlt.numeric(time(currTs)) : 'origin' must be supplied
End
Instead, when I run it through RScript (in windows) using the following line:
RScript.exe --vanilla "myscript.R"
I get this output:
Up to now, everything is OK
Execution interrupted
It seems like RScript crashes...
Any idea about the reason?
Is this a timeSeries package bug, or I'm doing something wrong ?
If the latter, what's the right way to be sure to catch all the errors ?
Thanks in advance.
EDIT :
Here's a smaller example reproducing the issue that doesn't use timeSeries package. To test it, just run it as described above:
library(methods)
# define a generic function
setGeneric("foo",
function(x, ...){standardGeneric("foo")})
# set a method for the generic function
setMethod("foo", signature("character"),
function(x) {x})
tryCatch(
{
foo("abc")
foo(notExisting)
},error=function(e)print(e))
It seems something related to generic method dispatching; when an argument of a method causes an error, the dispatcher cannot find the signature of the method and conseguently raises an exception that tryCatch function seems unable to handle when run through RScript.
Strangely, it doesn't happen for example with print(notExisting); in that case the exception is correctly handled.
Any idea about the reason and how to catch this kind of errors ?
Note:
I'm using R-2.14.2 on Windows 7
The issue is in the way the internal C code implementing S4 method dispatch tries to catch and handle some errors and how the non-interactive case is treated in this approach. A work-around should be in place in R-devel and R-patched soon.
Work-around now committed to R-devel and R-patched.
Information about tryCatch() [that the OP already knew and used but I didn't notice]
I think you are missing that your tryCatch() is not doing anything special with the error, hence you are raising an error in the normal fashion. In interactive use the error is thrown and handled in the usual fashion, but an error inside a script run in a non-interactive session (a la Rscript) will abort the running script.
tryCatch() is a complex function that allows the potential to trap and handle all sorts of events in R, not just errors. However by default it is set up to mimic the standard R error handling procedure; basically allow the error to be thrown and reported by R. If you want R to do anything other than the basic behaviour then you need to add a specific handler for the error:
> e <- simpleError("test error")
> tryCatch(foo, error = function(e) e,
+ finally = writeLines("There was a problem!"))
There was a problem!
<simpleError in doTryCatch(return(expr), name, parentenv, handler): object 'foo'
not found>
I suggest you read ?tryCatch in more detail to understand better what it does.
An alternative is to use try(). To modify your script I would just do:
# this is the line with the uncatchable error
tried <- try(currTs[!(as.POSIXlt(time(currTs))$wday %in% specificWeekDay),] <- NA,
silent = TRUE)
if(inherits(tried, "try-error")) {
writeLines("There was an error!")
} else {
writeLines("Everything worked fine!")
}
The key bit is to save the object returned from try() so you can test the class, and to have try() operate silently. Consider the difference:
> bar <- try(foo)
Error in try(foo) : object 'foo' not found
> bar <- try(foo, silent = TRUE)
> class(bar)
[1] "try-error"
Note that in the first call above, the error is caught and reported as a message. In the second, it is not reported. In both cases an object of class "try-error" is returned.
Internally, try() is written as a single call to tryCatch() which sets up a custom function for the error handler which reports the error as a message and sets up the returned object. You might wish to study the R code for try() as another example of using tryCatch().

Resources