R Package Lifecycle Management Manage function and argument lifecycle using tidyverse conventions and the lifecycle package. Setup Check if lifecycle is configured by looking for lifecycle-*.svg files in man/figures/ . If not configured, run: usethis :: use_lifecycle ( ) This: Adds lifecycle to Imports in DESCRIPTION Adds @importFrom lifecycle deprecated to the package documentation file Copies badge SVGs to man/figures/ Lifecycle Badges Insert badges in roxygen2 documentation:
' @description
' r lifecycle::badge("experimental")
' r lifecycle::badge("deprecated")
' r lifecycle::badge("superseded")
For arguments:
' @param old_arg r lifecycle::badge("deprecated") Use new_arg instead.
Only badge functions/arguments whose stage differs from the package's overall stage. Deprecating a Function Add badge and explanation to @description :
' Do something
'
' @description
' r lifecycle::badge("deprecated")
'
' old_fun() was deprecated in mypkg 1.0.0. Use [new_fun()] instead.
' @keywords internal
Add 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 ) } Show migration in examples:
' @examples
' old_fun(x)
' # ->
' new_fun(x)
Deprecation Functions 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 Deprecation workflow for major releases: Search deprecate_stop() - consider removing function entirely Replace deprecate_warn() with deprecate_stop() Replace deprecate_soft() with deprecate_warn() Renaming a Function Move implementation to new name, call from old name with deprecation:
' @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 } Deprecating an Argument Use 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
} Renaming an Argument 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 ) } Superseding a Function For functions with better alternatives that shouldn't be removed:
' 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").
No warning needed - just document the preferred alternative. Marking as Experimental
' @description
' r lifecycle::badge("experimental")
cool_function <- function ( ) { lifecycle :: signal_stage ( "experimental" , "cool_function()" )
...
}
Testing Deprecations
Test that deprecated functions work and warn appropriately:
test_that
(
"old_fun is deprecated"
,
{
expect_snapshot
(
{
x
<-
old_fun
(
1
)
expect_equal
(
x
,
expected_value
)
}
)
}
)
Suppress warnings in existing tests:
test_that
(
"old_fun returns correct value"
,
{
withr
::
local_options
(
lifecycle_verbosity
=
"quiet"
)
expect_equal
(
old_fun
(
1
)
,
expected_value
)
}
)
Deprecation Helpers
For deprecations affecting many functions (e.g., removing a common argument), create an internal helper:
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
(
)
}
Then use in affected functions:
my_function
<-
function
(
...
,
verbose
=
deprecated
(
)
)
{
warn_for_verbose
(
verbose
)
...
} Custom Deprecation Messages For non-standard deprecations, use 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"' ) ) The what fragment must work with "was deprecated in..." appended. Reference See references/lifecycle-stages.md for detailed stage definitions and transitions.