[R-pkg-devel] tryCatch() doesn't capture errors due to && or || with R CMD check --as-cran
Hi Martin, I'm not sure I understand what you mean regarding suppressed warnings in testthat. - All warnings are reported to users by `devtools::test()`, with accompanying backtraces. They are not hidden. - R CMD check doesn't report warnings emitted from files in `tests/`. If you need some sort of warning to surface as errors, warnings, or notes in R CMD check, it should be possible to come up with something. This could take the form of special classes of conditions that R CMD check would catch and emit corresponding diagnostics for. We would change testthat to make sure all such conditions are properly emitted during checks. Best, Lionel
On 9/1/22, Martin Maechler <maechler at stat.math.ethz.ch> wrote:
Etienne Bacher
on Thu, 01 Sep 2022 13:55:15 +0000 writes:
Dear all,
Calling && or || with LHS or (if evaluated) RHS of length greater than one gives an error in the devel version of R and a warning since R 4.2.0. With R 4.2.1, I can capture this warning with tryCatch(). However, R CMD check with R-devel fails because of this new behavior, meaning that tryCatch() doesn't work.
Very much on purpose, even though we (the R Core team) may not have said so loudly. The problem is that too many "smart" people, including the authors of certain widely used testing packages do call tryCatch(), or suppressWarnings() and similar to eliminate warnings and errors in a situation we really *do* want these to be shown. For instance, we, the Matrix package authors, have planned to deprecate certain usages of as(*, "<someMatrixClass>") and give deprecation warnings -- see help(Deprecated) -- so the users and package authors can see the undesired usages and eventually update their code. No, because of too much use of suppressWarnings() they *NEVER EVER* see *any* deprecation warnings for all their own code which silences these warnings and for all (often 100%) of their tests where they use the famous test...t package ... An additional reason for such a non-suppressible error is that when you find such warnings/errors in package testing of packages with many dependencies, if the warning/error is raised and you *do* see it, it may *still* not at all be easy to see from which of the (sometimes 20--100) packages that are in use the problem is caused. I hope you understand that such "obnoxious" behavior is rational and desirable in such rare cases. Best regards, Martin -- Martin Maechler ETH Zurich and R Core team
For example, take this function:
foo <- function() {
tryCatch(
if (c(TRUE, TRUE) || c(TRUE, TRUE)) 1,
warning = function(w) {
print(w)
NULL
},
error = function(e) {
print(e)
NULL
}
)
}
With R 4.2.1, this correctly gives a warning and returns NULL when I run
this locally:
foo()
<simpleWarning in c(TRUE, TRUE) || c(TRUE, TRUE): 'length(x) = 2 > 1' in coercion to 'logical(1)'> NULL And if I change the environment variables to return an error instead of the warning, it correctly gives an error and returns NULL:
Sys.setenv(
`_R_CHECK_LENGTH_1_CONDITION_` = "true",
`_R_CHECK_LENGTH_1_LOGIC2_` = "true"
)
foo()
<simpleError in c(TRUE, TRUE) || c(TRUE, TRUE): 'length(x) = 2 > 1' in coercion to 'logical(1)'> NULL This behavior is expected. But if I put this function in a package, add a test for it, and run R CMD check "." --as-cran (or rcmdcheck::rcmdcheck(args = "--as-cran")), then I get an error that I paste at the end of this email because it's quite long. I thought that tryCatch() would capture this error, even when using R CMD check with R-devel, but this is not the case. Is this an expected behavior or a bug? If you want to reproduce this error, I made a tiny package here: https://github.com/etiennebacher/testpackage. You can simply clone the repo and run R CMD check on it. If it matters, I'm using R 4.2.1 on Windows 10. Thanks in advance, Etienne ----------- FAILURE REPORT -------------- --- failure: length > 1 in coercion to logical --- --- srcref --- : --- package (from environment) --- compiler --- call from context --- do.call(ffun, args) --- call from argument --- .Primitive("||")(c(TRUE, TRUE), c(TRUE, TRUE)) --- R stacktrace --- where 1: do.call(ffun, args) where 2: mode(e) where 3: mode(e) %in% constModes where 4: checkConst(do.call(ffun, args)) where 5: doTryCatch(return(expr), name, parentenv, handler) where 6: tryCatchOne(expr, names, parentenv, handlers[[1L]]) where 7: tryCatchList(expr, names[-nh], parentenv, handlers[-nh]) where 8: doTryCatch(return(expr), name, parentenv, handler) where 9: tryCatchOne(tryCatchList(expr, names[-nh], parentenv, handlers[-nh]), names[nh], parentenv, handlers[[nh]]) where 10: tryCatchList(expr, classes, parentenv, handlers) where 11: tryCatch(checkConst(do.call(ffun, args)), error = function(e) NULL, warning = function(w) NULL) where 12: constantFoldCall(e, cntxt) where 13: constantFold(test, cntxt, loc = cb$savecurloc()) where 14: h(e, cb, cntxt) where 15: tryInline(call, cb, cntxt) where 16: cmpCall(e, cb, cntxt) where 17: cmp(e, cb, cntxt, setloc = FALSE) where 18: genCode(a, pcntxt, loc = cb$savecurloc()) where 19: cb$putconst(genCode(a, pcntxt, loc = cb$savecurloc())) where 20: cmpCallArgs(args, cb, cntxt, nse) where 21: cmpCallSymFun(fun, args, call, cb, cntxt) where 22: cmpCall(e, cb, cntxt) where 23: cmp(subexp, cb, cntxt, setloc = FALSE) where 24: h(e, cb, cntxt) where 25: tryInline(call, cb, cntxt) where 26: cmpCall(e, cb, cntxt) where 27: cmp(e, cb, cntxt, setloc = FALSE) where 28: genCode(body(f), ncntxt, loc = loc) where 29: cmpfun(f) where 30: doTryCatch(return(expr), name, parentenv, handler) where 31: tryCatchOne(expr, names, parentenv, handlers[[1L]]) where 32: tryCatchList(expr, classes, parentenv, handlers) where 33: tryCatch(cmpfun(f), error = function(e) { notifyCompilerError(paste(e$message, "at", deparse(e$call))) f }) where 34: compiler:::tryCmpfun(function () { tryCatch(if (c(TRUE, TRUE) || c(TRUE, TRUE)) 1, warning = function(w) { print(w) NULL }, error = function(e) { print(e) NULL }) }) where 35: lazyLoadDBinsertVariable(vars[i], from, datafile, ascii, compress, envhook) where 36: makeLazyLoadDB(ns, dbbase, compress = compress, set.install.dir = set.install.dir) where 37: code2LazyLoadDB(package, lib.loc = lib.loc, keep.source = keep.source, keep.parse.data = keep.parse.data, compress = compress, set.install.dir = set.install.dir) where 38: tools:::makeLazyLoading("testpackage", "C:/Users/etienne/AppData/Local/Temp/Rtmp8QXtOL/file41b43ee61605/testpackage.Rcheck/00LOCK-TESTPA~1/00new", keep.source = FALSE, keep.parse.data = FALSE, set.install.dir = "C:/Users/etienne/AppData/Local/Temp/Rtmp8QXtOL/file41b43ee61605/testpackage.Rcheck/testpackage") --- value of length: 2 type: logical --- [1] TRUE TRUE --- function from context --- function (what, args, quote = FALSE, envir = parent.frame()) { if (!is.list(args)) stop("second argument must be a list") if (quote) args <- lapply(args, enquote) .Internal(do.call(what, args, envir)) } <bytecode: 0x0000021b0a155e20> <environment: namespace:base> --- function search by body --- Function do.call in namespace base has this body. ----------- END OF FAILURE REPORT -------------- Fatal error: length > 1 in coercion to logical
______________________________________________ R-package-devel at r-project.org mailing list https://stat.ethz.ch/mailman/listinfo/r-package-devel