This is a bit tricky for me to describe but please see the example below. I am trying to isolate scope of some R scripts by loading the scripts into a function. But this doesn't work when loading 'nested' functions. Per example below, the function 'inside' can be called after being loaded, but then the function 'outside' errors out saying it can not find the function 'inside.'
#this would be in some file
inside <- function(a, b){
return(a+b)
}
outside <- function(c, d){
inside(c, d)
}
save.image("my_r_functions.model")
rm(list = ls())
#this would be in some other file
wrapper <- function(d, e){
load("my_r_functions.model")
print(paste('inside works: ', inside(d,e)))
print('but outside can not find inside')
outside(d,e)
}
wrapper(1,2)
output:
[1] "inside works: 3"
[1] "but outside can not find inside"
Error in outside(d, e) : could not find function "inside"
You didn't specify where you wanted it loaded. Just add envir=globalenv() (or envir=environment(wrapper)) to the call to load.
wrapper <- function(d, e){
load("my_r_functions.model",envir=environment(wrapper))
print(paste('inside works: ', inside(d,e) ))
print('but outside can not find inside')
outside(d,e)
}
wrapper(1,2)
will work
Related
I have created an R function which uses a tryCatch construct to skip over errors. The function works when executed as a standalone but gives an error when executing within an Rmarkdown file
The code is as below
for(x in 1:length(aa)){
bowlers <- unique(aa[[x]]$bowler)
for (y in 1:length(bowlers)){
#cat("x=",x,"team",theTeams[x],"\n")
tryCatch(l <- getBowlerWicketDetails(team=theTeams[x],name=bowlers[y],dir="."),
error = function(e) {
print("Error!")
}
)
l <- select(l,bowler,wickets,economyRate)
o <-rbind(o,l)
}
}
I get the following error when executing the code within an Rmd. The error is
Error in select_(.data,.dots=lazyeval::lazy_dots(...),:object l not found calls:Anonymos etc.
I think the code is trying to evaluate even when there is an error in the getBowlerWicketDetails() function when 'l' will not be available. How can this be resolved?
Finally solved the problem by adding an additional check exists(). As I mentioned, directly executing the function seemed to work while executing within Rmd gave the variable does not exist
The modified code was as follows
for(x in 1:length(aa)){
bowlers <- unique(aa[[x]]$bowler)
for (y in 1:length(bowlers)){
#cat("x=",x,"team",theTeams[x],"\n")
tryCatch(l <- getBowlerWicketDetails(team=theTeams[x],name=bowlers[y],dir="."),
error = function(e) {
#print("Error!")
}
)
if(exists("l")){
m <- select(l,bowler,wickets,economyRate)
o <-rbind(o,m)
}
}
}
This worked finally for both.
Thanks all!
I am working on a code and ran into a problem I can't seem to fix. Basically the idea is that I have one overall function and within that function are several other functions. My problem is: within one of those function I need the option to stop if a certain condition is not satisfied, but using stopifnot() of if (...) {stop} stops the overall functions as well. Is there a way in which I can stop the specific function from running without also stopping the overall function?
For example:
full=function(){
message("before")
x=2
small=function(x){
if (x<3){stop("smaller than 3")
print(x)
}
}
small(x)
message("after")
}
full()
What I want to do here is quit the "small" function if x is smaller than 3 (so x is not printed), but I still want to run the message "after". Is there a way to do that?
Thanks in advance.
Perhaps you are just looking for the return() function. Otherwise,
try error handling facilities:
full <- function() {
message("before")
small <- function(x){
if (x<3) {
# or just e.g. return(NULL)
stop("smaller than 3")
}
print(x)
}
tryCatch({
small(2)
}, error=function(err) {
# do nothing on error
})
message("after")
}
full()
## before
## after
Is there any way to stop an R program without error?
For example I have a big source, defining several functions and after it there are some calls to the functions. It happens that I edit some function, and want the function definitions to be updated in R environment, but they are not actually called.
I defined a variable justUpdate and when it is TRUE want to stop the program just after function definitions.
ReadInput <- function(...) ...
Analyze <- function(...) ...
WriteOutput <- function(...) ...
if (justUpdate)
stop()
# main body
x <- ReadInput()
y <- Analyze(x)
WriteOutput(y)
I have called stop() function, but the problem is that it prints an error message.
ctrl+c is another option, but I want to stop the source in specific line.
The problem with q() or quit() is that it terminates R session, but I would like to have the R session still open.
As #JoshuaUlrich proposed browser() can be another option, but still not perfect, because the source terminates in a new environment (i.e. the R prompt will change to Browser[1]> rather than >). Still we can press Q to quit it, but I am looking for the straightforward way.
Another option is to use if (! justUpdate) { main body } but it's clearing the problem, not solving it.
Is there any better option?
I found a rather neat solution here. The trick is to turn off all error messages just before calling stop(). The function on.exit() is used to make sure that error messages are turned on again afterwards. The function looks like this:
stop_quietly <- function() {
opt <- options(show.error.messages = FALSE)
on.exit(options(opt))
stop()
}
The first line turns off error messages and stores the old setting to the variable opt. After this line, any error that occurs will not output a message and therfore, also stop() will not cause any message to be printed.
According to the R help,
on.exit records the expression given as its argument as needing to be executed when the current function exits.
The current function is stop_quietly() and it exits when stop() is called. So the last thing that the program does is call options(opt) which will set show.error.messages to the value it had, before stop_quietly() was called (presumably, but not necessarily, TRUE).
There is a nice solution in a mailing list here that defines a stopQuietly function that basically hides the error shown from the stop function:
stopQuietly <- function(...) {
blankMsg <- sprintf("\r%s\r", paste(rep(" ", getOption("width")-1L), collapse=" "));
stop(simpleError(blankMsg));
} # stopQuietly()
> stopQuietly()
I have a similar problem and, based on #VangelisTasoulas answer, I got a simple solution.
Inside functions, I have to check if DB is updated. If it is not, stop the execution.
r=readline(prompt="Is DB updated?(y/n)")
Is DB updated?(y/n)n
if(r != 'y') stop('\r Update DB')
Update DB
Just putting \r in the beginning of the message, overwrite Error: in the message.
You're looking for the function browser.
You can use the following solution to stop an R program without error:
if (justUpdate)
return(cat(".. Your Message .. "))
Just return something at the line you want to quit the function:
f <- function(x, dry=F) {
message("hi1")
if (dry) return(x)
message("hi2")
x <- 2*x
}
y1 <- f(2) # = 4 hi1 hi2
y2 <- f(2, dry=T) # = 2 hi1
In addition to answer from Stibu on Mar 22 '17 at 7:29, if you want to write a message as a part of stop(), this message is not written.
I perceive strange that following two lines have to be used meaning on.exit(options(options(show....))) doesn't work.
opt <- options(show.error.messages = F)
on.exit(options(opt))
I had forgotten the answer to this and needed to look it up and landed here... You posted the hint to the answer in your question...
ctrl+c is another option, but I want to stop the source in specific line.
Signal an error, warning, or message
rlang::inform("Updated Only")
rlang::interrupt()
I've found it good to write a script and run it with source(). In the script, a write exit statements as a special class of error that a tryCatch() can pick up and send back as just a message:
exit <- function(..., .cl = NULL) {
# Use to capture acceptable stop
cond <- structure(
list(.makeMessage(...), .cl),
class = c("exitError", "error", "condition"),
names = c("message", "call")
)
stop(cond)
}
foo <- function() {
exit("quit here")
1
}
tryCatch(
# rather than foo(), you might use source(filename)
foo(),
exitError = function(e) message(e$message)
)
#> quit here
Created on 2022-01-24 by the reprex package (v2.0.1)
You can use with_options() in the withr package to temporarily disable error messages and then you can call stop() directly.
Here is an example:
weird_math <- function(x, y, z) {
if (x > z) {
withr::with_options(
list(show.error.messages = FALSE),
{
print("You can execute other code here if you want")
stop()
}
)
}
# only runs if x <= z
x + y ^ z
}
weird_math(1, 2, 3)
[1] 9
weird_math(3, 2, 1)
[1] "You can execute other code here if you want"
why not just use an if () {} else {}? It's only a couple of characters...
f1 <- function(){}
f2 <- function(){}
if (justUpdate) {
} else {
# main body
}
or even
f1 <- function(){}
f2 <- function(){}
if (!justUpdate) {
# main body
}
The below code work for me stopped without error messages.
opt <- options(show.error.messages = FALSE)
on.exit(options(opt))
break
Is there any way to stop an R program without error?
For example I have a big source, defining several functions and after it there are some calls to the functions. It happens that I edit some function, and want the function definitions to be updated in R environment, but they are not actually called.
I defined a variable justUpdate and when it is TRUE want to stop the program just after function definitions.
ReadInput <- function(...) ...
Analyze <- function(...) ...
WriteOutput <- function(...) ...
if (justUpdate)
stop()
# main body
x <- ReadInput()
y <- Analyze(x)
WriteOutput(y)
I have called stop() function, but the problem is that it prints an error message.
ctrl+c is another option, but I want to stop the source in specific line.
The problem with q() or quit() is that it terminates R session, but I would like to have the R session still open.
As #JoshuaUlrich proposed browser() can be another option, but still not perfect, because the source terminates in a new environment (i.e. the R prompt will change to Browser[1]> rather than >). Still we can press Q to quit it, but I am looking for the straightforward way.
Another option is to use if (! justUpdate) { main body } but it's clearing the problem, not solving it.
Is there any better option?
I found a rather neat solution here. The trick is to turn off all error messages just before calling stop(). The function on.exit() is used to make sure that error messages are turned on again afterwards. The function looks like this:
stop_quietly <- function() {
opt <- options(show.error.messages = FALSE)
on.exit(options(opt))
stop()
}
The first line turns off error messages and stores the old setting to the variable opt. After this line, any error that occurs will not output a message and therfore, also stop() will not cause any message to be printed.
According to the R help,
on.exit records the expression given as its argument as needing to be executed when the current function exits.
The current function is stop_quietly() and it exits when stop() is called. So the last thing that the program does is call options(opt) which will set show.error.messages to the value it had, before stop_quietly() was called (presumably, but not necessarily, TRUE).
There is a nice solution in a mailing list here that defines a stopQuietly function that basically hides the error shown from the stop function:
stopQuietly <- function(...) {
blankMsg <- sprintf("\r%s\r", paste(rep(" ", getOption("width")-1L), collapse=" "));
stop(simpleError(blankMsg));
} # stopQuietly()
> stopQuietly()
I have a similar problem and, based on #VangelisTasoulas answer, I got a simple solution.
Inside functions, I have to check if DB is updated. If it is not, stop the execution.
r=readline(prompt="Is DB updated?(y/n)")
Is DB updated?(y/n)n
if(r != 'y') stop('\r Update DB')
Update DB
Just putting \r in the beginning of the message, overwrite Error: in the message.
You're looking for the function browser.
You can use the following solution to stop an R program without error:
if (justUpdate)
return(cat(".. Your Message .. "))
Just return something at the line you want to quit the function:
f <- function(x, dry=F) {
message("hi1")
if (dry) return(x)
message("hi2")
x <- 2*x
}
y1 <- f(2) # = 4 hi1 hi2
y2 <- f(2, dry=T) # = 2 hi1
In addition to answer from Stibu on Mar 22 '17 at 7:29, if you want to write a message as a part of stop(), this message is not written.
I perceive strange that following two lines have to be used meaning on.exit(options(options(show....))) doesn't work.
opt <- options(show.error.messages = F)
on.exit(options(opt))
I had forgotten the answer to this and needed to look it up and landed here... You posted the hint to the answer in your question...
ctrl+c is another option, but I want to stop the source in specific line.
Signal an error, warning, or message
rlang::inform("Updated Only")
rlang::interrupt()
I've found it good to write a script and run it with source(). In the script, a write exit statements as a special class of error that a tryCatch() can pick up and send back as just a message:
exit <- function(..., .cl = NULL) {
# Use to capture acceptable stop
cond <- structure(
list(.makeMessage(...), .cl),
class = c("exitError", "error", "condition"),
names = c("message", "call")
)
stop(cond)
}
foo <- function() {
exit("quit here")
1
}
tryCatch(
# rather than foo(), you might use source(filename)
foo(),
exitError = function(e) message(e$message)
)
#> quit here
Created on 2022-01-24 by the reprex package (v2.0.1)
You can use with_options() in the withr package to temporarily disable error messages and then you can call stop() directly.
Here is an example:
weird_math <- function(x, y, z) {
if (x > z) {
withr::with_options(
list(show.error.messages = FALSE),
{
print("You can execute other code here if you want")
stop()
}
)
}
# only runs if x <= z
x + y ^ z
}
weird_math(1, 2, 3)
[1] 9
weird_math(3, 2, 1)
[1] "You can execute other code here if you want"
why not just use an if () {} else {}? It's only a couple of characters...
f1 <- function(){}
f2 <- function(){}
if (justUpdate) {
} else {
# main body
}
or even
f1 <- function(){}
f2 <- function(){}
if (!justUpdate) {
# main body
}
The below code work for me stopped without error messages.
opt <- options(show.error.messages = FALSE)
on.exit(options(opt))
break
When I use tryCatch, I can define an error handler and use conditionCall to determine the call that caused the error. For instance,
tryCatch(
eval(parse(text="prnit('Hello')")),
error=function(e) {
cl <- conditionCall(e)
#...
})
Can I get to the bad call on the R prompt? Until now, I found only this solution:
> err_hdl <- function() {
file1 <- tempfile("Rrawhist")
savehistory(file1)
rawhist <- readLines(file1)
unlink(file1)
cat("Error : ", tail(rawhist,1), "\n")
return(TRUE)
}
> options(error=err_hdl)
> prnit("Hello")
but I believe there must be a more straightforward way..
Any hint appreciated!
I put out a bounty. The first answer that implements the behaviour of the err_hdl function above without file I/O that is platform independent will be accepted.
Edit -- the code above seems only to work on windows. I am looking for the input that raised the error.
It looks like dump.frames can be told not to dump to a file but rather to an object in the .GlobalEnv. However, I haven't tested it on anything but a Mac. Would the following help?
err_hdl2 <- function() {
dump.frames("theErr", to.file = FALSE)
cat("What happened?\n", attr(theErr,"error.message"), "\nOh.\n")
}
options(error = err_hdl2)
> prnit(dt)
Error: could not find function "prnit"
What happened?
Error: could not find function "prnit"
Oh.
There might be a drawback to creating the object theErr in the global environment, I suppose.
> theErr
$`function ()
{
dump.frames("theErr", to.file = FALSE)
cat("What`
<environment: 0x1030fe140>
attr(,"error.message")
[1] "Error: could not find function \"prnit\"\n"
attr(,"class")
[1] "dump.frames"