From Philippe.Grosjean at umh.ac.be  Sun Jun 25 19:43:18 2006
From: Philippe.Grosjean at umh.ac.be (Philippe Grosjean)
Date: Sun, 25 Jun 2006 19:43:18 +0200
Subject: [Rd] using withCallingHandlers, how to deal with warning( ,
 immediate. = TRUE)?
Message-ID: <449ECB36.4050208@umh.ac.be>

Hello,

I want to use withCallingHandlers(expr, warning = function(w) { ....}), 
that is, to use a custom warning handler. I want this handler to 
replicate the behavior of the usual handler. I have problems with the 
mode 'options(warn = 0)' where the warnings are delayed, except if 
calling  'warning("message", immediate. = TRUE). Indeed, if my custom 
warning handler manages to delay the display of warning messages, it 
cannot detect if the argument immediate. = TRUE was use, and thus, it 
cannot behave consequently.

Here is a toy example to illustrate my problem (whole script at the end 
of this message):

 > # This is what I want to replicate in my own handler:
 > options(warn = 0)
 > options(warning.expression = NULL)
 > for (i in 1:3) {
+   print(i)
+   warning("test", immediate. = (i < 2))
+ }
[1] 1
Warning: test
[1] 2
[1] 3
Warning messages:
1: test
2: test
# First warning is NOT delayed, but the others are

Here is what I could use if I do not delay printing of warnings:

 > options(warning.expression = NULL)
 > options(warning.expression = expression()) # Disable normal warnings
 > withCallingHandlers(for (i in 1:3) {print(i);
+   warning("test", immediate. = (i < 2))},
+   warning = function(w)
+   cat("Warning:", conditionMessage(w), "\n"))
[1] 1
Warning: test
[1] 2
Warning: test
[1] 3
Warning: test
 > options(warning.expression = NULL)

It gets a little bit more complex to delay handling of warning messages, 
but basically, I manage it that way:

 > options(warning.expression = NULL)
 > options(warning.expression = NULL)
 > options(warning.expression = expression()) # Disable normal warnings
 > if (exists("last.warning", envir = .GlobalEnv))
+   rm("last.warning", envir = .GlobalEnv)
 > withCallingHandlers(for (i in 1:3) {print(i);
+   warning("test", immediate. = (i < 2))},
+   warning = function(w) {
+     if (exists("last.warning", envir = .GlobalEnv)) {
+       lwarn <- get("last.warning", envir = .GlobalEnv)
+     } else lwarn <- list()
+     # Do not add more than 50 warnings
+     if (length(lwarn) >= 50) return()
+     # Add the warning to this list
+     nwarn <- length(lwarn)
+     names.warn <- names(lwarn)
+     Call <- conditionCall(w)
+     lwarn[[nwarn + 1]] <- Call
+     names(lwarn) <- c(names.warn, conditionMessage(w))
+     # Save the modified version in .GlobalEnv
+     last.warning <<- lwarn
+ })
[1] 1
[1] 2
[1] 3
 > invisible(warnings()) # Now display delayed warnings()
Warning messages:
1: test in: withCallingHandlers(for (i in 1:3) {  ...
2: test in: withCallingHandlers(for (i in 1:3) {  ...
3: test in: withCallingHandlers(for (i in 1:3) {  ...
 > options(warning.expression = NULL)

Now, obviously, I need a mechanism to detect if 'immediate. = TRUE' was 
used in warning(), in order to delay or not accordingly, and replicate 
exactly the example above... BUT... I have no idea at all where I can 
find this information! Could someone help me, please?
Best,

Philippe Grosjean

P.S.: here is the complete script of the toy example:

### The example we want to replicate with our own handler
options(warn = 0)
options(warning.expression = NULL)
for (i in 1:3) {
   print(i)
   warning("test", immediate. = (i < 2))
}

### A custom warning handler that does NOT delay warning messages
options(warning.expression = NULL)
options(warning.expression = expression()) # Disable normal warnings
withCallingHandlers(for (i in 1:3) {print(i);
   warning("test", immediate. = (i < 2))},
   warning = function(w)
   cat("Warning:", conditionMessage(w), "\n"))
options(warning.expression = NULL)

### A custom warning handler that ALWAYS delays warning messages
options(warning.expression = NULL)
options(warning.expression = expression()) # Disable normal warnings
if (exists("last.warning", envir = .GlobalEnv))
   rm("last.warning", envir = .GlobalEnv)
withCallingHandlers(for (i in 1:3) {print(i);
   warning("test", immediate. = (i < 2))},
   warning = function(w) {
     if (exists("last.warning", envir = .GlobalEnv)) {
       lwarn <- get("last.warning", envir = .GlobalEnv)
     } else lwarn <- list()
     # Do not add more than 50 warnings
     if (length(lwarn) >= 50) return()
     # Add the warning to this list
     nwarn <- length(lwarn)
     names.warn <- names(lwarn)
     Call <- conditionCall(w)
     lwarn[[nwarn + 1]] <- Call
     names(lwarn) <- c(names.warn, conditionMessage(w))
     # Save the modified version in .GlobalEnv
     last.warning <<- lwarn
})
invisible(warnings()) # Now display delayed warnings()
options(warning.expression = NULL)

### How do I write my handler that delays only when warn = 0 and
### immediate. = FALSE in the calling of warning() ???
# ...?



[Rd] using withCallingHandlers, how to deal with warning( , immediate. = TRUE)?
Philippe Grosjean