user18894435
user18894435

Reputation: 531

Compress any numbers of warning messages into one

From ?options, the description of warn said

If 10 or fewer warnings were signalled, they will be printed, otherwise a message saying how many were signalled.

So if there are more than 10 warnings, they will be compressed into 1 message. For example:

f <- function() {
  warning("warn 1")
  warning("warn 2")
  warning("warn 3")
  warning("warn 4")
  warning("warn 5")
  warning("warn 6")
  warning("warn 7")
  warning("warn 8")
  warning("warn 9")
  warning("warn 10")
  warning("warn 11")
  return(1)
}

f()

[1] 1
There were 11 warnings (use warnings() to see them)

How can I reduce the limit of 10 to 1? I.e. Even if I have only one warning, I expect it to show

There were 1 warnings (use warnings() to see them)

Upvotes: 4

Views: 83

Answers (1)

jay.sf
jay.sf

Reputation: 73437

Couldn't find an option to globally set this threshold to a custom value (might be a nice feature request you could discuss on r-devel). Instead, you could use a wrapper function to summarize warnings where needed. We'd need an environment since---for good reason---'last.warning' is read-only.

W <- \(FUN) {
  env <- new.env()
  env$w_lst <- list()  ## empty warning list to increment
  res <- withCallingHandlers(FUN, warning=\(w) {
    env$w_lst <- c(env$w_lst, list(w))
    invokeRestart('muffleWarning')
  })
  n <- length(env$w_lst)  ## count warnings
  if (n > 0) {
    more <- (n > 1L) + 1L
    msg <- sprintf('There %s %s warning%s (use warnings2() to see %s)',
                   switch(more, 'was', 'were'),
                   n,
                   switch(more, '', 's'),
                   switch(more, 'it', 'them')
    )
    message('Warning: ', msg)
    assign('last.warning', env$w_lst, envir=warn_env)  ## assign warnings to env
  }
  res
}
## alternative warnings function
warnings2 <- \() {
  if (exists("last.warning", envir=warn_env)) {
    w_lst <- get("last.warning", envir=warn_env)
    for (i in seq_along(w_lst)) {
      message(sprintf('Warning %d: %s', i, conditionMessage(w_lst[[i]])))
    }
  } else {
    base::warnings()
  }
}

> warn_env <- new.env()  ## create env for 'last.waning'
> 
> W(f(0))
[1] 1
> W(f(1))
Warning: There was 1 warning (use warnings2() to see it)
[1] 1
> W(f(2))
Warning: There were 2 warnings (use warnings2() to see them)
[1] 1
> W(f(11))
Warning: There were 11 warnings (use warnings2() to see them)
[1] 1
> 
> warnings2()
Warning 1: foo
Warning 2: foo
Warning 3: foo
Warning 4: foo
Warning 5: foo
Warning 6: foo
Warning 7: foo
Warning 8: foo
Warning 9: foo
Warning 10: foo
Warning 11: foo

Data:

f <- \(n) {
  replicate(n, warning('foo'))
  return(1)
}

Upvotes: 3

Related Questions