如何在每个会话中只显示一次警告?
How to display a warning only once per session?
我的包中有一项功能应谨慎使用。
用户应该知道这一点,但如果 he/she 认为情况正常,那么每次调用该函数时都显示警告会很麻烦。
我经常看到只显示一次的警告。它们调试起来非常痛苦,所以我找不到可重现的示例(如果有的话我会添加一个)但是它们显示了一条特定的警告消息,然后是 rlang
信息:
This warning is displayed once per session
调试这些消息需要很多帮助(例如 , here, or here,只是 google“r 此警告每个会话显示一次”)
我认为包 lifecyle
经常使用这些软弃用,但我无法在 lifecycle:::lifecycle_build_message
中发现技巧。
如何在我的包裹中发出这样的警告?
编辑:
这是一个可重现的例子。您必须重新启动 R 会话才能再次显示。如您所见,options(warn=2)
没有任何影响。
options(warn=2)
xx=c("Sepal.Width")
tidyselect::vars_select(names(iris), xx)
在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
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)
}
2021 年中期更新:
{rlang}
现在有一个内置选项。见 help here.
rlang::warn("This message is displayed once per session.", .frequency = "once")
原始答案:
虽然 Aurèle 的回答显然赢得了比赛,但 tidyselect
的功能并不完全符合我的需求,因为它需要一些未导出的功能。
对于那些想要在他们的包中使用一个简单函数的人,这是我的:
#' @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()
我的包中有一项功能应谨慎使用。
用户应该知道这一点,但如果 he/she 认为情况正常,那么每次调用该函数时都显示警告会很麻烦。
我经常看到只显示一次的警告。它们调试起来非常痛苦,所以我找不到可重现的示例(如果有的话我会添加一个)但是它们显示了一条特定的警告消息,然后是 rlang
信息:
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)
在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
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)
}
2021 年中期更新:
{rlang}
现在有一个内置选项。见 help here.
rlang::warn("This message is displayed once per session.", .frequency = "once")
原始答案:
虽然 Aurèle 的回答显然赢得了比赛,但 tidyselect
的功能并不完全符合我的需求,因为它需要一些未导出的功能。
对于那些想要在他们的包中使用一个简单函数的人,这是我的:
#' @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()