Guidance for managing R package lifecycle according to tidyverse principles using the lifecycle package. Use when: (1) Setting up lifecycle infrastructure in a package, (2) Deprecating functions or arguments, (3) Renaming functions or arguments, (4) Superseding functions, (5) Marking functions as experimental, (6) Understanding lifecycle stages (stable, experimental, deprecated, superseded), or (7) Writing deprecation helpers for complex scenarios.
lifecycle-*.svg files in man/figures/.usethis::use_lifecycle()
Imports in DESCRIPTION@importFrom lifecycle deprecated to the package documentation fileman/figures/#' @description
#' `r lifecycle::badge("experimental")`
#' `r lifecycle::badge("deprecated")`
#' `r lifecycle::badge("superseded")`
#' @param old_arg `r lifecycle::badge("deprecated")` Use `new_arg` instead.
@description:#' Do something
#'
#' @description
#' `r lifecycle::badge("deprecated")`
#'
#' `old_fun()` was deprecated in mypkg 1.0.0. Use [new_fun()] instead.
#' @keywords internal
deprecate_warn() as first line of function body:old_fun <- function(x) {
lifecycle::deprecate_warn("1.0.0", "old_fun()", "new_fun()")
new_fun(x)
}
#' @examples
#' old_fun(x)
#' # ->
#' new_fun(x)
| Function | When to Use |
|---|---|
deprecate_soft() | First stage; warns only direct users and during tests |
deprecate_warn() | Standard deprecation; warns once per 8 hours |
deprecate_stop() | Final stage before removal; errors with helpful message |
deprecate_stop() - consider removing function entirelydeprecate_warn() with deprecate_stop()deprecate_soft() with deprecate_warn()#' @description
#' `r lifecycle::badge("deprecated")`
#'
#' `add_two()` was renamed to `number_add()` for API consistency.
#' @keywords internal
#' @export
add_two <- function(x, y) {
lifecycle::deprecate_warn("1.0.0", "add_two()", "number_add()")
number_add(x, y)
}
#' Add two numbers
#' @export
number_add <- function(x, y) {
x + y
}
deprecated() as default value with is_present() check:#' @param path `r lifecycle::badge("deprecated")` Use `file` instead.
write_file <- function(x, file, path = deprecated()) {
if (lifecycle::is_present(path)) {
lifecycle::deprecate_warn("1.4.0", "write_file(path)", "write_file(file)")
file <- path
}
# ... rest of function
}
add_two <- function(x, y, na_rm = TRUE, na.rm = deprecated()) {
if (lifecycle::is_present(na.rm)) {
lifecycle::deprecate_warn("1.0.0", "add_two(na.rm)", "add_two(na_rm)")
na_rm <- na.rm
}
sum(x, y, na.rm = na_rm)
}
#' Gather columns into key-value pairs
#'
#' @description
#' `r lifecycle::badge("superseded")`
#'
#' Development on `gather()` is complete. For new code, use [pivot_longer()].
#'
#' `df %>% gather("key", "value", x, y, z)` is equivalent to
#' `df %>% pivot_longer(c(x, y, z), names_to = "key", values_to = "value")`.
#' @description
#' `r lifecycle::badge("experimental")`
cool_function <- function() {
lifecycle::signal_stage("experimental", "cool_function()")
# ...
}
test_that("old_fun is deprecated", {
expect_snapshot({
x <- old_fun(1)
expect_equal(x, expected_value)
})
})
test_that("old_fun returns correct value", {
withr::local_options(lifecycle_verbosity = "quiet")
expect_equal(old_fun(1), expected_value)
})
warn_for_verbose <- function(
verbose = TRUE,
env = rlang::caller_env(),
user_env = rlang::caller_env(2)
) {
if (!lifecycle::is_present(verbose) || isTRUE(verbose)) {
return(invisible())
}
lifecycle::deprecate_warn(
when = "2.0.0",
what = I("The `verbose` argument"),
details = c(
"Set `options(mypkg_quiet = TRUE)` to suppress messages.",
"The `verbose` argument will be removed in a future release."
),
user_env = user_env
)
invisible()
}
my_function <- function(..., verbose = deprecated()) {
warn_for_verbose(verbose)
# ...
}
I() to wrap custom text:lifecycle::deprecate_warn(
when = "1.0.0",
what = I('Setting option "pkg.opt" to "foo"'),
with = I('"pkg.new_opt"')
)
what fragment must work with "was deprecated in..." appended.references/lifecycle-stages.md for detailed stage definitions and transitions.