Search code examples
rlifecyclerlang

How to display a warning only once per session?


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)

Solution

  • UPDATE mid-2021:

    There is now a built-in option in {rlang}. See the help here.

    rlang::warn("This message is displayed once per session.",   .frequency = "once")
    

    ORIGINAL ANSWER:

    While Aurèle's answer clearly wins the game, tidyselect's function was not exactly fit for my needs, as it required some unexported functions.

    For folks who want a simple function to use in their package, here is mine:

    #' @importFrom rlang env env_has inform
    #' @importFrom crayon silver has_color
    #' @author tidyselect (https://github.com/r-lib/tidyselect/blob/2fab83639982d37fd94914210f771ab9cbd36b4b/R/utils.R#L281)
    warning_once = function(msg, id=msg) {
        stopifnot(is_string(id))
        
        if (env_has(warning_env, id)) {
            return(invisible(NULL))
        }
        inform_env[[id]] = TRUE
        
        x = "This message is displayed once per session."
        if(is_installed("crayon") && crayon::has_color())
            x=crayon::silver(x)
        warn(paste(msg, x, sep = "\n"))
    }
    warning_env = rlang::env()