Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to display a warning only once per session?

Tags:

r

lifecycle

rlang

There is a functionality in my package that should be used with caution.

The user should be aware of this but if he/she thinks that the situation is OK then it would be bothering to show the warning each time the function is called.

I often see warnings that are displayed only once. They are quite painful to debug so I couldn't find a reproducible example (I'll add one if I get any) but they show a specific warning message, followed by the rlang info:

This warning is displayed once per session

There are a lot of help wanted to debug those messages (for instance here, here, or here, just google "r This warning is displayed once per session")

I think that the package lifecyle often uses those for soft-deprecation, but I wasn't able to discover the trick in lifecycle:::lifecycle_build_message.

How can I throw such a warning in my package?

EDIT:

Here is a reproducible example. You have to restart your R session for it to show again. As you can see, options(warn=2) had no impact.

options(warn=2)
xx=c("Sepal.Width")
tidyselect::vars_select(names(iris), xx)
like image 270
Dan Chaltiel Avatar asked Apr 07 '20 08:04

Dan Chaltiel


1 Answers

In the case of tidyselect::vars_select, the trick is in tidyselect:::inform_once.

  if (env_has(inform_env, id)) {
    return(invisible(NULL))
  }
  inform_env[[id]] <- TRUE

  # ....

  inform(paste_line(
    msg, silver("This message is displayed once per session.")
  ))

An environment inform_env is maintained that records whether a given message has been displayed already.


In the case of lifecycle, it works similarly with environment deprecation_env being used in deprecate_warn

deprecate_warn <- function(....) {
  msg <- lifecycle_build_message(when, what, with, details, "deprecate_warn")

  # ....

  if (verbosity == "quiet") {
    return(invisible(NULL))
  }

  if (verbosity == "default" && !needs_warning(id) && ....) {
    return(invisible(NULL))
  }

  # ....

    if (verbosity == "default") {
      # Prevent warning from being displayed again
      env_poke(deprecation_env, id, Sys.time());

      msg <- paste_line(
        msg,
        silver("This warning is displayed once every 8 hours."),
        silver("Call `lifecycle::last_warnings()` to see where this warning was generated.")
      )
    }

    # ....
}

needs_warning <- function(id) {
  last <- deprecation_env[[id]]
  if (is_null(last)) {
    return(TRUE)
  }

  # ....

  # Warn every 8 hours
  (Sys.time() - last) > (8 * 60 * 60)
}
like image 124
Aurèle Avatar answered Sep 27 '22 20:09

Aurèle