首页 > 解决方案 > 如何在每个会话中仅显示一次警告?

问题描述

我的包中有一个功能应该谨慎使用。

用户应该意识到这一点,但如果他/她认为情况没问题,那么每次调用函数时都显示警告会很麻烦。

我经常看到只显示一次的警告。它们调试起来非常痛苦,所以我找不到可重现的示例(如果有的话,我会添加一个),但是它们显示了特定的警告消息,然后是rlang信息:

每个会话显示一次此警告

有很多帮助想要调试这些消息(例如hereherehere,只需google“r This warning is displayed once per session”)

我认为该软件包lifecyle经常使用那些进行软弃用,但我无法发现lifecycle:::lifecycle_build_message.

我怎样才能在我的包裹中抛出这样的警告?

编辑:

这是一个可重现的例子。您必须重新启动 R 会话才能再次显示。如您所见,options(warn=2)没有影响。

options(warn=2)
xx=c("Sepal.Width")
tidyselect::vars_select(names(iris), xx)

标签: rlifecyclerlang

解决方案


在 的情况下tidyselect::vars_select,诀窍在于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.")
  ))

inform_env维护一个记录给定消息是否已经显示的环境。


在 的情况下lifecycle,它与使用deprecation_env的环境类似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)
}

推荐阅读