diff --git a/.Rbuildignore b/.Rbuildignore index ed4e8d8a..5da62c7a 100644 --- a/.Rbuildignore +++ b/.Rbuildignore @@ -26,3 +26,4 @@ ^admiraldev.*\.tgz$ ^staged_dependencies.yaml$ ^README.Rmd$ +^\.devcontainer$ diff --git a/.Rprofile b/.Rprofile index 77ae067e..d059c2fc 100644 --- a/.Rprofile +++ b/.Rprofile @@ -1,15 +1,48 @@ # Set renv profile base on R version. -if ((Sys.getenv("GITHUB_ACTIONS") == "") && (Sys.getenv("DOCKER_CONTAINER_CONTEXT") == "")) { - renv_profile <- paste(R.version$major, substr(R.version$minor, 1, 1), sep = ".") - if (file.exists("./renv/profile")) { - message("Using renv profile from `renv/profile` file.") - } else if (renv_profile %in% c("4.1", "4.2", "4.3")) { - message("Set renv profile to `", renv_profile, "`") - Sys.setenv("RENV_PROFILE" = renv_profile) +.get_dependencies <- function(project_dir) { + + admdev_loc <- find.package("admiraldev", lib.loc = .libPaths(), quiet = TRUE) + adm_dev_suggests <- if(length(admdev_loc) != 0) { + renv:::renv_dependencies_discover_description(admdev_loc, fields = c("Depends", "Imports", "LinkingTo", "Suggests")) + } else { + data.frame(Packages = character(0)) + } + suggests_packages <- renv:::renv_dependencies_discover_description(project_dir, fields = "Suggests") + + packages <- names( + renv:::renv_package_dependencies( + unique(c( + project_dir, + adm_dev_suggests[["Package"]], + suggests_packages[["Package"]], + c("staged.dependencies", "renv", "styler") + )) + ) + ) + packages[!(packages %in% c("admiral", "admiraldev", "admiralci", "admiral.test", "pharmaversesdtm", getwd()))] +} + +options(renv.snapshot.filter = .get_dependencies) + +.renv_profile <- paste(R.version$major, substr(R.version$minor, 1, 1), sep = ".") +if (!file.exists("./renv/profile")) { + if (.renv_profile %in% c("4.1", "4.2", "4.3")) { + message("Set renv profile to `", .renv_profile, "`") + Sys.setenv("RENV_PROFILE" = .renv_profile) } else { message("This repository do not contains the renv profile for your R version.") } - source("renv/activate.R") } else { - options(repos = c(CRAN = "https://cran.rstudio.com")) + message( + "Using renv profile from `renv/profile` file.\n", + "The `", readLines("./renv/profile"), "` profile will be used." + ) +} + +if (Sys.getenv("GITHUB_ACTIONS") != "") { + options(repos = c(CRAN = "https://packagemanager.posit.co/cran/latest")) + Sys.setenv("RENV_AUTOLOADER_ENABLED" = FALSE) } +Sys.setenv("RENV_CONFIG_SANDBOX_ENABLED" = FALSE) +Sys.setenv("RENV_CONFIG_AUTO_SNAPSHOT" = FALSE) +source("renv/activate.R") diff --git a/.devcontainer/4.1/devcontainer.json b/.devcontainer/4.1/devcontainer.json new file mode 100644 index 00000000..1d05f7fd --- /dev/null +++ b/.devcontainer/4.1/devcontainer.json @@ -0,0 +1,76 @@ +{ + // https://containers.dev/implementors/json_reference/ + "name": "Admiral R-4.1 (RStudio) container", + "image": "ghcr.io/pharmaverse/admiralci-4.1:latest", + // Install Dev Container Features. More info: https://containers.dev/features + "containerEnv": { + "ROOT": "true", + "PASSWORD": "rstudio", + "DISABLE_AUTH": "true", + "RENV_AUTOLOADER_ENABLED": "false" + }, + "features": { + "ghcr.io/rocker-org/devcontainer-features/r-rig:1": { + "version": "none", + "vscodeRSupport": "full", + "installRadian": true, + "installVscDebugger": true + }, + "ghcr.io/rocker-org/devcontainer-features/renv-cache:latest": {}, + "ghcr.io/devcontainers/features/common-utils:2": { + "installZsh": true, + "configureZshAsDefaultShell": false, + "installOhMyZsh": true, + "username": "rstudio", + "upgradePackages": false + }, + "ghcr.io/mikaello/devcontainer-features/modern-shell-utils:1": {} + }, + "init": true, + "overrideCommand": false, + + "postCreateCommand": "bash ./.devcontainer/postCreateCommand.sh", + + "postAttachCommand": "$BROWSER \"https://${CODESPACE_NAME}-8787.${GITHUB_CODESPACES_PORT_FORWARDING_DOMAIN}/\"", + + "customizations": { + "vscode": { + "settings": { + "r.rterm.linux": "/usr/local/bin/radian", + "r.bracketedPaste": true, + "editor.bracketPairColorization.enabled": true, + "editor.guides.bracketPairs": "active" + }, + "extensions": [ + "vsls-contrib.codetour", + "GitHub.copilot", + "GitHub.copilot-chat", + // R extensions + "ikuyadeu.r", + "REditorSupport.r-lsp", + // Extra extension + "streetsidesoftware.code-spell-checker", + "eamodio.gitlens", + "cweijan.vscode-office", + "donjayamanne.githistory", + "GitHub.vscode-github-actions", + "GitHub.vscode-pull-request-github", + "GitHub.remotehub", + "alefragnani.Bookmarks", + "vscode-icons-team.vscode-icons" + ] + } + }, + + // RStudio ports + "forwardPorts": [8787], + "portsAttributes": { + "8787": { + "label": "Rstudio", + "requireLocalPort": true, + "onAutoForward": "openBrowser" + } + }, + // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root + "remoteUser": "rstudio" +} diff --git a/.devcontainer/4.2/devcontainer.json b/.devcontainer/4.2/devcontainer.json new file mode 100644 index 00000000..f30486e0 --- /dev/null +++ b/.devcontainer/4.2/devcontainer.json @@ -0,0 +1,76 @@ +{ + // https://containers.dev/implementors/json_reference/ + "name": "Admiral R-4.2 (RStudio) container", + "image": "ghcr.io/pharmaverse/admiralci-4.2:latest", + // Install Dev Container Features. More info: https://containers.dev/features + "containerEnv": { + "ROOT": "true", + "PASSWORD": "rstudio", + "DISABLE_AUTH": "true", + "RENV_AUTOLOADER_ENABLED": "false" + }, + "features": { + "ghcr.io/rocker-org/devcontainer-features/r-rig:1": { + "version": "none", + "vscodeRSupport": "full", + "installRadian": true, + "installVscDebugger": true + }, + "ghcr.io/rocker-org/devcontainer-features/renv-cache:latest": {}, + "ghcr.io/devcontainers/features/common-utils:2": { + "installZsh": true, + "configureZshAsDefaultShell": false, + "installOhMyZsh": true, + "username": "rstudio", + "upgradePackages": false + }, + "ghcr.io/mikaello/devcontainer-features/modern-shell-utils:1": {} + }, + "init": true, + "overrideCommand": false, + + "postCreateCommand": "bash ./.devcontainer/postCreateCommand.sh", + + "postAttachCommand": "$BROWSER \"https://${CODESPACE_NAME}-8787.${GITHUB_CODESPACES_PORT_FORWARDING_DOMAIN}/\"", + + "customizations": { + "vscode": { + "settings": { + "r.rterm.linux": "/usr/local/bin/radian", + "r.bracketedPaste": true, + "editor.bracketPairColorization.enabled": true, + "editor.guides.bracketPairs": "active" + }, + "extensions": [ + "vsls-contrib.codetour", + "GitHub.copilot", + "GitHub.copilot-chat", + // R extensions + "ikuyadeu.r", + "REditorSupport.r-lsp", + // Extra extension + "streetsidesoftware.code-spell-checker", + "eamodio.gitlens", + "cweijan.vscode-office", + "donjayamanne.githistory", + "GitHub.vscode-github-actions", + "GitHub.vscode-pull-request-github", + "GitHub.remotehub", + "alefragnani.Bookmarks", + "vscode-icons-team.vscode-icons" + ] + } + }, + + // RStudio ports + "forwardPorts": [8787], + "portsAttributes": { + "8787": { + "label": "Rstudio", + "requireLocalPort": true, + "onAutoForward": "openBrowser" + } + }, + // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root + "remoteUser": "rstudio" +} diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 00000000..4f49db8f --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,76 @@ +{ + // https://containers.dev/implementors/json_reference/ + "name": "Admiral R-4.3 (RStudio) container", + "image": "ghcr.io/pharmaverse/admiralci-4.3:latest", + // Install Dev Container Features. More info: https://containers.dev/features + "containerEnv": { + "ROOT": "true", + "PASSWORD": "rstudio", + "DISABLE_AUTH": "true", + "RENV_AUTOLOADER_ENABLED": "false" + }, + "features": { + "ghcr.io/rocker-org/devcontainer-features/r-rig:1": { + "version": "none", + "vscodeRSupport": "full", + "installRadian": true, + "installVscDebugger": true + }, + "ghcr.io/rocker-org/devcontainer-features/renv-cache:latest": {}, + "ghcr.io/devcontainers/features/common-utils:2": { + "installZsh": true, + "configureZshAsDefaultShell": false, + "installOhMyZsh": true, + "username": "rstudio", + "upgradePackages": false + }, + "ghcr.io/mikaello/devcontainer-features/modern-shell-utils:1": {} + }, + "init": true, + "overrideCommand": false, + + "postCreateCommand": "bash ./.devcontainer/postCreateCommand.sh", + + "postAttachCommand": "$BROWSER \"https://${CODESPACE_NAME}-8787.${GITHUB_CODESPACES_PORT_FORWARDING_DOMAIN}/\"", + + "customizations": { + "vscode": { + "settings": { + "r.rterm.linux": "/usr/local/bin/radian", + "r.bracketedPaste": true, + "editor.bracketPairColorization.enabled": true, + "editor.guides.bracketPairs": "active" + }, + "extensions": [ + "vsls-contrib.codetour", + "GitHub.copilot", + "GitHub.copilot-chat", + // R extensions + "ikuyadeu.r", + "REditorSupport.r-lsp", + // Extra extension + "streetsidesoftware.code-spell-checker", + "eamodio.gitlens", + "cweijan.vscode-office", + "donjayamanne.githistory", + "GitHub.vscode-github-actions", + "GitHub.vscode-pull-request-github", + "GitHub.remotehub", + "alefragnani.Bookmarks", + "vscode-icons-team.vscode-icons" + ] + } + }, + + // RStudio ports + "forwardPorts": [8787], + "portsAttributes": { + "8787": { + "label": "Rstudio", + "requireLocalPort": true, + "onAutoForward": "openBrowser" + } + }, + // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root + "remoteUser": "rstudio" +} diff --git a/.devcontainer/postCreateCommand.sh b/.devcontainer/postCreateCommand.sh new file mode 100644 index 00000000..9b9db23a --- /dev/null +++ b/.devcontainer/postCreateCommand.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +R -q -e 'renv::restore(lockfile = file.path("renv", "profiles", paste(R.version$major, substr(R.version$minor, 1, 1), sep = "."), "renv.lock")); staged.dependencies::install_deps(staged.dependencies::dependency_table(project = ".", verbose = 1), verbose = 1);' + +jq --arg folder "$(pwd)/" '. + { "initial_working_directory": $folder }' .devcontainer/rstudio-prefs.json > ~/.config/rstudio/rstudio-prefs.json diff --git a/.devcontainer/rstudio-prefs.json b/.devcontainer/rstudio-prefs.json new file mode 100644 index 00000000..2d5cce84 --- /dev/null +++ b/.devcontainer/rstudio-prefs.json @@ -0,0 +1,8 @@ +{ + "save_workspace": "never", + "always_save_history": false, + "reuse_sessions_for_project_links": true, + "posix_terminal_shell": "bash", + "initial_working_directory": "/workspaces", + "show_hidden_files": true +} diff --git a/DESCRIPTION b/DESCRIPTION index 9a9ad929..75ca24ca 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,19 +1,20 @@ Package: admiraldev Type: Package Title: Utility Functions and Development Tools for the Admiral Package Family -Version: 0.4.0 +Version: 0.5.0 Authors@R: c( person("Ben", "Straub", email = "ben.x.straub@gsk.com", role = c("aut", "cre")), person("Stefan", "Bundfuss", role = "aut"), - person("Thomas", "Neitmann", role = "aut"), - person("Samia", "Kabi", role = "aut"), - person("Pooja", "Kumari", role = "aut"), - person("Syed", "Mubasheer", role = "aut"), + person("Jeffrey", "Dickinson", role = "aut"), person("Ross", "Farrugia", role = "aut"), + person("Pooja", "Kumari", role = "aut"), + person("Edoardo", "Mancini", role = "aut"), person("Sadchla", "Mascary", role = "aut"), person("Zelos", "Zhu", role = "aut"), - person("Jeffrey", "Dickinson", role = "aut"), - person("Ania", "Golab", role = "aut"), + person("Ania", "Golab", role = "ctb"), + person("Samia", "Kabi", role = "ctb"), + person("Syed", "Mubasheer", role = "ctb"), + person("Thomas", "Neitmann", role = "ctb"), person("Ondrej", "Slama", role = "ctb"), person("F. Hoffmann-La Roche AG", role = c("cph", "fnd")), person("GlaxoSmithKline LLC", role = c("cph", "fnd")) @@ -42,7 +43,7 @@ Imports: tidyr (>= 1.0.2), tidyselect (>= 1.0.0) Suggests: - admiral.test, + pharmaversesdtm, devtools, diffdf, lintr, diff --git a/NAMESPACE b/NAMESPACE index 4b57dd79..a8eabf60 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -43,6 +43,7 @@ export(expect_dfs_equal) export(expr_c) export(extract_vars) export(filter_if) +export(friendly_type_of) export(get_constant_vars) export(get_dataset) export(get_duplicates) @@ -55,11 +56,8 @@ export(is_order_vars) export(is_valid_dtc) export(left_join) export(process_set_values_to) -export(quo_c) -export(quo_not_missing) export(remove_tmp_vars) export(replace_symbol_in_expr) -export(replace_symbol_in_quo) export(replace_values_by_names) export(squote) export(suppress_warning) diff --git a/NEWS.md b/NEWS.md index b3ec78a8..aba0ce6b 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,42 @@ +# admiraldev 0.5.0 + +## New Features + +- Calls for `admiral.test` have been swapped with `pharmaversesdtm` (#321) +- New vignette for package writing extensions is now available (#295, #312) +- New vignette for creating test data is now available (#282) + +## Updates of Existing Functions + +- The messaging for `warn_if_invalid_dtc()` was updated to align with what the date/datetime functions in `admiral` currently do. (#316) + +## Breaking Changes + +- The following functions/arguments have been deprecated from previous admiral versions using the next phase of the deprecation process: (#288) + - `assert_order_vars()` + - `quo_c()` + - `quo_not_missing()` + - `replace_symbol_in_quo()` + - The `quosures` argument was replaced by the `expressions` argument in `replace_values_by_names()`, `get_source_vars()`, and `vars2chr()`. (#288) +- `assert_function_param()` was deprecated in favor of `assert_function()`. (#264) +- `assert_named_expr()` was deprecated in favor of `assert_expr_list()`. (#264) +- `assert_has_variables()` was deprecated in favor of `assert_data_frame()`. (#264) + +## Documentation + +- Guidance around issues and merging updated (#286) +- Common R CMD troubleshooting made into separate vignette (#286) +- Documentation of `get_dataset()` was improved. (#271) +- Minor updates to programming strategy were added (#213, #240, #260) +- Updated unit testing vignette with snapshot testing guidance. (#302) +- Documentation of `friendly_type_of()` was provided (#22) +- Minor updates to pull request review guidance were added (#201, #292) +- Documentation of singular versus plural function argument names was added into the programming strategy vignette. Also documentation on the common arguments `missing_value` and `missing_values` was added. (#296) +- Documentation highlighting the difference between `set_values_to` and `keep_source_vars` (#318) +- List of common arguments was updated (#306) + +## Various + # admiraldev 0.4.0 ## New Features diff --git a/R/assertions.R b/R/assertions.R index 9f83cc95..fe5078c1 100644 --- a/R/assertions.R +++ b/R/assertions.R @@ -21,18 +21,18 @@ #' @family assertion #' #' @examples -#' library(admiral.test) +#' library(pharmaversesdtm) #' library(dplyr, warn.conflicts = FALSE) #' library(rlang) -#' data(admiral_dm) +#' data(dm) #' #' example_fun <- function(dataset) { #' assert_data_frame(dataset, required_vars = exprs(STUDYID, USUBJID)) #' } #' -#' example_fun(admiral_dm) +#' example_fun(dm) #' -#' try(example_fun(select(admiral_dm, -STUDYID))) +#' try(example_fun(select(dm, -STUDYID))) #' #' try(example_fun("Not a dataset")) assert_data_frame <- function(arg, @@ -332,23 +332,23 @@ assert_logical_scalar <- function(arg, optional = FALSE) { #' @keywords assertion #' @family assertion #' @examples -#' library(admiral.test) +#' library(pharmaversesdtm) #' library(dplyr, warn.conflicts = FALSE) #' library(rlang) -#' data(admiral_dm) +#' data(dm) #' #' example_fun <- function(dat, var) { #' var <- assert_symbol(enexpr(var)) #' select(dat, !!var) #' } #' -#' example_fun(admiral_dm, USUBJID) +#' example_fun(dm, USUBJID) #' -#' try(example_fun(admiral_dm)) +#' try(example_fun(dm)) #' -#' try(example_fun(admiral_dm, "USUBJID")) +#' try(example_fun(dm, "USUBJID")) #' -#' try(example_fun(admiral_dm, toupper(PARAMCD))) +#' try(example_fun(dm, toupper(PARAMCD))) assert_symbol <- function(arg, optional = FALSE) { assert_logical_scalar(optional) @@ -424,10 +424,10 @@ assert_expr <- function(arg, optional = FALSE) { #' @family assertion #' #' @examples -#' library(admiral.test) +#' library(pharmaversesdtm) #' library(dplyr, warn.conflicts = FALSE) #' library(rlang) -#' data(admiral_dm) +#' data(dm) #' #' # typical usage in a function as an argument check #' example_fun <- function(dat, x) { @@ -435,9 +435,9 @@ assert_expr <- function(arg, optional = FALSE) { #' filter(dat, !!x) #' } #' -#' example_fun(admiral_dm, AGE == 64) +#' example_fun(dm, AGE == 64) #' -#' try(example_fun(admiral_dm, USUBJID)) +#' try(example_fun(dm, USUBJID)) assert_filter_cond <- function(arg, optional = FALSE) { assert_logical_scalar(optional) @@ -545,9 +545,7 @@ assert_vars <- function(arg, expect_names = FALSE, optional = FALSE) { assert_order_vars <- function(arg, optional = FALSE) { assert_logical_scalar(optional) - deprecate_warn("0.4.0", "assert_order_vars()", "assert_expr_list()") - - assert_expr_list(arg, optional = optional) + deprecate_stop("0.4.0", "assert_order_vars()", "assert_expr_list()") } #' Is an Argument an Integer Scalar? @@ -871,10 +869,15 @@ assert_named <- function(arg, optional = FALSE) { #' Assert Argument is a Named List of Expressions #' +#' @description +#' `r lifecycle::badge("deprecated")` +#' +#' This function is *deprecated*, please use `assert_expr_list()` instead. +#' #' @inheritParams assert_data_frame #' -#' @keywords assertion -#' @family assertion +#' @keywords deprecated +#' @family deprecated #' #' @return #' The function throws an error if `arg` is not a named `list` of expression or @@ -882,30 +885,19 @@ assert_named <- function(arg, optional = FALSE) { #' #' @export assert_named_exprs <- function(arg, optional = FALSE) { - assert_logical_scalar(optional) - - if (optional && is.null(arg)) { - return(invisible(arg)) - } - - if (!is.list(arg) || - !all(map_lgl(arg, ~ is.language(.x) | is.logical(.x))) || - any(names(arg) == "")) { - err_msg <- sprintf( - "`%s` must be a named list of expressions created using `rlang::exprs()` but is %s", - arg_name(substitute(arg)), - what_is_it(arg) - ) - abort(err_msg) - } - - invisible(arg) + deprecate_warn("0.5.0", "assert_named_exprs()", "assert_expr_list()", always = TRUE) + assert_expr_list(arg = arg, named = TRUE) } #' Does a Dataset Contain All Required Variables? #' #' Checks if a dataset contains all required variables #' +#' @description +#' `r lifecycle::badge("deprecated")` +#' +#' This function is *deprecated*, please use `assert_data_frame()` instead. +#' #' @param dataset A `data.frame` #' @param required_vars A `character` vector of variable names #' @@ -915,31 +907,17 @@ assert_named_exprs <- function(arg, optional = FALSE) { #' #' @export #' -#' @keywords assertion -#' @family assertion -#' @examples -#' library(admiral.test) -#' data(admiral_dm) -#' -#' assert_has_variables(admiral_dm, "STUDYID") -#' -#' try(assert_has_variables(admiral_dm, "AVAL")) +#' @keywords deprecated +#' @family deprecated assert_has_variables <- function(dataset, required_vars) { - is_missing <- !required_vars %in% colnames(dataset) - if (any(is_missing)) { - missing_vars <- required_vars[is_missing] - if (length(missing_vars) == 1L) { - err_msg <- paste0("Required variable `", missing_vars, "` is missing.") - } else { - err_msg <- paste0( - "Required variables ", - enumerate(missing_vars), - " are missing." - ) - } - abort(err_msg) - } - invisible(dataset) + deprecate_warn("0.5.0", "assert_has_variables()", "assert_data_frame()") + assert_data_frame( + arg = dataset, + required_vars = set_names( + exprs(!!!syms(required_vars)), + names(required_vars) + ) + ) } #' Is Argument a Function? @@ -947,6 +925,11 @@ assert_has_variables <- function(dataset, required_vars) { #' Checks if the argument is a function and if all expected arguments are #' provided by the function. #' +#' @description +#' `r lifecycle::badge("deprecated")` +#' +#' This function is *deprecated*, please use `assert_function_param()` instead. +#' #' @param arg A function argument to be checked #' #' @param params A character vector of expected argument names @@ -965,8 +948,8 @@ assert_has_variables <- function(dataset, required_vars) { #' #' @export #' -#' @keywords assertion -#' @family assertion +#' @keywords deprecated +#' @family deprecated #' @examples #' example_fun <- function(fun) { #' assert_function(fun, params = c("x")) @@ -1029,32 +1012,9 @@ assert_function <- function(arg, params = NULL, optional = FALSE) { #' the function given by `arg` #' #' @export -#' -#' @examples -#' hello <- function(name) { -#' print(sprintf("Hello %s", name)) -#' } -#' -#' assert_function_param("hello", "name") -#' -#' try(assert_function_param("hello", "surname")) assert_function_param <- function(arg, params) { - assert_character_scalar(arg) - assert_character_vector(params) - fun <- match.fun(arg) - - is_param <- params %in% names(formals(fun)) - if (!all(is_param)) { - txt <- if (sum(!is_param) == 1L) { - "%s is not an argument of `%s()`" - } else { - "%s are not arguments of `%s()`" - } - err_msg <- sprintf(txt, enumerate(params[!is_param]), arg) - abort(err_msg) - } - - invisible(arg) + deprecate_warn("0.5.0", "assert_function_param()", "assert_function()", always = TRUE) + assert_function(arg = arg, params = params) } #' Asserts That a Parameter is Provided in the Expected Unit diff --git a/R/compat_friendly_type.R b/R/compat_friendly_type.R index 5897a04b..01ef4ad4 100644 --- a/R/compat_friendly_type.R +++ b/R/compat_friendly_type.R @@ -1,10 +1,21 @@ -#' Return English-friendly Type +#' Return English-friendly messaging for object-types +#' #' @param x Any R object. #' @param value Whether to describe the value of `x`. #' @param length Whether to mention the length of vectors and lists. +#' +#' @details This helper function aids us in forming user-friendly messages that gets +#' called through `what_is_it()`, which is often used in the assertion functions +#' to identify what object-type the user passed through an argument instead of +#' an expected-type. +#' +#' @export +#' #' @return A string describing the type. Starts with an indefinite #' article, e.g. "an integer vector". -#' @noRd +#' +#' @keywords dev_utility +#' @family dev_utility friendly_type_of <- function(x, value = TRUE, length = FALSE) { # nolint if (rlang::is_missing(x)) { return("absent") @@ -70,6 +81,7 @@ friendly_type_of <- function(x, value = TRUE, length = FALSE) { # nolint type } +# Used in building `friendly_type_of()` above .rlang_as_friendly_vector_type <- function(type, n_dim) { if (type == "list") { if (n_dim < 2) { @@ -102,6 +114,7 @@ friendly_type_of <- function(x, value = TRUE, length = FALSE) { # nolint sprintf(type, kind) } +# Used in building `friendly_type_of()` above .rlang_as_friendly_type <- function(type) { switch(type, list = "a list", @@ -128,6 +141,7 @@ friendly_type_of <- function(x, value = TRUE, length = FALSE) { # nolint ) } +# Used in building `friendly_type_of()` above .rlang_stop_unexpected_typeof <- function(x, call = rlang::caller_env()) { rlang::abort( sprintf("Unexpected type <%s>.", typeof(x)), diff --git a/R/datasets.R b/R/datasets.R deleted file mode 100644 index 8f46033b..00000000 --- a/R/datasets.R +++ /dev/null @@ -1,16 +0,0 @@ -#' Retrieve a Dataset from the `admiraldev_environment` environment -#' -#' @param name The name of the dataset to retrieve -#' -#' @return A `data.frame` -#' -#' -#' @keywords datasets -#' @family datasets -#' -#' @export -get_dataset <- function(name) { - assert_character_scalar(name, values = c("one_to_many", "many_to_one")) - - admiraldev_environment[[name]] -} diff --git a/R/dev_utilities.R b/R/dev_utilities.R index 4d37a178..fb540c79 100644 --- a/R/dev_utilities.R +++ b/R/dev_utilities.R @@ -162,12 +162,11 @@ contains_vars <- function(arg) { #' vars2chr(exprs(USUBJID, AVAL)) vars2chr <- function(expressions, quosures) { if (!missing(quosures)) { - deprecate_warn( + deprecate_stop( "0.10.0", "vars2chr(quosures = )", "vars2chr(expressions = )" ) - expressions <- map(quosures, rlang::quo_get_expr) } rlang::set_names( map_chr(expressions, as_string), diff --git a/R/get.R b/R/get.R index 2018ce99..c209a564 100644 --- a/R/get.R +++ b/R/get.R @@ -86,12 +86,11 @@ get_duplicates <- function(x) { #' @export get_source_vars <- function(expressions, quosures) { if (!missing(quosures)) { - deprecate_warn( + deprecate_stop( "0.10.0", "get_source_vars(quosures = )", "get_source_vars(expressions = )" ) - expressions <- map(quosures, rlang::quo_get_expr) } assert_varval_list(expressions, optional = TRUE) @@ -103,3 +102,39 @@ get_source_vars <- function(expressions, quosures) { source_vars } } +#' Retrieve a Dataset from the `admiraldev_environment` environment +#' +#' @details +#' +#' Sometimes, developers may want to provide information to users which does not fit into a +#' warning or error message. For example, if the input dataset of a function contains unexpected +#' records, these can be stored in a separate dataset, which users can access to investigate +#' the issue. +#' +#' To achieve this, R has a data structure known as an 'environment'. These environment objects +#' are created at build time, but can be populated with values after the package has been loaded +#' and update those values over the course of an R session. +#' +#' As so, the establishment of `admiraldev_environment` allows us to create dynamic data/objects +#' based on user-inputs that need modification. The purpose of `get_dataset` is to +#' retrieve the datasets contained inside `admiraldev_environment`. +#' +#' Currently we only support two datasets inside our `admiraldev_environment` object: +#' - `one_to_many` +#' - `many_to_one` +#' +#' +#' @param name The name of the dataset to retrieve +#' +#' @return A `data.frame` +#' +#' +#' @keywords get +#' @family get +#' +#' @export +get_dataset <- function(name) { + assert_character_scalar(name, values = c("one_to_many", "many_to_one")) + + admiraldev_environment[[name]] +} diff --git a/R/quo.R b/R/quo.R index a5870a6f..10fccb9f 100644 --- a/R/quo.R +++ b/R/quo.R @@ -1,30 +1,3 @@ -#' Concatenate One or More Quosure(s) -#' -#' `r lifecycle::badge("deprecated")` -#' -#' This function is *deprecated*, please use `expr_c()` instead. -#' -#' @param ... One or more objects of class `quosure` or `quosures` -#' -#' @return An object of class `quosures` -#' -#' -#' @keywords deprecated -#' @family deprecated -#' -#' @export -quo_c <- function(...) { - deprecate_stop( - "0.3.0", - "quo_c()", - "expr_c()", - details = paste( - "Expressions created by `exprs()` must be used", - "instead of quosures created by `vars()`." - ) - ) -} - #' Concatenate One or More Expressions #' #' @param ... One or more expressions or list of expressions @@ -53,30 +26,6 @@ expr_c <- function(...) { inputs[!is_null] } -#' Check Whether an Argument Is Not a Quosure of a Missing Argument -#' -#' @param x Test object -#' -#' @return TRUE or error. -#' -#' -#' @keywords deprecated -#' @family deprecated -#' -#' @export -quo_not_missing <- function(x) { - deprecate_stop( - "0.3.0", - "quo_not_missing()", - details = paste( - "Due to changing from `vars()` to `exprs()` the function is no longer required.", - "It will be removed in future.", - sep = "\n" - ) - ) -} - - #' Replace Expression Value with Name #' #' @param expressions A list of expressions @@ -101,7 +50,6 @@ replace_values_by_names <- function(expressions, quosures) { "replace_values_by_names(quosures = )", "replace_values_by_names(expressions = )" ) - expressions <- map(quosures, rlang::quo_get_expr) } if (is.null(names(expressions))) { return(expressions) @@ -114,40 +62,6 @@ replace_values_by_names <- function(expressions, quosures) { }) } -#' Replace Symbols in a Quosure -#' -#' `r lifecycle::badge("deprecated")` -#' -#' This function is *deprecated*, please use `replace_symbol_in_expr()` instead. -#' -#' @param quosure Quosure -#' -#' @param target Target symbol -#' -#' @param replace Replacing symbol -#' -#' -#' @return The quosure where every occurrence of the symbol `target` is replaced -#' by `replace` -#' -#' @keywords deprecated -#' @family deprecated -#' -#' @export -replace_symbol_in_quo <- function(quosure, - target, - replace) { - deprecate_stop( - "0.3.0", - "replace_symbol_in_quo()", - "replace_symbol_in_expr()", - details = paste( - "Expressions created by `exprs()` must be used", - "instead of quosures created by `vars()`." - ) - ) -} - #' Replace Symbols in an Expression #' #' Replace symbols in an expression diff --git a/R/tmp_vars.R b/R/tmp_vars.R index 72deb84a..5dc20ca4 100644 --- a/R/tmp_vars.R +++ b/R/tmp_vars.R @@ -19,11 +19,11 @@ #' #' @examples #' library(dplyr, warn.conflicts = FALSE) -#' library(admiral.test) -#' data(admiral_dm) +#' library(pharmaversesdtm) +#' data(dm) #' -#' tmp_var <- get_new_tmp_var(admiral_dm) -#' mutate(admiral_dm, !!tmp_var := NA) +#' tmp_var <- get_new_tmp_var(dm) +#' mutate(dm, !!tmp_var := NA) get_new_tmp_var <- function(dataset, prefix = "tmp_var") { assert_data_frame(dataset, optional = TRUE) assert_character_scalar(prefix) @@ -69,9 +69,9 @@ get_new_tmp_var <- function(dataset, prefix = "tmp_var") { #' #' @examples #' library(dplyr, warn.conflicts = FALSE) -#' library(admiral.test) -#' data(admiral_dm) -#' dm <- select(admiral_dm, USUBJID) +#' library(pharmaversesdtm) +#' data(dm) +#' dm <- select(dm, USUBJID) #' tmp_var <- get_new_tmp_var(dm) #' dm <- mutate(dm, !!tmp_var := NA) #' diff --git a/R/warnings.R b/R/warnings.R index 8f6f3799..dc0cb069 100644 --- a/R/warnings.R +++ b/R/warnings.R @@ -14,14 +14,14 @@ #' @export #' #' @examples -#' library(admiral.test) -#' data(admiral_dm) +#' library(pharmaversesdtm) +#' data(dm) #' #' ## No warning as `AAGE` doesn't exist in `dm` -#' warn_if_vars_exist(admiral_dm, "AAGE") +#' warn_if_vars_exist(dm, "AAGE") #' #' ## Issues a warning -#' warn_if_vars_exist(admiral_dm, "ARM") +#' warn_if_vars_exist(dm, "ARM") warn_if_vars_exist <- function(dataset, vars) { existing_vars <- vars[vars %in% colnames(dataset)] if (length(existing_vars) == 1L) { @@ -69,20 +69,10 @@ warn_if_invalid_dtc <- function(dtc, is_valid = is_valid_dtc(dtc)) { ) info <- paste0( - "The following ISO representations are handled: \n", - "2003-12-15T13:15:17.123\n", - "2003-12-15T13:15:17\n", - "2003-12-15T13:15\n", - "2003-12-15T13\n", - "2003-12-15\n", - "2003-12\n", - "2003\n", - "2003---15\n\n", - "The following ISO representations, and any other representation are NOT handled: \n", - "2003-12-15T-:15:18\n", - "2003-12-15T13:-:19\n", - "--12-15\n", - "-----T07:15" + "ISO representations of the form YYYY-MM-DDThh:mm:ss.ddd are expected, ", + "e.g., 2003-12-15T13:15:17.123. Missing parts at the end can be omitted. ", + "Missing parts in the middle must be represented by a dash, e.g., 2003---15.", + sep = "\n" ) warn(paste(main_msg, tbl, info, sep = "\n")) } diff --git a/README.Rmd b/README.Rmd index 0a3dc4c0..2e52a8f3 100644 --- a/README.Rmd +++ b/README.Rmd @@ -44,7 +44,7 @@ Utility Functions and Development Tools for the Admiral Package Family ## Purpose -Functions and Tools for developing core `{admiral}` functions. Most functions in `{admiraldev}` are around testing inputs going into `{admiral}` functions. There are also additional quality of life functions/Addins to assist developers of `{admiral}` or `{admiral}` extension packages as well as functions to help with rendering documentation. +Functions, tools and documentation for developing core `{admiral}` and extension package functions. Most functions in `{admiraldev}` are around testing inputs going into functions. There are also additional quality of life functions/Addins to assist developers of `{admiral}` or `{admiral}` extension packages, functions to help with rendering documentation, Developer Guides on developing function and using GitHub, GitHub Actions. **NOTE:** This package is not intended for standalone use but rather as a central dependency for `{admiral}` and its extension packages @@ -59,9 +59,9 @@ if (!requireNamespace("remotes", quietly = TRUE)) { install.packages("remotes") } -remotes::install_github("pharmaverse/admiraldev", ref = "devel") +remotes::install_github("pharmaverse/admiraldev") ``` ## Release Schedule -`{admiraldev}` is to be officially released to CRAN one week before an official release of `{admiral}`. You can find the release schedule for `{admiral}` packages [here](https://pharmaverse.github.io/admiral/#release-schedule). +`{admiraldev}` is to be released to CRAN at the same time as an official release of `{admiral}`. You can find the release schedule for `{admiral}` packages [here](https://pharmaverse.github.io/admiral/#release-schedule). diff --git a/README.md b/README.md index d4566c2a..6947d593 100644 --- a/README.md +++ b/README.md @@ -6,18 +6,24 @@ Utility Functions and Development Tools for the Admiral Package Family +[![CRAN +status](https://www.r-pkg.org/badges/version/admiraldev)](https://CRAN.R-project.org/package=admiraldev) +[![Test +Coverage](https://raw.githubusercontent.com/pharmaverse/admiraldev/badges/main/test-coverage.svg)](https://github.com/pharmaverse/admiraldev/actions/workflows/common.yml) + ## Purpose -Functions and Tools for developing core `{admiral}` functions. Most -functions in `{admiraldev}` are around testing inputs going into -`{admiral}` functions. There are also additional quality of life -functions/Addins to assist developers of `{admiral}` or `{admiral}` -extension packages as well as functions to help with rendering -documentation. +Functions, tools and documentation for developing core `{admiral}` and +extension package functions. Most functions in `{admiraldev}` are around +testing inputs going into functions. There are also additional quality +of life functions/Addins to assist developers of `{admiral}` or +`{admiral}` extension packages, functions to help with rendering +documentation, Developer Guides on developing function and using GitHub, +GitHub Actions. -__NOTE:__ This package is not intended for standalone use but rather as +**NOTE:** This package is not intended for standalone use but rather as a central dependency for `{admiral}` and its extension packages ## Installation @@ -28,17 +34,15 @@ The package is available from CRAN and can be installed by running To install the latest development version of the package directly from GitHub use the following code: -``` -if (!requireNamespace("remotes", quietly = TRUE)) { - install.packages("remotes") -} + if (!requireNamespace("remotes", quietly = TRUE)) { + install.packages("remotes") + } -remotes::install_github("pharmaverse/admiraldev", ref = "devel") -``` + remotes::install_github("pharmaverse/admiraldev") ## Release Schedule -`{admiraldev}` is to be officially released to CRAN one week before an -official release of `{admiral}`. You can find the release schedule for +`{admiraldev}` is to be released to CRAN at the same time as an official +release of `{admiral}`. You can find the release schedule for `{admiral}` packages [here](https://pharmaverse.github.io/admiral/#release-schedule). diff --git a/_pkgdown.yml b/_pkgdown.yml index 22293eab..1a58d169 100644 --- a/_pkgdown.yml +++ b/_pkgdown.yml @@ -1,4 +1,4 @@ -url: https://pharmaverse.github.io/admiraldev/devel +url: https://pharmaverse.github.io/admiraldev template: bootstrap: 5 @@ -13,6 +13,14 @@ repo: news: cran_dates: true +authors: + before: "We define *authors* as those who are actively maintaining the code base, and *contributors* as those who made a significant contribution in the past." + footer: + roles: [aut, ctb, cre, fnd] + text: "Developed by" + sidebar: + roles: [aut] + reference: - title: Assertion Functions desc: Checks the inputs for user-facing functions and provides error, warnings and other messaging around expectation of inputs. @@ -112,5 +120,11 @@ navbar: href: articles/git_usage.html - text: Pull Request Review Guidance href: articles/pr_review_guidance.html + - text: R CMD Issues + href: articles/rcmd_issues.html - text: Release Strategy href: articles/release_strategy.html + - text: Test Data Guidance + href: articles/test_data_guidance.html + - text: Package Extensions + href: articles/package_extensions.html diff --git a/docs/pkgdown.yml b/docs/pkgdown.yml index 4e7f8407..2d59f98d 100644 --- a/docs/pkgdown.yml +++ b/docs/pkgdown.yml @@ -1,16 +1,19 @@ -pandoc: 2.11.4 +pandoc: 2.19.2 pkgdown: 2.0.7 pkgdown_sha: ~ articles: admiraldev: admiraldev.html development_process: development_process.html git_usage: git_usage.html + package_extensions: package_extensions.html pr_review_guidance: pr_review_guidance.html programming_strategy: programming_strategy.html + rcmd_issues: rcmd_issues.html release_strategy: release_strategy.html + test_data_guidance: test_data_guidance.html unit_test_guidance: unit_test_guidance.html writing_vignettes: writing_vignettes.html -last_built: 2023-04-12T17:21Z +last_built: 2023-08-24T20:45Z urls: reference: https://pharmaverse.github.io/admiraldev/devel/reference article: https://pharmaverse.github.io/admiraldev/devel/articles diff --git a/inst/WORDLIST b/inst/WORDLIST index 100c7409..cfed9f97 100644 --- a/inst/WORDLIST +++ b/inst/WORDLIST @@ -1,20 +1,26 @@ ADSL ADT +ADVS ADaM ADaMs AEs Addin Addins +Arancibia BDS +BMI CDISC CMD Changelog Codebase +Codeowners Cyclomatic +DM DTC Datetime Github GlaxoSmithKline +GSK Hoffmann IG LLC @@ -24,8 +30,12 @@ OCCDS PRs Pandoc Pharma +Pharmaverse Quosure Quosures +PHUSE +README +Rimler ROxygen RStudio Roxygen @@ -40,8 +50,13 @@ addin adex adlb admiralci +admiraltemplate +admiralxxx advs +anonymized +cmd codebase +codeowner cyclomatic datatable datetime @@ -56,19 +71,19 @@ flexibilities functions’ funder github -hotfixes hotfix +hotfixes insightsengineering -lifecycle linter lintr lockfile occds +onboarding optionality +pharmaverse pkgs pre proc -quosure quosures repo reproducibility diff --git a/inst/templates/ad_adxx.R b/inst/templates/ad_adxx.R index d97bb9d5..297c40d2 100644 --- a/inst/templates/ad_adxx.R +++ b/inst/templates/ad_adxx.R @@ -4,6 +4,6 @@ # # Input: xx, xx, xx library(admiral) -library(admiral.test) # Contains example datasets from the CDISC pilot project +library(pharmaversesdtm) # Contains example datasets from the CDISC pilot project # Add your template ADaM script code diff --git a/man/admiraldev-package.Rd b/man/admiraldev-package.Rd index 912f544d..324f6539 100644 --- a/man/admiraldev-package.Rd +++ b/man/admiraldev-package.Rd @@ -25,19 +25,20 @@ Useful links: Authors: \itemize{ \item Stefan Bundfuss - \item Thomas Neitmann - \item Samia Kabi - \item Pooja Kumari - \item Syed Mubasheer + \item Jeffrey Dickinson \item Ross Farrugia + \item Pooja Kumari + \item Edoardo Mancini \item Sadchla Mascary \item Zelos Zhu - \item Jeffrey Dickinson - \item Ania Golab } Other contributors: \itemize{ + \item Ania Golab [contributor] + \item Samia Kabi [contributor] + \item Syed Mubasheer [contributor] + \item Thomas Neitmann [contributor] \item Ondrej Slama [contributor] \item F. Hoffmann-La Roche AG [copyright holder, funder] \item GlaxoSmithKline LLC [copyright holder, funder] diff --git a/man/arg_name.Rd b/man/arg_name.Rd index 78fd3c79..5282bea0 100644 --- a/man/arg_name.Rd +++ b/man/arg_name.Rd @@ -23,6 +23,7 @@ Developer Utility Functions: \code{\link{convert_dtm_to_dtc}()}, \code{\link{extract_vars}()}, \code{\link{filter_if}()}, +\code{\link{friendly_type_of}()}, \code{\link{valid_time_units}()}, \code{\link{vars2chr}()} } diff --git a/man/assert_atomic_vector.Rd b/man/assert_atomic_vector.Rd index 5314c62e..76fca001 100644 --- a/man/assert_atomic_vector.Rd +++ b/man/assert_atomic_vector.Rd @@ -38,13 +38,10 @@ Checks for valid input and returns warning or errors messages: \code{\link{assert_expr}()}, \code{\link{assert_filter_cond}()}, \code{\link{assert_function_param}()}, -\code{\link{assert_function}()}, -\code{\link{assert_has_variables}()}, \code{\link{assert_integer_scalar}()}, \code{\link{assert_list_element}()}, \code{\link{assert_list_of}()}, \code{\link{assert_logical_scalar}()}, -\code{\link{assert_named_exprs}()}, \code{\link{assert_named}()}, \code{\link{assert_numeric_vector}()}, \code{\link{assert_one_to_one}()}, diff --git a/man/assert_character_scalar.Rd b/man/assert_character_scalar.Rd index a4c8539f..cc0db79c 100644 --- a/man/assert_character_scalar.Rd +++ b/man/assert_character_scalar.Rd @@ -68,13 +68,10 @@ Checks for valid input and returns warning or errors messages: \code{\link{assert_expr}()}, \code{\link{assert_filter_cond}()}, \code{\link{assert_function_param}()}, -\code{\link{assert_function}()}, -\code{\link{assert_has_variables}()}, \code{\link{assert_integer_scalar}()}, \code{\link{assert_list_element}()}, \code{\link{assert_list_of}()}, \code{\link{assert_logical_scalar}()}, -\code{\link{assert_named_exprs}()}, \code{\link{assert_named}()}, \code{\link{assert_numeric_vector}()}, \code{\link{assert_one_to_one}()}, diff --git a/man/assert_character_vector.Rd b/man/assert_character_vector.Rd index 08e20d99..0e114558 100644 --- a/man/assert_character_vector.Rd +++ b/man/assert_character_vector.Rd @@ -50,13 +50,10 @@ Checks for valid input and returns warning or errors messages: \code{\link{assert_expr}()}, \code{\link{assert_filter_cond}()}, \code{\link{assert_function_param}()}, -\code{\link{assert_function}()}, -\code{\link{assert_has_variables}()}, \code{\link{assert_integer_scalar}()}, \code{\link{assert_list_element}()}, \code{\link{assert_list_of}()}, \code{\link{assert_logical_scalar}()}, -\code{\link{assert_named_exprs}()}, \code{\link{assert_named}()}, \code{\link{assert_numeric_vector}()}, \code{\link{assert_one_to_one}()}, diff --git a/man/assert_data_frame.Rd b/man/assert_data_frame.Rd index 0b2a8c7d..6fad9c54 100644 --- a/man/assert_data_frame.Rd +++ b/man/assert_data_frame.Rd @@ -31,18 +31,18 @@ Checks if an argument is a data frame and (optionally) whether is contains a set of required variables } \examples{ -library(admiral.test) +library(pharmaversesdtm) library(dplyr, warn.conflicts = FALSE) library(rlang) -data(admiral_dm) +data(dm) example_fun <- function(dataset) { assert_data_frame(dataset, required_vars = exprs(STUDYID, USUBJID)) } -example_fun(admiral_dm) +example_fun(dm) -try(example_fun(select(admiral_dm, -STUDYID))) +try(example_fun(select(dm, -STUDYID))) try(example_fun("Not a dataset")) } @@ -56,13 +56,10 @@ Checks for valid input and returns warning or errors messages: \code{\link{assert_expr}()}, \code{\link{assert_filter_cond}()}, \code{\link{assert_function_param}()}, -\code{\link{assert_function}()}, -\code{\link{assert_has_variables}()}, \code{\link{assert_integer_scalar}()}, \code{\link{assert_list_element}()}, \code{\link{assert_list_of}()}, \code{\link{assert_logical_scalar}()}, -\code{\link{assert_named_exprs}()}, \code{\link{assert_named}()}, \code{\link{assert_numeric_vector}()}, \code{\link{assert_one_to_one}()}, diff --git a/man/assert_date_vector.Rd b/man/assert_date_vector.Rd index e9f1e2a9..7aee4078 100644 --- a/man/assert_date_vector.Rd +++ b/man/assert_date_vector.Rd @@ -39,13 +39,10 @@ Checks for valid input and returns warning or errors messages: \code{\link{assert_expr}()}, \code{\link{assert_filter_cond}()}, \code{\link{assert_function_param}()}, -\code{\link{assert_function}()}, -\code{\link{assert_has_variables}()}, \code{\link{assert_integer_scalar}()}, \code{\link{assert_list_element}()}, \code{\link{assert_list_of}()}, \code{\link{assert_logical_scalar}()}, -\code{\link{assert_named_exprs}()}, \code{\link{assert_named}()}, \code{\link{assert_numeric_vector}()}, \code{\link{assert_one_to_one}()}, diff --git a/man/assert_expr.Rd b/man/assert_expr.Rd index aaa51970..579b6cd4 100644 --- a/man/assert_expr.Rd +++ b/man/assert_expr.Rd @@ -29,13 +29,10 @@ Checks for valid input and returns warning or errors messages: \code{\link{assert_expr_list}()}, \code{\link{assert_filter_cond}()}, \code{\link{assert_function_param}()}, -\code{\link{assert_function}()}, -\code{\link{assert_has_variables}()}, \code{\link{assert_integer_scalar}()}, \code{\link{assert_list_element}()}, \code{\link{assert_list_of}()}, \code{\link{assert_logical_scalar}()}, -\code{\link{assert_named_exprs}()}, \code{\link{assert_named}()}, \code{\link{assert_numeric_vector}()}, \code{\link{assert_one_to_one}()}, diff --git a/man/assert_expr_list.Rd b/man/assert_expr_list.Rd index 790f8ec6..effb5d5d 100644 --- a/man/assert_expr_list.Rd +++ b/man/assert_expr_list.Rd @@ -49,13 +49,10 @@ Checks for valid input and returns warning or errors messages: \code{\link{assert_expr}()}, \code{\link{assert_filter_cond}()}, \code{\link{assert_function_param}()}, -\code{\link{assert_function}()}, -\code{\link{assert_has_variables}()}, \code{\link{assert_integer_scalar}()}, \code{\link{assert_list_element}()}, \code{\link{assert_list_of}()}, \code{\link{assert_logical_scalar}()}, -\code{\link{assert_named_exprs}()}, \code{\link{assert_named}()}, \code{\link{assert_numeric_vector}()}, \code{\link{assert_one_to_one}()}, diff --git a/man/assert_filter_cond.Rd b/man/assert_filter_cond.Rd index 797cb61c..8971e970 100644 --- a/man/assert_filter_cond.Rd +++ b/man/assert_filter_cond.Rd @@ -23,10 +23,10 @@ Check if \code{arg} is a suitable filtering condition to be used in functions like \code{subset} or \code{dplyr::filter}. } \examples{ -library(admiral.test) +library(pharmaversesdtm) library(dplyr, warn.conflicts = FALSE) library(rlang) -data(admiral_dm) +data(dm) # typical usage in a function as an argument check example_fun <- function(dat, x) { @@ -34,9 +34,9 @@ example_fun <- function(dat, x) { filter(dat, !!x) } -example_fun(admiral_dm, AGE == 64) +example_fun(dm, AGE == 64) -try(example_fun(admiral_dm, USUBJID)) +try(example_fun(dm, USUBJID)) } \seealso{ Checks for valid input and returns warning or errors messages: @@ -48,13 +48,10 @@ Checks for valid input and returns warning or errors messages: \code{\link{assert_expr_list}()}, \code{\link{assert_expr}()}, \code{\link{assert_function_param}()}, -\code{\link{assert_function}()}, -\code{\link{assert_has_variables}()}, \code{\link{assert_integer_scalar}()}, \code{\link{assert_list_element}()}, \code{\link{assert_list_of}()}, \code{\link{assert_logical_scalar}()}, -\code{\link{assert_named_exprs}()}, \code{\link{assert_named}()}, \code{\link{assert_numeric_vector}()}, \code{\link{assert_one_to_one}()}, diff --git a/man/assert_function.Rd b/man/assert_function.Rd index 728746ff..2f7d09ed 100644 --- a/man/assert_function.Rd +++ b/man/assert_function.Rd @@ -24,6 +24,11 @@ The function throws an error } } \description{ +\ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#deprecated}{\figure{lifecycle-deprecated.svg}{options: alt='[Deprecated]'}}}{\strong{[Deprecated]}} + +This function is \emph{deprecated}, please use \code{assert_function_param()} instead. +} +\details{ Checks if the argument is a function and if all expected arguments are provided by the function. } @@ -39,32 +44,10 @@ try(example_fun(1)) try(example_fun(sum)) } \seealso{ -Checks for valid input and returns warning or errors messages: -\code{\link{assert_atomic_vector}()}, -\code{\link{assert_character_scalar}()}, -\code{\link{assert_character_vector}()}, -\code{\link{assert_data_frame}()}, -\code{\link{assert_date_vector}()}, -\code{\link{assert_expr_list}()}, -\code{\link{assert_expr}()}, -\code{\link{assert_filter_cond}()}, -\code{\link{assert_function_param}()}, +Other deprecated: \code{\link{assert_has_variables}()}, -\code{\link{assert_integer_scalar}()}, -\code{\link{assert_list_element}()}, -\code{\link{assert_list_of}()}, -\code{\link{assert_logical_scalar}()}, \code{\link{assert_named_exprs}()}, -\code{\link{assert_named}()}, -\code{\link{assert_numeric_vector}()}, -\code{\link{assert_one_to_one}()}, -\code{\link{assert_param_does_not_exist}()}, -\code{\link{assert_s3_class}()}, -\code{\link{assert_same_type}()}, -\code{\link{assert_symbol}()}, -\code{\link{assert_unit}()}, -\code{\link{assert_vars}()}, -\code{\link{assert_varval_list}()} +\code{\link{assert_order_vars}()} } -\concept{assertion} -\keyword{assertion} +\concept{deprecated} +\keyword{deprecated} diff --git a/man/assert_function_param.Rd b/man/assert_function_param.Rd index 93a69636..d4a6edbc 100644 --- a/man/assert_function_param.Rd +++ b/man/assert_function_param.Rd @@ -18,15 +18,6 @@ the function given by \code{arg} \description{ Assert Argument is a Parameter of a Function } -\examples{ -hello <- function(name) { - print(sprintf("Hello \%s", name)) -} - -assert_function_param("hello", "name") - -try(assert_function_param("hello", "surname")) -} \seealso{ Checks for valid input and returns warning or errors messages: \code{\link{assert_atomic_vector}()}, @@ -37,13 +28,10 @@ Checks for valid input and returns warning or errors messages: \code{\link{assert_expr_list}()}, \code{\link{assert_expr}()}, \code{\link{assert_filter_cond}()}, -\code{\link{assert_function}()}, -\code{\link{assert_has_variables}()}, \code{\link{assert_integer_scalar}()}, \code{\link{assert_list_element}()}, \code{\link{assert_list_of}()}, \code{\link{assert_logical_scalar}()}, -\code{\link{assert_named_exprs}()}, \code{\link{assert_named}()}, \code{\link{assert_numeric_vector}()}, \code{\link{assert_one_to_one}()}, diff --git a/man/assert_has_variables.Rd b/man/assert_has_variables.Rd index 98fd5c4e..86b8f41c 100644 --- a/man/assert_has_variables.Rd +++ b/man/assert_has_variables.Rd @@ -16,43 +16,18 @@ The function throws an error if any of the required variables are missing in the input dataset. Otherwise, the dataset is returned invisibly. } \description{ -Checks if a dataset contains all required variables -} -\examples{ -library(admiral.test) -data(admiral_dm) - -assert_has_variables(admiral_dm, "STUDYID") +\ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#deprecated}{\figure{lifecycle-deprecated.svg}{options: alt='[Deprecated]'}}}{\strong{[Deprecated]}} -try(assert_has_variables(admiral_dm, "AVAL")) +This function is \emph{deprecated}, please use \code{assert_data_frame()} instead. +} +\details{ +Checks if a dataset contains all required variables } \seealso{ -Checks for valid input and returns warning or errors messages: -\code{\link{assert_atomic_vector}()}, -\code{\link{assert_character_scalar}()}, -\code{\link{assert_character_vector}()}, -\code{\link{assert_data_frame}()}, -\code{\link{assert_date_vector}()}, -\code{\link{assert_expr_list}()}, -\code{\link{assert_expr}()}, -\code{\link{assert_filter_cond}()}, -\code{\link{assert_function_param}()}, +Other deprecated: \code{\link{assert_function}()}, -\code{\link{assert_integer_scalar}()}, -\code{\link{assert_list_element}()}, -\code{\link{assert_list_of}()}, -\code{\link{assert_logical_scalar}()}, \code{\link{assert_named_exprs}()}, -\code{\link{assert_named}()}, -\code{\link{assert_numeric_vector}()}, -\code{\link{assert_one_to_one}()}, -\code{\link{assert_param_does_not_exist}()}, -\code{\link{assert_s3_class}()}, -\code{\link{assert_same_type}()}, -\code{\link{assert_symbol}()}, -\code{\link{assert_unit}()}, -\code{\link{assert_vars}()}, -\code{\link{assert_varval_list}()} +\code{\link{assert_order_vars}()} } -\concept{assertion} -\keyword{assertion} +\concept{deprecated} +\keyword{deprecated} diff --git a/man/assert_integer_scalar.Rd b/man/assert_integer_scalar.Rd index 05d59895..d927a12a 100644 --- a/man/assert_integer_scalar.Rd +++ b/man/assert_integer_scalar.Rd @@ -47,12 +47,9 @@ Checks for valid input and returns warning or errors messages: \code{\link{assert_expr}()}, \code{\link{assert_filter_cond}()}, \code{\link{assert_function_param}()}, -\code{\link{assert_function}()}, -\code{\link{assert_has_variables}()}, \code{\link{assert_list_element}()}, \code{\link{assert_list_of}()}, \code{\link{assert_logical_scalar}()}, -\code{\link{assert_named_exprs}()}, \code{\link{assert_named}()}, \code{\link{assert_numeric_vector}()}, \code{\link{assert_one_to_one}()}, diff --git a/man/assert_list_element.Rd b/man/assert_list_element.Rd index 7167d04b..b8062ebc 100644 --- a/man/assert_list_element.Rd +++ b/man/assert_list_element.Rd @@ -50,12 +50,9 @@ Checks for valid input and returns warning or errors messages: \code{\link{assert_expr}()}, \code{\link{assert_filter_cond}()}, \code{\link{assert_function_param}()}, -\code{\link{assert_function}()}, -\code{\link{assert_has_variables}()}, \code{\link{assert_integer_scalar}()}, \code{\link{assert_list_of}()}, \code{\link{assert_logical_scalar}()}, -\code{\link{assert_named_exprs}()}, \code{\link{assert_named}()}, \code{\link{assert_numeric_vector}()}, \code{\link{assert_one_to_one}()}, diff --git a/man/assert_list_of.Rd b/man/assert_list_of.Rd index 6541616b..ed5092e6 100644 --- a/man/assert_list_of.Rd +++ b/man/assert_list_of.Rd @@ -52,12 +52,9 @@ Checks for valid input and returns warning or errors messages: \code{\link{assert_expr}()}, \code{\link{assert_filter_cond}()}, \code{\link{assert_function_param}()}, -\code{\link{assert_function}()}, -\code{\link{assert_has_variables}()}, \code{\link{assert_integer_scalar}()}, \code{\link{assert_list_element}()}, \code{\link{assert_logical_scalar}()}, -\code{\link{assert_named_exprs}()}, \code{\link{assert_named}()}, \code{\link{assert_numeric_vector}()}, \code{\link{assert_one_to_one}()}, diff --git a/man/assert_logical_scalar.Rd b/man/assert_logical_scalar.Rd index 640fed0f..ece4c6a0 100644 --- a/man/assert_logical_scalar.Rd +++ b/man/assert_logical_scalar.Rd @@ -45,12 +45,9 @@ Checks for valid input and returns warning or errors messages: \code{\link{assert_expr}()}, \code{\link{assert_filter_cond}()}, \code{\link{assert_function_param}()}, -\code{\link{assert_function}()}, -\code{\link{assert_has_variables}()}, \code{\link{assert_integer_scalar}()}, \code{\link{assert_list_element}()}, \code{\link{assert_list_of}()}, -\code{\link{assert_named_exprs}()}, \code{\link{assert_named}()}, \code{\link{assert_numeric_vector}()}, \code{\link{assert_one_to_one}()}, diff --git a/man/assert_named.Rd b/man/assert_named.Rd index 24a486ee..c10b6407 100644 --- a/man/assert_named.Rd +++ b/man/assert_named.Rd @@ -41,13 +41,10 @@ Checks for valid input and returns warning or errors messages: \code{\link{assert_expr}()}, \code{\link{assert_filter_cond}()}, \code{\link{assert_function_param}()}, -\code{\link{assert_function}()}, -\code{\link{assert_has_variables}()}, \code{\link{assert_integer_scalar}()}, \code{\link{assert_list_element}()}, \code{\link{assert_list_of}()}, \code{\link{assert_logical_scalar}()}, -\code{\link{assert_named_exprs}()}, \code{\link{assert_numeric_vector}()}, \code{\link{assert_one_to_one}()}, \code{\link{assert_param_does_not_exist}()}, diff --git a/man/assert_named_exprs.Rd b/man/assert_named_exprs.Rd index e81213a2..70b36399 100644 --- a/man/assert_named_exprs.Rd +++ b/man/assert_named_exprs.Rd @@ -17,35 +17,15 @@ The function throws an error if \code{arg} is not a named \code{list} of express returns the input invisibly otherwise } \description{ -Assert Argument is a Named List of Expressions +\ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#deprecated}{\figure{lifecycle-deprecated.svg}{options: alt='[Deprecated]'}}}{\strong{[Deprecated]}} + +This function is \emph{deprecated}, please use \code{assert_expr_list()} instead. } \seealso{ -Checks for valid input and returns warning or errors messages: -\code{\link{assert_atomic_vector}()}, -\code{\link{assert_character_scalar}()}, -\code{\link{assert_character_vector}()}, -\code{\link{assert_data_frame}()}, -\code{\link{assert_date_vector}()}, -\code{\link{assert_expr_list}()}, -\code{\link{assert_expr}()}, -\code{\link{assert_filter_cond}()}, -\code{\link{assert_function_param}()}, +Other deprecated: \code{\link{assert_function}()}, \code{\link{assert_has_variables}()}, -\code{\link{assert_integer_scalar}()}, -\code{\link{assert_list_element}()}, -\code{\link{assert_list_of}()}, -\code{\link{assert_logical_scalar}()}, -\code{\link{assert_named}()}, -\code{\link{assert_numeric_vector}()}, -\code{\link{assert_one_to_one}()}, -\code{\link{assert_param_does_not_exist}()}, -\code{\link{assert_s3_class}()}, -\code{\link{assert_same_type}()}, -\code{\link{assert_symbol}()}, -\code{\link{assert_unit}()}, -\code{\link{assert_vars}()}, -\code{\link{assert_varval_list}()} +\code{\link{assert_order_vars}()} } -\concept{assertion} -\keyword{assertion} +\concept{deprecated} +\keyword{deprecated} diff --git a/man/assert_numeric_vector.Rd b/man/assert_numeric_vector.Rd index a12da5ca..34a855aa 100644 --- a/man/assert_numeric_vector.Rd +++ b/man/assert_numeric_vector.Rd @@ -39,13 +39,10 @@ Checks for valid input and returns warning or errors messages: \code{\link{assert_expr}()}, \code{\link{assert_filter_cond}()}, \code{\link{assert_function_param}()}, -\code{\link{assert_function}()}, -\code{\link{assert_has_variables}()}, \code{\link{assert_integer_scalar}()}, \code{\link{assert_list_element}()}, \code{\link{assert_list_of}()}, \code{\link{assert_logical_scalar}()}, -\code{\link{assert_named_exprs}()}, \code{\link{assert_named}()}, \code{\link{assert_one_to_one}()}, \code{\link{assert_param_does_not_exist}()}, diff --git a/man/assert_one_to_one.Rd b/man/assert_one_to_one.Rd index 09a71367..67dfd455 100644 --- a/man/assert_one_to_one.Rd +++ b/man/assert_one_to_one.Rd @@ -32,13 +32,10 @@ Checks for valid input and returns warning or errors messages: \code{\link{assert_expr}()}, \code{\link{assert_filter_cond}()}, \code{\link{assert_function_param}()}, -\code{\link{assert_function}()}, -\code{\link{assert_has_variables}()}, \code{\link{assert_integer_scalar}()}, \code{\link{assert_list_element}()}, \code{\link{assert_list_of}()}, \code{\link{assert_logical_scalar}()}, -\code{\link{assert_named_exprs}()}, \code{\link{assert_named}()}, \code{\link{assert_numeric_vector}()}, \code{\link{assert_param_does_not_exist}()}, diff --git a/man/assert_order_vars.Rd b/man/assert_order_vars.Rd index b17ce75a..48c00578 100644 --- a/man/assert_order_vars.Rd +++ b/man/assert_order_vars.Rd @@ -27,9 +27,9 @@ using \code{exprs()} } \seealso{ Other deprecated: -\code{\link{quo_c}()}, -\code{\link{quo_not_missing}()}, -\code{\link{replace_symbol_in_quo}()} +\code{\link{assert_function}()}, +\code{\link{assert_has_variables}()}, +\code{\link{assert_named_exprs}()} } \concept{deprecated} \keyword{deprecated} diff --git a/man/assert_param_does_not_exist.Rd b/man/assert_param_does_not_exist.Rd index c51ec8df..bb2f839c 100644 --- a/man/assert_param_does_not_exist.Rd +++ b/man/assert_param_does_not_exist.Rd @@ -39,13 +39,10 @@ Checks for valid input and returns warning or errors messages: \code{\link{assert_expr}()}, \code{\link{assert_filter_cond}()}, \code{\link{assert_function_param}()}, -\code{\link{assert_function}()}, -\code{\link{assert_has_variables}()}, \code{\link{assert_integer_scalar}()}, \code{\link{assert_list_element}()}, \code{\link{assert_list_of}()}, \code{\link{assert_logical_scalar}()}, -\code{\link{assert_named_exprs}()}, \code{\link{assert_named}()}, \code{\link{assert_numeric_vector}()}, \code{\link{assert_one_to_one}()}, diff --git a/man/assert_s3_class.Rd b/man/assert_s3_class.Rd index 1726392b..fd41a9a6 100644 --- a/man/assert_s3_class.Rd +++ b/man/assert_s3_class.Rd @@ -43,13 +43,10 @@ Checks for valid input and returns warning or errors messages: \code{\link{assert_expr}()}, \code{\link{assert_filter_cond}()}, \code{\link{assert_function_param}()}, -\code{\link{assert_function}()}, -\code{\link{assert_has_variables}()}, \code{\link{assert_integer_scalar}()}, \code{\link{assert_list_element}()}, \code{\link{assert_list_of}()}, \code{\link{assert_logical_scalar}()}, -\code{\link{assert_named_exprs}()}, \code{\link{assert_named}()}, \code{\link{assert_numeric_vector}()}, \code{\link{assert_one_to_one}()}, diff --git a/man/assert_same_type.Rd b/man/assert_same_type.Rd index c12d7c6c..797bab58 100644 --- a/man/assert_same_type.Rd +++ b/man/assert_same_type.Rd @@ -43,13 +43,10 @@ Checks for valid input and returns warning or errors messages: \code{\link{assert_expr}()}, \code{\link{assert_filter_cond}()}, \code{\link{assert_function_param}()}, -\code{\link{assert_function}()}, -\code{\link{assert_has_variables}()}, \code{\link{assert_integer_scalar}()}, \code{\link{assert_list_element}()}, \code{\link{assert_list_of}()}, \code{\link{assert_logical_scalar}()}, -\code{\link{assert_named_exprs}()}, \code{\link{assert_named}()}, \code{\link{assert_numeric_vector}()}, \code{\link{assert_one_to_one}()}, diff --git a/man/assert_symbol.Rd b/man/assert_symbol.Rd index 52819dfb..4a7ad587 100644 --- a/man/assert_symbol.Rd +++ b/man/assert_symbol.Rd @@ -20,23 +20,23 @@ invisibly otherwise. Checks if an argument is a symbol } \examples{ -library(admiral.test) +library(pharmaversesdtm) library(dplyr, warn.conflicts = FALSE) library(rlang) -data(admiral_dm) +data(dm) example_fun <- function(dat, var) { var <- assert_symbol(enexpr(var)) select(dat, !!var) } -example_fun(admiral_dm, USUBJID) +example_fun(dm, USUBJID) -try(example_fun(admiral_dm)) +try(example_fun(dm)) -try(example_fun(admiral_dm, "USUBJID")) +try(example_fun(dm, "USUBJID")) -try(example_fun(admiral_dm, toupper(PARAMCD))) +try(example_fun(dm, toupper(PARAMCD))) } \seealso{ Checks for valid input and returns warning or errors messages: @@ -49,13 +49,10 @@ Checks for valid input and returns warning or errors messages: \code{\link{assert_expr}()}, \code{\link{assert_filter_cond}()}, \code{\link{assert_function_param}()}, -\code{\link{assert_function}()}, -\code{\link{assert_has_variables}()}, \code{\link{assert_integer_scalar}()}, \code{\link{assert_list_element}()}, \code{\link{assert_list_of}()}, \code{\link{assert_logical_scalar}()}, -\code{\link{assert_named_exprs}()}, \code{\link{assert_named}()}, \code{\link{assert_numeric_vector}()}, \code{\link{assert_one_to_one}()}, diff --git a/man/assert_unit.Rd b/man/assert_unit.Rd index 52820720..b72051d9 100644 --- a/man/assert_unit.Rd +++ b/man/assert_unit.Rd @@ -45,13 +45,10 @@ Checks for valid input and returns warning or errors messages: \code{\link{assert_expr}()}, \code{\link{assert_filter_cond}()}, \code{\link{assert_function_param}()}, -\code{\link{assert_function}()}, -\code{\link{assert_has_variables}()}, \code{\link{assert_integer_scalar}()}, \code{\link{assert_list_element}()}, \code{\link{assert_list_of}()}, \code{\link{assert_logical_scalar}()}, -\code{\link{assert_named_exprs}()}, \code{\link{assert_named}()}, \code{\link{assert_numeric_vector}()}, \code{\link{assert_one_to_one}()}, diff --git a/man/assert_vars.Rd b/man/assert_vars.Rd index 596f418a..873b1cce 100644 --- a/man/assert_vars.Rd +++ b/man/assert_vars.Rd @@ -57,13 +57,10 @@ Checks for valid input and returns warning or errors messages: \code{\link{assert_expr}()}, \code{\link{assert_filter_cond}()}, \code{\link{assert_function_param}()}, -\code{\link{assert_function}()}, -\code{\link{assert_has_variables}()}, \code{\link{assert_integer_scalar}()}, \code{\link{assert_list_element}()}, \code{\link{assert_list_of}()}, \code{\link{assert_logical_scalar}()}, -\code{\link{assert_named_exprs}()}, \code{\link{assert_named}()}, \code{\link{assert_numeric_vector}()}, \code{\link{assert_one_to_one}()}, diff --git a/man/assert_varval_list.Rd b/man/assert_varval_list.Rd index 343fe57c..2dc74ae7 100644 --- a/man/assert_varval_list.Rd +++ b/man/assert_varval_list.Rd @@ -56,13 +56,10 @@ Checks for valid input and returns warning or errors messages: \code{\link{assert_expr}()}, \code{\link{assert_filter_cond}()}, \code{\link{assert_function_param}()}, -\code{\link{assert_function}()}, -\code{\link{assert_has_variables}()}, \code{\link{assert_integer_scalar}()}, \code{\link{assert_list_element}()}, \code{\link{assert_list_of}()}, \code{\link{assert_logical_scalar}()}, -\code{\link{assert_named_exprs}()}, \code{\link{assert_named}()}, \code{\link{assert_numeric_vector}()}, \code{\link{assert_one_to_one}()}, diff --git a/man/contains_vars.Rd b/man/contains_vars.Rd index 411aac94..77c0f1e5 100644 --- a/man/contains_vars.Rd +++ b/man/contains_vars.Rd @@ -25,6 +25,7 @@ Developer Utility Functions: \code{\link{convert_dtm_to_dtc}()}, \code{\link{extract_vars}()}, \code{\link{filter_if}()}, +\code{\link{friendly_type_of}()}, \code{\link{valid_time_units}()}, \code{\link{vars2chr}()} } diff --git a/man/convert_dtm_to_dtc.Rd b/man/convert_dtm_to_dtc.Rd index 6ea86669..5940d4b1 100644 --- a/man/convert_dtm_to_dtc.Rd +++ b/man/convert_dtm_to_dtc.Rd @@ -25,6 +25,7 @@ Developer Utility Functions: \code{\link{contains_vars}()}, \code{\link{extract_vars}()}, \code{\link{filter_if}()}, +\code{\link{friendly_type_of}()}, \code{\link{valid_time_units}()}, \code{\link{vars2chr}()} } diff --git a/man/extract_vars.Rd b/man/extract_vars.Rd index 198ed3eb..6b2a8bff 100644 --- a/man/extract_vars.Rd +++ b/man/extract_vars.Rd @@ -31,6 +31,7 @@ Developer Utility Functions: \code{\link{contains_vars}()}, \code{\link{convert_dtm_to_dtc}()}, \code{\link{filter_if}()}, +\code{\link{friendly_type_of}()}, \code{\link{valid_time_units}()}, \code{\link{vars2chr}()} } diff --git a/man/filter_if.Rd b/man/filter_if.Rd index 23cd1447..e15cdf19 100644 --- a/man/filter_if.Rd +++ b/man/filter_if.Rd @@ -26,6 +26,7 @@ Developer Utility Functions: \code{\link{contains_vars}()}, \code{\link{convert_dtm_to_dtc}()}, \code{\link{extract_vars}()}, +\code{\link{friendly_type_of}()}, \code{\link{valid_time_units}()}, \code{\link{vars2chr}()} } diff --git a/man/friendly_type_of.Rd b/man/friendly_type_of.Rd new file mode 100644 index 00000000..c52ba7c5 --- /dev/null +++ b/man/friendly_type_of.Rd @@ -0,0 +1,42 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/compat_friendly_type.R +\name{friendly_type_of} +\alias{friendly_type_of} +\title{Return English-friendly messaging for object-types} +\usage{ +friendly_type_of(x, value = TRUE, length = FALSE) +} +\arguments{ +\item{x}{Any R object.} + +\item{value}{Whether to describe the value of \code{x}.} + +\item{length}{Whether to mention the length of vectors and lists.} +} +\value{ +A string describing the type. Starts with an indefinite +article, e.g. "an integer vector". +} +\description{ +Return English-friendly messaging for object-types +} +\details{ +This helper function aids us in forming user-friendly messages that gets +called through \code{what_is_it()}, which is often used in the assertion functions +to identify what object-type the user passed through an argument instead of +an expected-type. +} +\seealso{ +Developer Utility Functions: +\code{\link{\%notin\%}()}, +\code{\link{\%or\%}()}, +\code{\link{arg_name}()}, +\code{\link{contains_vars}()}, +\code{\link{convert_dtm_to_dtc}()}, +\code{\link{extract_vars}()}, +\code{\link{filter_if}()}, +\code{\link{valid_time_units}()}, +\code{\link{vars2chr}()} +} +\concept{dev_utility} +\keyword{dev_utility} diff --git a/man/get_constant_vars.Rd b/man/get_constant_vars.Rd index 373bcefe..1fda9d09 100644 --- a/man/get_constant_vars.Rd +++ b/man/get_constant_vars.Rd @@ -28,6 +28,7 @@ Get Constant Variables } \seealso{ Brings something to you!?!: +\code{\link{get_dataset}()}, \code{\link{get_duplicates}()}, \code{\link{get_source_vars}()} } diff --git a/man/get_dataset.Rd b/man/get_dataset.Rd index 2b391952..142bde84 100644 --- a/man/get_dataset.Rd +++ b/man/get_dataset.Rd @@ -1,5 +1,5 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/datasets.R +% Please edit documentation in R/get.R \name{get_dataset} \alias{get_dataset} \title{Retrieve a Dataset from the \code{admiraldev_environment} environment} @@ -15,5 +15,31 @@ A \code{data.frame} \description{ Retrieve a Dataset from the \code{admiraldev_environment} environment } -\concept{datasets} -\keyword{datasets} +\details{ +Sometimes, developers may want to provide information to users which does not fit into a +warning or error message. For example, if the input dataset of a function contains unexpected +records, these can be stored in a separate dataset, which users can access to investigate +the issue. + +To achieve this, R has a data structure known as an 'environment'. These environment objects +are created at build time, but can be populated with values after the package has been loaded +and update those values over the course of an R session. + +As so, the establishment of \code{admiraldev_environment} allows us to create dynamic data/objects +based on user-inputs that need modification. The purpose of \code{get_dataset} is to +retrieve the datasets contained inside \code{admiraldev_environment}. + +Currently we only support two datasets inside our \code{admiraldev_environment} object: +\itemize{ +\item \code{one_to_many} +\item \code{many_to_one} +} +} +\seealso{ +Brings something to you!?!: +\code{\link{get_constant_vars}()}, +\code{\link{get_duplicates}()}, +\code{\link{get_source_vars}()} +} +\concept{get} +\keyword{get} diff --git a/man/get_duplicates.Rd b/man/get_duplicates.Rd index ad6b5da7..dffad00b 100644 --- a/man/get_duplicates.Rd +++ b/man/get_duplicates.Rd @@ -23,6 +23,7 @@ get_duplicates(c("a", "a", "b", "c", "d", "d")) \seealso{ Brings something to you!?!: \code{\link{get_constant_vars}()}, +\code{\link{get_dataset}()}, \code{\link{get_source_vars}()} } \concept{get} diff --git a/man/get_new_tmp_var.Rd b/man/get_new_tmp_var.Rd index bc892e40..e0a5e799 100644 --- a/man/get_new_tmp_var.Rd +++ b/man/get_new_tmp_var.Rd @@ -26,11 +26,11 @@ The function returns a new unique temporary variable name to be used inside } \examples{ library(dplyr, warn.conflicts = FALSE) -library(admiral.test) -data(admiral_dm) +library(pharmaversesdtm) +data(dm) -tmp_var <- get_new_tmp_var(admiral_dm) -mutate(admiral_dm, !!tmp_var := NA) +tmp_var <- get_new_tmp_var(dm) +mutate(dm, !!tmp_var := NA) } \seealso{ \code{\link[=remove_tmp_vars]{remove_tmp_vars()}} diff --git a/man/get_source_vars.Rd b/man/get_source_vars.Rd index f0458b4b..45797a0c 100644 --- a/man/get_source_vars.Rd +++ b/man/get_source_vars.Rd @@ -20,6 +20,7 @@ Get Source Variables from a List of Expressions \seealso{ Brings something to you!?!: \code{\link{get_constant_vars}()}, +\code{\link{get_dataset}()}, \code{\link{get_duplicates}()} } \concept{get} diff --git a/man/grapes-notin-grapes.Rd b/man/grapes-notin-grapes.Rd index 61c33f64..d65221dd 100644 --- a/man/grapes-notin-grapes.Rd +++ b/man/grapes-notin-grapes.Rd @@ -26,6 +26,7 @@ Developer Utility Functions: \code{\link{convert_dtm_to_dtc}()}, \code{\link{extract_vars}()}, \code{\link{filter_if}()}, +\code{\link{friendly_type_of}()}, \code{\link{valid_time_units}()}, \code{\link{vars2chr}()} } diff --git a/man/grapes-or-grapes.Rd b/man/grapes-or-grapes.Rd index b7c6da50..4c93ede5 100644 --- a/man/grapes-or-grapes.Rd +++ b/man/grapes-or-grapes.Rd @@ -30,6 +30,7 @@ Developer Utility Functions: \code{\link{convert_dtm_to_dtc}()}, \code{\link{extract_vars}()}, \code{\link{filter_if}()}, +\code{\link{friendly_type_of}()}, \code{\link{valid_time_units}()}, \code{\link{vars2chr}()} } diff --git a/man/quo_c.Rd b/man/quo_c.Rd deleted file mode 100644 index 672877ae..00000000 --- a/man/quo_c.Rd +++ /dev/null @@ -1,28 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/quo.R -\name{quo_c} -\alias{quo_c} -\title{Concatenate One or More Quosure(s)} -\usage{ -quo_c(...) -} -\arguments{ -\item{...}{One or more objects of class \code{quosure} or \code{quosures}} -} -\value{ -An object of class \code{quosures} -} -\description{ -\ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#deprecated}{\figure{lifecycle-deprecated.svg}{options: alt='[Deprecated]'}}}{\strong{[Deprecated]}} -} -\details{ -This function is \emph{deprecated}, please use \code{expr_c()} instead. -} -\seealso{ -Other deprecated: -\code{\link{assert_order_vars}()}, -\code{\link{quo_not_missing}()}, -\code{\link{replace_symbol_in_quo}()} -} -\concept{deprecated} -\keyword{deprecated} diff --git a/man/quo_not_missing.Rd b/man/quo_not_missing.Rd deleted file mode 100644 index 7e45b673..00000000 --- a/man/quo_not_missing.Rd +++ /dev/null @@ -1,25 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/quo.R -\name{quo_not_missing} -\alias{quo_not_missing} -\title{Check Whether an Argument Is Not a Quosure of a Missing Argument} -\usage{ -quo_not_missing(x) -} -\arguments{ -\item{x}{Test object} -} -\value{ -TRUE or error. -} -\description{ -Check Whether an Argument Is Not a Quosure of a Missing Argument -} -\seealso{ -Other deprecated: -\code{\link{assert_order_vars}()}, -\code{\link{quo_c}()}, -\code{\link{replace_symbol_in_quo}()} -} -\concept{deprecated} -\keyword{deprecated} diff --git a/man/remove_tmp_vars.Rd b/man/remove_tmp_vars.Rd index b8275256..339fdb1e 100644 --- a/man/remove_tmp_vars.Rd +++ b/man/remove_tmp_vars.Rd @@ -17,9 +17,9 @@ Remove All Temporary Variables Created Within the Current Function Environment } \examples{ library(dplyr, warn.conflicts = FALSE) -library(admiral.test) -data(admiral_dm) -dm <- select(admiral_dm, USUBJID) +library(pharmaversesdtm) +data(dm) +dm <- select(dm, USUBJID) tmp_var <- get_new_tmp_var(dm) dm <- mutate(dm, !!tmp_var := NA) diff --git a/man/replace_symbol_in_quo.Rd b/man/replace_symbol_in_quo.Rd deleted file mode 100644 index ccbb3200..00000000 --- a/man/replace_symbol_in_quo.Rd +++ /dev/null @@ -1,33 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/quo.R -\name{replace_symbol_in_quo} -\alias{replace_symbol_in_quo} -\title{Replace Symbols in a Quosure} -\usage{ -replace_symbol_in_quo(quosure, target, replace) -} -\arguments{ -\item{quosure}{Quosure} - -\item{target}{Target symbol} - -\item{replace}{Replacing symbol} -} -\value{ -The quosure where every occurrence of the symbol \code{target} is replaced -by \code{replace} -} -\description{ -\ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#deprecated}{\figure{lifecycle-deprecated.svg}{options: alt='[Deprecated]'}}}{\strong{[Deprecated]}} -} -\details{ -This function is \emph{deprecated}, please use \code{replace_symbol_in_expr()} instead. -} -\seealso{ -Other deprecated: -\code{\link{assert_order_vars}()}, -\code{\link{quo_c}()}, -\code{\link{quo_not_missing}()} -} -\concept{deprecated} -\keyword{deprecated} diff --git a/man/valid_time_units.Rd b/man/valid_time_units.Rd index 44d3d8ea..ed0b27d9 100644 --- a/man/valid_time_units.Rd +++ b/man/valid_time_units.Rd @@ -21,6 +21,7 @@ Developer Utility Functions: \code{\link{convert_dtm_to_dtc}()}, \code{\link{extract_vars}()}, \code{\link{filter_if}()}, +\code{\link{friendly_type_of}()}, \code{\link{vars2chr}()} } \concept{dev_utility} diff --git a/man/vars2chr.Rd b/man/vars2chr.Rd index 039beb93..15d59450 100644 --- a/man/vars2chr.Rd +++ b/man/vars2chr.Rd @@ -32,6 +32,7 @@ Developer Utility Functions: \code{\link{convert_dtm_to_dtc}()}, \code{\link{extract_vars}()}, \code{\link{filter_if}()}, +\code{\link{friendly_type_of}()}, \code{\link{valid_time_units}()} } \concept{dev_utility} diff --git a/man/warn_if_vars_exist.Rd b/man/warn_if_vars_exist.Rd index c709439a..2c5ca4a6 100644 --- a/man/warn_if_vars_exist.Rd +++ b/man/warn_if_vars_exist.Rd @@ -18,14 +18,14 @@ No return value, called for side effects Warn if a variable already exists inside a dataset } \examples{ -library(admiral.test) -data(admiral_dm) +library(pharmaversesdtm) +data(dm) ## No warning as `AAGE` doesn't exist in `dm` -warn_if_vars_exist(admiral_dm, "AAGE") +warn_if_vars_exist(dm, "AAGE") ## Issues a warning -warn_if_vars_exist(admiral_dm, "ARM") +warn_if_vars_exist(dm, "ARM") } \seealso{ Function that provide users with custom warnings diff --git a/renv.lock b/renv.lock index 66174483..5801ed10 100644 --- a/renv.lock +++ b/renv.lock @@ -4,7 +4,7 @@ "Repositories": [ { "Name": "CRAN", - "URL": "https://cloud.r-project.org" + "URL": "https://packagemanager.posit.co/cran/latest" }, { "Name": "RSPM", @@ -179,7 +179,7 @@ "Package": "callr", "Version": "3.7.3", "Source": "Repository", - "Repository": "CRAN", + "Repository": "RSPM", "Requirements": [ "R", "R6", @@ -188,11 +188,23 @@ ], "Hash": "9b2191ede20fa29828139b9900922e51" }, + "cellranger": { + "Package": "cellranger", + "Version": "1.1.0", + "Source": "Repository", + "Repository": "RSPM", + "Requirements": [ + "R", + "rematch", + "tibble" + ], + "Hash": "f61dbaec772ccd2e17705c1e872e9e7c" + }, "cli": { "Package": "cli", "Version": "3.4.1", "Source": "Repository", - "Repository": "CRAN", + "Repository": "RSPM", "Requirements": [ "R", "utils" @@ -219,6 +231,13 @@ ], "Hash": "019388fc48e48b3da0d3a76ff94608a8" }, + "collections": { + "Package": "collections", + "Version": "0.3.5", + "Source": "Repository", + "Repository": "RSPM", + "Hash": "92537c684a3d2eaa6bd8f65c28ef97f0" + }, "commonmark": { "Package": "commonmark", "Version": "1.8.0", @@ -250,7 +269,7 @@ "Package": "cpp11", "Version": "0.4.3", "Source": "Repository", - "Repository": "CRAN", + "Repository": "RSPM", "Hash": "ed588261931ee3be2c700d22e94a29ab" }, "crayon": { @@ -320,7 +339,7 @@ "Package": "desc", "Version": "1.4.2", "Source": "Repository", - "Repository": "CRAN", + "Repository": "RSPM", "Requirements": [ "R", "R6", @@ -423,7 +442,7 @@ "Package": "dplyr", "Version": "1.1.1", "Source": "Repository", - "Repository": "CRAN", + "Repository": "RSPM", "Requirements": [ "R", "R6", @@ -704,7 +723,7 @@ "Package": "knitr", "Version": "1.40", "Source": "Repository", - "Repository": "CRAN", + "Repository": "RSPM", "Requirements": [ "R", "evaluate", @@ -717,6 +736,30 @@ ], "Hash": "caea8b0f899a0b1738444b9bc47067e7" }, + "languageserver": { + "Package": "languageserver", + "Version": "0.3.12", + "Source": "Repository", + "Repository": "RSPM", + "Requirements": [ + "R", + "R6", + "callr", + "collections", + "fs", + "jsonlite", + "lintr", + "parallel", + "roxygen2", + "stringi", + "styler", + "tools", + "utils", + "xml2", + "xmlparsedata" + ], + "Hash": "f62ed8b09fd56cd70291bd077bc52c4b" + }, "later": { "Package": "later", "Version": "1.3.0", @@ -755,7 +798,7 @@ "Package": "lintr", "Version": "3.0.2", "Source": "Repository", - "Repository": "CRAN", + "Repository": "RSPM", "Requirements": [ "R", "backports", @@ -841,7 +884,7 @@ "Package": "pillar", "Version": "1.9.0", "Source": "Repository", - "Repository": "CRAN", + "Repository": "RSPM", "Requirements": [ "cli", "fansi", @@ -886,7 +929,7 @@ "Package": "pkgdown", "Version": "2.0.7", "Source": "Repository", - "Repository": "CRAN", + "Repository": "RSPM", "Requirements": [ "R", "bslib", @@ -948,7 +991,7 @@ "Package": "processx", "Version": "3.6.1", "Source": "Repository", - "Repository": "CRAN", + "Repository": "RSPM", "Requirements": [ "R", "R6", @@ -957,6 +1000,19 @@ ], "Hash": "a11891e28c1f1e5ddd773ba1b8c07cf6" }, + "progress": { + "Package": "progress", + "Version": "1.2.2", + "Source": "Repository", + "Repository": "RSPM", + "Requirements": [ + "R6", + "crayon", + "hms", + "prettyunits" + ], + "Hash": "14dc9f7a3c91ebb14ec5bb9208a07061" + }, "promises": { "Package": "promises", "Version": "1.2.0.1", @@ -1038,6 +1094,27 @@ ], "Hash": "8f25ebe2ec38b1f2aef3b0d2ef76f6c4" }, + "readxl": { + "Package": "readxl", + "Version": "1.3.1", + "Source": "Repository", + "Repository": "RSPM", + "Requirements": [ + "Rcpp", + "cellranger", + "progress", + "tibble", + "utils" + ], + "Hash": "63537c483c2dbec8d9e3183b3735254a" + }, + "rematch": { + "Package": "rematch", + "Version": "1.0.1", + "Source": "Repository", + "Repository": "RSPM", + "Hash": "c66b930d20bb6d858cd18e1cebcfae5c" + }, "rematch2": { "Package": "rematch2", "Version": "2.1.2", @@ -1050,7 +1127,7 @@ }, "remotes": { "Package": "remotes", - "Version": "2.4.2", + "Version": "2.4.2.1", "Source": "Repository", "Repository": "RSPM", "Requirements": [ @@ -1060,17 +1137,17 @@ "tools", "utils" ], - "Hash": "227045be9aee47e6dda9bb38ac870d67" + "Hash": "63d15047eb239f95160112bcadc4fcb9" }, "renv": { "Package": "renv", - "Version": "0.17.0", + "Version": "1.0.0", "Source": "Repository", "Repository": "RSPM", "Requirements": [ "utils" ], - "Hash": "ce3065fc1a0b64a859f55ac3998d6927" + "Hash": "c321cd99d56443dbffd1c9e673c0c1a2" }, "rex": { "Package": "rex", @@ -1086,7 +1163,7 @@ "Package": "rlang", "Version": "1.1.0", "Source": "Repository", - "Repository": "CRAN", + "Repository": "RSPM", "Requirements": [ "R", "utils" @@ -1097,7 +1174,7 @@ "Package": "rmarkdown", "Version": "2.17", "Source": "Repository", - "Repository": "CRAN", + "Repository": "RSPM", "Requirements": [ "R", "bslib", @@ -1120,7 +1197,7 @@ "Package": "roxygen2", "Version": "7.2.3", "Source": "Repository", - "Repository": "CRAN", + "Repository": "RSPM", "Requirements": [ "R", "R6", @@ -1257,14 +1334,14 @@ }, "staged.dependencies": { "Package": "staged.dependencies", - "Version": "0.2.8", + "Version": "0.3.1", "Source": "GitHub", "RemoteType": "github", "RemoteHost": "api.github.com", "RemoteUsername": "openpharma", "RemoteRepo": "staged.dependencies", "RemoteRef": "main", - "RemoteSha": "ce7c112ba3d75cf48e4dd6310b3140ab0ec3b486", + "RemoteSha": "1ab184a029bef8839a57bb6acd1c5c919cf1fd89", "Requirements": [ "desc", "devtools", @@ -1285,7 +1362,7 @@ "withr", "yaml" ], - "Hash": "89f2e1d1009601f58f64b7092abcc0d7" + "Hash": "ea298f9fb221a8c7ca4c9e55e9c29b48" }, "stringi": { "Package": "stringi", @@ -1317,7 +1394,7 @@ "Package": "styler", "Version": "1.9.1", "Source": "Repository", - "Repository": "CRAN", + "Repository": "RSPM", "Requirements": [ "R", "R.cache", @@ -1354,7 +1431,7 @@ "Package": "testthat", "Version": "3.1.7", "Source": "Repository", - "Repository": "CRAN", + "Repository": "RSPM", "Requirements": [ "R", "R6", @@ -1396,7 +1473,7 @@ "Package": "tibble", "Version": "3.2.0", "Source": "Repository", - "Repository": "CRAN", + "Repository": "RSPM", "Requirements": [ "R", "fansi", @@ -1437,7 +1514,7 @@ "Package": "tidyselect", "Version": "1.2.0", "Source": "Repository", - "Repository": "CRAN", + "Repository": "RSPM", "Requirements": [ "R", "cli", @@ -1504,7 +1581,7 @@ "Package": "vctrs", "Version": "0.6.0", "Source": "Repository", - "Repository": "CRAN", + "Repository": "RSPM", "Requirements": [ "R", "cli", @@ -1518,7 +1595,7 @@ "Package": "waldo", "Version": "0.4.0", "Source": "Repository", - "Repository": "CRAN", + "Repository": "RSPM", "Requirements": [ "cli", "diffobj", @@ -1555,7 +1632,7 @@ "Package": "xfun", "Version": "0.34", "Source": "Repository", - "Repository": "CRAN", + "Repository": "RSPM", "Requirements": [ "stats", "tools" diff --git a/renv/activate.R b/renv/activate.R index 360dd528..cc742fc9 100644 --- a/renv/activate.R +++ b/renv/activate.R @@ -2,7 +2,8 @@ local({ # the requested version of renv - version <- "0.17.0" + version <- "1.0.0" + attr(version, "sha") <- NULL # the project directory project <- getwd() @@ -60,21 +61,75 @@ local({ # load bootstrap tools `%||%` <- function(x, y) { - if (is.environment(x) || length(x)) x else y + if (is.null(x)) y else x + } + + catf <- function(fmt, ..., appendLF = TRUE) { + + quiet <- getOption("renv.bootstrap.quiet", default = FALSE) + if (quiet) + return(invisible()) + + msg <- sprintf(fmt, ...) + cat(msg, file = stdout(), sep = if (appendLF) "\n" else "") + + invisible(msg) + + } + + header <- function(label, + ..., + prefix = "#", + suffix = "-", + n = min(getOption("width"), 78)) + { + label <- sprintf(label, ...) + n <- max(n - nchar(label) - nchar(prefix) - 2L, 8L) + if (n <= 0) + return(paste(prefix, label)) + + tail <- paste(rep.int(suffix, n), collapse = "") + paste0(prefix, " ", label, " ", tail) + + } + + startswith <- function(string, prefix) { + substring(string, 1, nchar(prefix)) == prefix } bootstrap <- function(version, library) { + friendly <- renv_bootstrap_version_friendly(version) + section <- header(sprintf("Bootstrapping renv %s", friendly)) + catf(section) + # attempt to download renv - tarball <- tryCatch(renv_bootstrap_download(version), error = identity) - if (inherits(tarball, "error")) - stop("failed to download renv ", version) + catf("- Downloading renv ... ", appendLF = FALSE) + withCallingHandlers( + tarball <- renv_bootstrap_download(version), + error = function(err) { + catf("FAILED") + stop("failed to download:\n", conditionMessage(err)) + } + ) + catf("OK") + on.exit(unlink(tarball), add = TRUE) # now attempt to install - status <- tryCatch(renv_bootstrap_install(version, tarball, library), error = identity) - if (inherits(status, "error")) - stop("failed to install renv ", version) + catf("- Installing renv ... ", appendLF = FALSE) + withCallingHandlers( + status <- renv_bootstrap_install(version, tarball, library), + error = function(err) { + catf("FAILED") + stop("failed to install:\n", conditionMessage(err)) + } + ) + catf("OK") + + # add empty line to break up bootstrapping from normal output + catf("") + return(invisible()) } renv_bootstrap_tests_running <- function() { @@ -83,31 +138,32 @@ local({ renv_bootstrap_repos <- function() { + # get CRAN repository + cran <- getOption("renv.repos.cran", "https://cloud.r-project.org") + # check for repos override repos <- Sys.getenv("RENV_CONFIG_REPOS_OVERRIDE", unset = NA) - if (!is.na(repos)) + if (!is.na(repos)) { + + # check for RSPM; if set, use a fallback repository for renv + rspm <- Sys.getenv("RSPM", unset = NA) + if (identical(rspm, repos)) + repos <- c(RSPM = rspm, CRAN = cran) + return(repos) + } + # check for lockfile repositories repos <- tryCatch(renv_bootstrap_repos_lockfile(), error = identity) if (!inherits(repos, "error") && length(repos)) return(repos) - # if we're testing, re-use the test repositories - if (renv_bootstrap_tests_running()) { - repos <- getOption("renv.tests.repos") - if (!is.null(repos)) - return(repos) - } - # retrieve current repos repos <- getOption("repos") # ensure @CRAN@ entries are resolved - repos[repos == "@CRAN@"] <- getOption( - "renv.repos.cran", - "https://cloud.r-project.org" - ) + repos[repos == "@CRAN@"] <- cran # add in renv.bootstrap.repos if set default <- c(FALLBACK = "https://cloud.r-project.org") @@ -146,33 +202,34 @@ local({ renv_bootstrap_download <- function(version) { - # if the renv version number has 4 components, assume it must - # be retrieved via github - nv <- numeric_version(version) - components <- unclass(nv)[[1]] - - # if this appears to be a development version of 'renv', we'll - # try to restore from github - dev <- length(components) == 4L - - # begin collecting different methods for finding renv - methods <- c( - renv_bootstrap_download_tarball, - if (dev) - renv_bootstrap_download_github - else c( - renv_bootstrap_download_cran_latest, - renv_bootstrap_download_cran_archive + sha <- attr(version, "sha", exact = TRUE) + + methods <- if (!is.null(sha)) { + + # attempting to bootstrap a development version of renv + c( + function() renv_bootstrap_download_tarball(sha), + function() renv_bootstrap_download_github(sha) ) - ) + + } else { + + # attempting to bootstrap a release version of renv + c( + function() renv_bootstrap_download_tarball(version), + function() renv_bootstrap_download_cran_latest(version), + function() renv_bootstrap_download_cran_archive(version) + ) + + } for (method in methods) { - path <- tryCatch(method(version), error = identity) + path <- tryCatch(method(), error = identity) if (is.character(path) && file.exists(path)) return(path) } - stop("failed to download renv ", version) + stop("All download methods failed") } @@ -236,8 +293,6 @@ local({ type <- spec$type repos <- spec$repos - message("* Downloading renv ", version, " ... ", appendLF = FALSE) - baseurl <- utils::contrib.url(repos = repos, type = type) ext <- if (identical(type, "source")) ".tar.gz" @@ -254,13 +309,10 @@ local({ condition = identity ) - if (inherits(status, "condition")) { - message("FAILED") + if (inherits(status, "condition")) return(FALSE) - } # report success and return - message("OK (downloaded ", type, ")") destfile } @@ -317,8 +369,6 @@ local({ urls <- file.path(repos, "src/contrib/Archive/renv", name) destfile <- file.path(tempdir(), name) - message("* Downloading renv ", version, " ... ", appendLF = FALSE) - for (url in urls) { status <- tryCatch( @@ -326,14 +376,11 @@ local({ condition = identity ) - if (identical(status, 0L)) { - message("OK") + if (identical(status, 0L)) return(destfile) - } } - message("FAILED") return(FALSE) } @@ -356,7 +403,7 @@ local({ if (!file.exists(tarball)) { # let the user know we weren't able to honour their request - fmt <- "* RENV_BOOTSTRAP_TARBALL is set (%s) but does not exist." + fmt <- "- RENV_BOOTSTRAP_TARBALL is set (%s) but does not exist." msg <- sprintf(fmt, tarball) warning(msg) @@ -365,10 +412,7 @@ local({ } - fmt <- "* Bootstrapping with tarball at path '%s'." - msg <- sprintf(fmt, tarball) - message(msg) - + catf("- Using local tarball '%s'.", tarball) tarball } @@ -395,8 +439,6 @@ local({ on.exit(do.call(base::options, saved), add = TRUE) } - message("* Downloading renv ", version, " from GitHub ... ", appendLF = FALSE) - url <- file.path("https://api.github.com/repos/rstudio/renv/tarball", version) name <- sprintf("renv_%s.tar.gz", version) destfile <- file.path(tempdir(), name) @@ -406,26 +448,105 @@ local({ condition = identity ) - if (!identical(status, 0L)) { - message("FAILED") + if (!identical(status, 0L)) return(FALSE) - } - message("OK") + renv_bootstrap_download_augment(destfile) + return(destfile) } + # Add Sha to DESCRIPTION. This is stop gap until #890, after which we + # can use renv::install() to fully capture metadata. + renv_bootstrap_download_augment <- function(destfile) { + sha <- renv_bootstrap_git_extract_sha1_tar(destfile) + if (is.null(sha)) { + return() + } + + # Untar + tempdir <- tempfile("renv-github-") + on.exit(unlink(tempdir, recursive = TRUE), add = TRUE) + untar(destfile, exdir = tempdir) + pkgdir <- dir(tempdir, full.names = TRUE)[[1]] + + # Modify description + desc_path <- file.path(pkgdir, "DESCRIPTION") + desc_lines <- readLines(desc_path) + remotes_fields <- c( + "RemoteType: github", + "RemoteHost: api.github.com", + "RemoteRepo: renv", + "RemoteUsername: rstudio", + "RemotePkgRef: rstudio/renv", + paste("RemoteRef: ", sha), + paste("RemoteSha: ", sha) + ) + writeLines(c(desc_lines[desc_lines != ""], remotes_fields), con = desc_path) + + # Re-tar + local({ + old <- setwd(tempdir) + on.exit(setwd(old), add = TRUE) + + tar(destfile, compression = "gzip") + }) + invisible() + } + + # Extract the commit hash from a git archive. Git archives include the SHA1 + # hash as the comment field of the tarball pax extended header + # (see https://www.kernel.org/pub/software/scm/git/docs/git-archive.html) + # For GitHub archives this should be the first header after the default one + # (512 byte) header. + renv_bootstrap_git_extract_sha1_tar <- function(bundle) { + + # open the bundle for reading + # We use gzcon for everything because (from ?gzcon) + # > Reading from a connection which does not supply a ‘gzip’ magic + # > header is equivalent to reading from the original connection + conn <- gzcon(file(bundle, open = "rb", raw = TRUE)) + on.exit(close(conn)) + + # The default pax header is 512 bytes long and the first pax extended header + # with the comment should be 51 bytes long + # `52 comment=` (11 chars) + 40 byte SHA1 hash + len <- 0x200 + 0x33 + res <- rawToChar(readBin(conn, "raw", n = len)[0x201:len]) + + if (grepl("^52 comment=", res)) { + sub("52 comment=", "", res) + } else { + NULL + } + } + renv_bootstrap_install <- function(version, tarball, library) { # attempt to install it into project library - message("* Installing renv ", version, " ... ", appendLF = FALSE) dir.create(library, showWarnings = FALSE, recursive = TRUE) + output <- renv_bootstrap_install_impl(library, tarball) + + # check for successful install + status <- attr(output, "status") + if (is.null(status) || identical(status, 0L)) + return(status) + + # an error occurred; report it + header <- "installation of renv failed" + lines <- paste(rep.int("=", nchar(header)), collapse = "") + text <- paste(c(header, lines, output), collapse = "\n") + stop(text) + + } + + renv_bootstrap_install_impl <- function(library, tarball) { # invoke using system2 so we can capture and report output bin <- R.home("bin") exe <- if (Sys.info()[["sysname"]] == "Windows") "R.exe" else "R" - r <- file.path(bin, exe) + R <- file.path(bin, exe) args <- c( "--vanilla", "CMD", "INSTALL", "--no-multiarch", @@ -433,19 +554,7 @@ local({ shQuote(path.expand(tarball)) ) - output <- system2(r, args, stdout = TRUE, stderr = TRUE) - message("Done!") - - # check for successful install - status <- attr(output, "status") - if (is.numeric(status) && !identical(status, 0L)) { - header <- "Error installing renv:" - lines <- paste(rep.int("=", nchar(header)), collapse = "") - text <- c(header, lines, output) - writeLines(text, con = stderr()) - } - - status + system2(R, args, stdout = TRUE, stderr = TRUE) } @@ -655,34 +764,60 @@ local({ } - renv_bootstrap_validate_version <- function(version) { + renv_bootstrap_validate_version <- function(version, description = NULL) { - loadedversion <- utils::packageDescription("renv", fields = "Version") - if (version == loadedversion) - return(TRUE) + # resolve description file + description <- description %||% { + path <- getNamespaceInfo("renv", "path") + packageDescription("renv", lib.loc = dirname(path)) + } - # assume four-component versions are from GitHub; - # three-component versions are from CRAN - components <- strsplit(loadedversion, "[.-]")[[1]] - remote <- if (length(components) == 4L) - paste("rstudio/renv", loadedversion, sep = "@") + # check whether requested version 'version' matches loaded version of renv + sha <- attr(version, "sha", exact = TRUE) + valid <- if (!is.null(sha)) + renv_bootstrap_validate_version_dev(sha, description) else - paste("renv", loadedversion, sep = "@") + renv_bootstrap_validate_version_release(version, description) + + if (valid) + return(TRUE) + + # the loaded version of renv doesn't match the requested version; + # give the user instructions on how to proceed + remote <- if (!is.null(description[["RemoteSha"]])) { + paste("rstudio/renv", description[["RemoteSha"]], sep = "@") + } else { + paste("renv", description[["Version"]], sep = "@") + } + + # display both loaded version + sha if available + friendly <- renv_bootstrap_version_friendly( + version = description[["Version"]], + sha = description[["RemoteSha"]] + ) fmt <- paste( "renv %1$s was loaded from project library, but this project is configured to use renv %2$s.", - "Use `renv::record(\"%3$s\")` to record renv %1$s in the lockfile.", - "Use `renv::restore(packages = \"renv\")` to install renv %2$s into the project library.", + "- Use `renv::record(\"%3$s\")` to record renv %1$s in the lockfile.", + "- Use `renv::restore(packages = \"renv\")` to install renv %2$s into the project library.", sep = "\n" ) - - msg <- sprintf(fmt, loadedversion, version, remote) - warning(msg, call. = FALSE) + catf(fmt, friendly, renv_bootstrap_version_friendly(version), remote) FALSE } + renv_bootstrap_validate_version_dev <- function(version, description) { + expected <- description[["RemoteSha"]] + is.character(expected) && startswith(expected, version) + } + + renv_bootstrap_validate_version_release <- function(version, description) { + expected <- description[["Version"]] + is.character(expected) && identical(expected, version) + } + renv_bootstrap_hash_text <- function(text) { hashfile <- tempfile("renv-hash-") @@ -847,6 +982,40 @@ local({ } + renv_bootstrap_version_friendly <- function(version, sha = NULL) { + sha <- sha %||% attr(version, "sha", exact = TRUE) + parts <- c(version, sprintf("[sha: %s]", substring(sha, 1L, 7L))) + paste(parts, collapse = " ") + } + + renv_bootstrap_run <- function(version, libpath) { + + # perform bootstrap + bootstrap(version, libpath) + + # exit early if we're just testing bootstrap + if (!is.na(Sys.getenv("RENV_BOOTSTRAP_INSTALL_ONLY", unset = NA))) + return(TRUE) + + # try again to load + if (requireNamespace("renv", lib.loc = libpath, quietly = TRUE)) { + return(renv::load(project = getwd())) + } + + # failed to download or load renv; warn the user + msg <- c( + "Failed to find an renv installation: the project will not be loaded.", + "Use `renv::activate()` to re-initialize the project." + ) + + warning(paste(msg, collapse = "\n"), call. = FALSE) + + } + + + renv_bootstrap_in_rstudio <- function() { + commandArgs()[[1]] == "RStudio" + } renv_json_read <- function(file = NULL, text = NULL) { @@ -990,31 +1159,23 @@ local({ if (renv_bootstrap_load(project, libpath, version)) return(TRUE) - # load failed; inform user we're about to bootstrap - prefix <- paste("# Bootstrapping renv", version) - postfix <- paste(rep.int("-", 77L - nchar(prefix)), collapse = "") - header <- paste(prefix, postfix) - message(header) - - # perform bootstrap - bootstrap(version, libpath) - - # exit early if we're just testing bootstrap - if (!is.na(Sys.getenv("RENV_BOOTSTRAP_INSTALL_ONLY", unset = NA))) - return(TRUE) + if (renv_bootstrap_in_rstudio()) { + setHook("rstudio.sessionInit", function(...) { + renv_bootstrap_run(version, libpath) - # try again to load - if (requireNamespace("renv", lib.loc = libpath, quietly = TRUE)) { - message("* Successfully installed and loaded renv ", version, ".") - return(renv::load()) + # Work around buglet in RStudio if hook uses readline + tryCatch( + { + tools <- as.environment("tools:rstudio") + tools$.rs.api.sendToConsole("", echo = FALSE, focus = FALSE) + }, + error = function(cnd) {} + ) + }) + } else { + renv_bootstrap_run(version, libpath) } - # failed to download or load renv; warn the user - msg <- c( - "Failed to find an renv installation: the project will not be loaded.", - "Use `renv::activate()` to re-initialize the project." - ) - - warning(paste(msg, collapse = "\n"), call. = FALSE) + invisible() }) diff --git a/renv/profiles/4.1/renv.lock b/renv/profiles/4.1/renv.lock index 0f3ac2c8..5801ed10 100644 --- a/renv/profiles/4.1/renv.lock +++ b/renv/profiles/4.1/renv.lock @@ -4,7 +4,7 @@ "Repositories": [ { "Name": "CRAN", - "URL": "https://cloud.r-project.org" + "URL": "https://packagemanager.posit.co/cran/latest" }, { "Name": "RSPM", @@ -179,7 +179,7 @@ "Package": "callr", "Version": "3.7.3", "Source": "Repository", - "Repository": "CRAN", + "Repository": "RSPM", "Requirements": [ "R", "R6", @@ -188,11 +188,23 @@ ], "Hash": "9b2191ede20fa29828139b9900922e51" }, + "cellranger": { + "Package": "cellranger", + "Version": "1.1.0", + "Source": "Repository", + "Repository": "RSPM", + "Requirements": [ + "R", + "rematch", + "tibble" + ], + "Hash": "f61dbaec772ccd2e17705c1e872e9e7c" + }, "cli": { "Package": "cli", "Version": "3.4.1", "Source": "Repository", - "Repository": "CRAN", + "Repository": "RSPM", "Requirements": [ "R", "utils" @@ -219,6 +231,13 @@ ], "Hash": "019388fc48e48b3da0d3a76ff94608a8" }, + "collections": { + "Package": "collections", + "Version": "0.3.5", + "Source": "Repository", + "Repository": "RSPM", + "Hash": "92537c684a3d2eaa6bd8f65c28ef97f0" + }, "commonmark": { "Package": "commonmark", "Version": "1.8.0", @@ -250,7 +269,7 @@ "Package": "cpp11", "Version": "0.4.3", "Source": "Repository", - "Repository": "CRAN", + "Repository": "RSPM", "Hash": "ed588261931ee3be2c700d22e94a29ab" }, "crayon": { @@ -320,7 +339,7 @@ "Package": "desc", "Version": "1.4.2", "Source": "Repository", - "Repository": "CRAN", + "Repository": "RSPM", "Requirements": [ "R", "R6", @@ -423,7 +442,7 @@ "Package": "dplyr", "Version": "1.1.1", "Source": "Repository", - "Repository": "CRAN", + "Repository": "RSPM", "Requirements": [ "R", "R6", @@ -704,7 +723,7 @@ "Package": "knitr", "Version": "1.40", "Source": "Repository", - "Repository": "CRAN", + "Repository": "RSPM", "Requirements": [ "R", "evaluate", @@ -717,6 +736,30 @@ ], "Hash": "caea8b0f899a0b1738444b9bc47067e7" }, + "languageserver": { + "Package": "languageserver", + "Version": "0.3.12", + "Source": "Repository", + "Repository": "RSPM", + "Requirements": [ + "R", + "R6", + "callr", + "collections", + "fs", + "jsonlite", + "lintr", + "parallel", + "roxygen2", + "stringi", + "styler", + "tools", + "utils", + "xml2", + "xmlparsedata" + ], + "Hash": "f62ed8b09fd56cd70291bd077bc52c4b" + }, "later": { "Package": "later", "Version": "1.3.0", @@ -742,7 +785,7 @@ "Package": "lifecycle", "Version": "1.0.3", "Source": "Repository", - "Repository": "CRAN", + "Repository": "RSPM", "Requirements": [ "R", "cli", @@ -755,7 +798,7 @@ "Package": "lintr", "Version": "3.0.2", "Source": "Repository", - "Repository": "CRAN", + "Repository": "RSPM", "Requirements": [ "R", "backports", @@ -841,7 +884,7 @@ "Package": "pillar", "Version": "1.9.0", "Source": "Repository", - "Repository": "CRAN", + "Repository": "RSPM", "Requirements": [ "cli", "fansi", @@ -886,7 +929,7 @@ "Package": "pkgdown", "Version": "2.0.7", "Source": "Repository", - "Repository": "CRAN", + "Repository": "RSPM", "Requirements": [ "R", "bslib", @@ -948,7 +991,7 @@ "Package": "processx", "Version": "3.6.1", "Source": "Repository", - "Repository": "CRAN", + "Repository": "RSPM", "Requirements": [ "R", "R6", @@ -957,6 +1000,19 @@ ], "Hash": "a11891e28c1f1e5ddd773ba1b8c07cf6" }, + "progress": { + "Package": "progress", + "Version": "1.2.2", + "Source": "Repository", + "Repository": "RSPM", + "Requirements": [ + "R6", + "crayon", + "hms", + "prettyunits" + ], + "Hash": "14dc9f7a3c91ebb14ec5bb9208a07061" + }, "promises": { "Package": "promises", "Version": "1.2.0.1", @@ -1038,6 +1094,27 @@ ], "Hash": "8f25ebe2ec38b1f2aef3b0d2ef76f6c4" }, + "readxl": { + "Package": "readxl", + "Version": "1.3.1", + "Source": "Repository", + "Repository": "RSPM", + "Requirements": [ + "Rcpp", + "cellranger", + "progress", + "tibble", + "utils" + ], + "Hash": "63537c483c2dbec8d9e3183b3735254a" + }, + "rematch": { + "Package": "rematch", + "Version": "1.0.1", + "Source": "Repository", + "Repository": "RSPM", + "Hash": "c66b930d20bb6d858cd18e1cebcfae5c" + }, "rematch2": { "Package": "rematch2", "Version": "2.1.2", @@ -1050,7 +1127,7 @@ }, "remotes": { "Package": "remotes", - "Version": "2.4.2", + "Version": "2.4.2.1", "Source": "Repository", "Repository": "RSPM", "Requirements": [ @@ -1060,17 +1137,17 @@ "tools", "utils" ], - "Hash": "227045be9aee47e6dda9bb38ac870d67" + "Hash": "63d15047eb239f95160112bcadc4fcb9" }, "renv": { "Package": "renv", - "Version": "0.17.0", + "Version": "1.0.0", "Source": "Repository", "Repository": "RSPM", "Requirements": [ "utils" ], - "Hash": "ce3065fc1a0b64a859f55ac3998d6927" + "Hash": "c321cd99d56443dbffd1c9e673c0c1a2" }, "rex": { "Package": "rex", @@ -1086,7 +1163,7 @@ "Package": "rlang", "Version": "1.1.0", "Source": "Repository", - "Repository": "CRAN", + "Repository": "RSPM", "Requirements": [ "R", "utils" @@ -1097,7 +1174,7 @@ "Package": "rmarkdown", "Version": "2.17", "Source": "Repository", - "Repository": "CRAN", + "Repository": "RSPM", "Requirements": [ "R", "bslib", @@ -1120,7 +1197,7 @@ "Package": "roxygen2", "Version": "7.2.3", "Source": "Repository", - "Repository": "CRAN", + "Repository": "RSPM", "Requirements": [ "R", "R6", @@ -1257,14 +1334,14 @@ }, "staged.dependencies": { "Package": "staged.dependencies", - "Version": "0.2.8", + "Version": "0.3.1", "Source": "GitHub", "RemoteType": "github", "RemoteHost": "api.github.com", "RemoteUsername": "openpharma", "RemoteRepo": "staged.dependencies", "RemoteRef": "main", - "RemoteSha": "ce7c112ba3d75cf48e4dd6310b3140ab0ec3b486", + "RemoteSha": "1ab184a029bef8839a57bb6acd1c5c919cf1fd89", "Requirements": [ "desc", "devtools", @@ -1285,7 +1362,7 @@ "withr", "yaml" ], - "Hash": "89f2e1d1009601f58f64b7092abcc0d7" + "Hash": "ea298f9fb221a8c7ca4c9e55e9c29b48" }, "stringi": { "Package": "stringi", @@ -1317,7 +1394,7 @@ "Package": "styler", "Version": "1.9.1", "Source": "Repository", - "Repository": "CRAN", + "Repository": "RSPM", "Requirements": [ "R", "R.cache", @@ -1354,7 +1431,7 @@ "Package": "testthat", "Version": "3.1.7", "Source": "Repository", - "Repository": "CRAN", + "Repository": "RSPM", "Requirements": [ "R", "R6", @@ -1396,7 +1473,7 @@ "Package": "tibble", "Version": "3.2.0", "Source": "Repository", - "Repository": "CRAN", + "Repository": "RSPM", "Requirements": [ "R", "fansi", @@ -1437,7 +1514,7 @@ "Package": "tidyselect", "Version": "1.2.0", "Source": "Repository", - "Repository": "CRAN", + "Repository": "RSPM", "Requirements": [ "R", "cli", @@ -1504,7 +1581,7 @@ "Package": "vctrs", "Version": "0.6.0", "Source": "Repository", - "Repository": "CRAN", + "Repository": "RSPM", "Requirements": [ "R", "cli", @@ -1518,7 +1595,7 @@ "Package": "waldo", "Version": "0.4.0", "Source": "Repository", - "Repository": "CRAN", + "Repository": "RSPM", "Requirements": [ "cli", "diffobj", @@ -1555,7 +1632,7 @@ "Package": "xfun", "Version": "0.34", "Source": "Repository", - "Repository": "CRAN", + "Repository": "RSPM", "Requirements": [ "stats", "tools" diff --git a/renv/profiles/4.1/renv/settings.dcf b/renv/profiles/4.1/renv/settings.dcf deleted file mode 100644 index fd205f80..00000000 --- a/renv/profiles/4.1/renv/settings.dcf +++ /dev/null @@ -1,10 +0,0 @@ -bioconductor.version: -external.libraries: -ignored.packages: admiral, admiraldev, admiral.test, admiralci -package.dependency.fields: Imports, Depends, LinkingTo -r.version: -snapshot.type: implicit -use.cache: TRUE -vcs.ignore.cellar: TRUE -vcs.ignore.library: TRUE -vcs.ignore.local: TRUE diff --git a/renv/profiles/4.1/renv/settings.json b/renv/profiles/4.1/renv/settings.json new file mode 100644 index 00000000..4922677e --- /dev/null +++ b/renv/profiles/4.1/renv/settings.json @@ -0,0 +1,25 @@ +{ + "bioconductor.version": null, + "external.libraries": [], + "ignored.packages": [ + "admiral", + "admiraldev", + "admiral.test", + "admiralci", + "pharmaversesdtm" + ], + "package.dependency.fields": [ + "Imports", + "Depends", + "LinkingTo" + ], + "ppm.enabled": null, + "ppm.ignored.urls": [], + "r.version": null, + "snapshot.type": "custom", + "use.cache": true, + "vcs.ignore.cellar": true, + "vcs.ignore.library": true, + "vcs.ignore.local": true, + "vcs.manage.ignores": true +} diff --git a/renv/profiles/4.2/renv.lock b/renv/profiles/4.2/renv.lock index 0bb8fc56..7661270b 100644 --- a/renv/profiles/4.2/renv.lock +++ b/renv/profiles/4.2/renv.lock @@ -4,7 +4,7 @@ "Repositories": [ { "Name": "CRAN", - "URL": "https://cloud.r-project.org" + "URL": "https://packagemanager.posit.co/cran/latest" }, { "Name": "RSPM", @@ -192,6 +192,18 @@ ], "Hash": "9b2191ede20fa29828139b9900922e51" }, + "cellranger": { + "Package": "cellranger", + "Version": "1.1.0", + "Source": "Repository", + "Repository": "RSPM", + "Requirements": [ + "R", + "rematch", + "tibble" + ], + "Hash": "f61dbaec772ccd2e17705c1e872e9e7c" + }, "cli": { "Package": "cli", "Version": "3.6.0", @@ -223,6 +235,13 @@ ], "Hash": "c089a619a7fae175d149d89164f8c7d8" }, + "collections": { + "Package": "collections", + "Version": "0.3.7", + "Source": "Repository", + "Repository": "RSPM", + "Hash": "90a0eda114ab0bef170ddbf5ef0cd93f" + }, "commonmark": { "Package": "commonmark", "Version": "1.8.1", @@ -429,7 +448,7 @@ "Package": "dplyr", "Version": "1.1.1", "Source": "Repository", - "Repository": "CRAN", + "Repository": "RSPM", "Requirements": [ "R", "R6", @@ -749,6 +768,30 @@ ], "Hash": "8329a9bcc82943c8069104d4be3ee22d" }, + "languageserver": { + "Package": "languageserver", + "Version": "0.3.15", + "Source": "Repository", + "Repository": "RSPM", + "Requirements": [ + "R", + "R6", + "callr", + "collections", + "fs", + "jsonlite", + "lintr", + "parallel", + "roxygen2", + "stringi", + "styler", + "tools", + "utils", + "xml2", + "xmlparsedata" + ], + "Hash": "fbea0dd12b4f5dedbe3654e4b9cbbddc" + }, "later": { "Package": "later", "Version": "1.3.0", @@ -876,7 +919,7 @@ "Package": "pillar", "Version": "1.9.0", "Source": "Repository", - "Repository": "CRAN", + "Repository": "RSPM", "Requirements": [ "cli", "fansi", @@ -1007,6 +1050,19 @@ ], "Hash": "e9d21e79848e02e524bea6f5bd53e7e4" }, + "progress": { + "Package": "progress", + "Version": "1.2.2", + "Source": "Repository", + "Repository": "RSPM", + "Requirements": [ + "R6", + "crayon", + "hms", + "prettyunits" + ], + "Hash": "14dc9f7a3c91ebb14ec5bb9208a07061" + }, "promises": { "Package": "promises", "Version": "1.2.0.1", @@ -1091,6 +1147,28 @@ ], "Hash": "8f25ebe2ec38b1f2aef3b0d2ef76f6c4" }, + "readxl": { + "Package": "readxl", + "Version": "1.4.2", + "Source": "Repository", + "Repository": "RSPM", + "Requirements": [ + "R", + "cellranger", + "cpp11", + "progress", + "tibble", + "utils" + ], + "Hash": "2e6020b1399d95f947ed867045e9ca17" + }, + "rematch": { + "Package": "rematch", + "Version": "1.0.1", + "Source": "Repository", + "Repository": "RSPM", + "Hash": "c66b930d20bb6d858cd18e1cebcfae5c" + }, "rematch2": { "Package": "rematch2", "Version": "2.1.2", @@ -1103,7 +1181,7 @@ }, "remotes": { "Package": "remotes", - "Version": "2.4.2", + "Version": "2.4.2.1", "Source": "Repository", "Repository": "RSPM", "Requirements": [ @@ -1113,17 +1191,17 @@ "tools", "utils" ], - "Hash": "227045be9aee47e6dda9bb38ac870d67" + "Hash": "63d15047eb239f95160112bcadc4fcb9" }, "renv": { "Package": "renv", - "Version": "0.17.0", + "Version": "1.0.0", "Source": "Repository", "Repository": "RSPM", "Requirements": [ "utils" ], - "Hash": "ce3065fc1a0b64a859f55ac3998d6927" + "Hash": "c321cd99d56443dbffd1c9e673c0c1a2" }, "rex": { "Package": "rex", @@ -1173,7 +1251,7 @@ "Package": "roxygen2", "Version": "7.2.3", "Source": "Repository", - "Repository": "CRAN", + "Repository": "RSPM", "Requirements": [ "R", "R6", @@ -1310,14 +1388,14 @@ }, "staged.dependencies": { "Package": "staged.dependencies", - "Version": "0.2.8", + "Version": "0.3.1", "Source": "GitHub", "RemoteType": "github", "RemoteHost": "api.github.com", "RemoteUsername": "openpharma", "RemoteRepo": "staged.dependencies", "RemoteRef": "main", - "RemoteSha": "ce7c112ba3d75cf48e4dd6310b3140ab0ec3b486", + "RemoteSha": "1ab184a029bef8839a57bb6acd1c5c919cf1fd89", "Requirements": [ "desc", "devtools", @@ -1338,7 +1416,7 @@ "withr", "yaml" ], - "Hash": "89f2e1d1009601f58f64b7092abcc0d7" + "Hash": "ea298f9fb221a8c7ca4c9e55e9c29b48" }, "stringi": { "Package": "stringi", @@ -1587,7 +1665,7 @@ "Package": "vctrs", "Version": "0.6.0", "Source": "Repository", - "Repository": "CRAN", + "Repository": "RSPM", "Requirements": [ "R", "cli", diff --git a/renv/profiles/4.2/renv/settings.dcf b/renv/profiles/4.2/renv/settings.dcf deleted file mode 100644 index fd205f80..00000000 --- a/renv/profiles/4.2/renv/settings.dcf +++ /dev/null @@ -1,10 +0,0 @@ -bioconductor.version: -external.libraries: -ignored.packages: admiral, admiraldev, admiral.test, admiralci -package.dependency.fields: Imports, Depends, LinkingTo -r.version: -snapshot.type: implicit -use.cache: TRUE -vcs.ignore.cellar: TRUE -vcs.ignore.library: TRUE -vcs.ignore.local: TRUE diff --git a/renv/profiles/4.2/renv/settings.json b/renv/profiles/4.2/renv/settings.json new file mode 100644 index 00000000..4922677e --- /dev/null +++ b/renv/profiles/4.2/renv/settings.json @@ -0,0 +1,25 @@ +{ + "bioconductor.version": null, + "external.libraries": [], + "ignored.packages": [ + "admiral", + "admiraldev", + "admiral.test", + "admiralci", + "pharmaversesdtm" + ], + "package.dependency.fields": [ + "Imports", + "Depends", + "LinkingTo" + ], + "ppm.enabled": null, + "ppm.ignored.urls": [], + "r.version": null, + "snapshot.type": "custom", + "use.cache": true, + "vcs.ignore.cellar": true, + "vcs.ignore.library": true, + "vcs.ignore.local": true, + "vcs.manage.ignores": true +} diff --git a/renv/profiles/4.3/renv.lock b/renv/profiles/4.3/renv.lock index b875a5b8..1ce40dba 100644 --- a/renv/profiles/4.3/renv.lock +++ b/renv/profiles/4.3/renv.lock @@ -1,10 +1,10 @@ { "R": { - "Version": "4.3.0", + "Version": "4.3.1", "Repositories": [ { "Name": "CRAN", - "URL": "https://cloud.r-project.org" + "URL": "https://packagemanager.posit.co/cran/latest" }, { "Name": "RSPM", @@ -192,6 +192,18 @@ ], "Hash": "9b2191ede20fa29828139b9900922e51" }, + "cellranger": { + "Package": "cellranger", + "Version": "1.1.0", + "Source": "Repository", + "Repository": "RSPM", + "Requirements": [ + "R", + "rematch", + "tibble" + ], + "Hash": "f61dbaec772ccd2e17705c1e872e9e7c" + }, "cli": { "Package": "cli", "Version": "3.6.1", @@ -223,6 +235,13 @@ ], "Hash": "c089a619a7fae175d149d89164f8c7d8" }, + "collections": { + "Package": "collections", + "Version": "0.3.7", + "Source": "Repository", + "Repository": "RSPM", + "Hash": "90a0eda114ab0bef170ddbf5ef0cd93f" + }, "commonmark": { "Package": "commonmark", "Version": "1.9.0", @@ -748,6 +767,30 @@ ], "Hash": "8329a9bcc82943c8069104d4be3ee22d" }, + "languageserver": { + "Package": "languageserver", + "Version": "0.3.15", + "Source": "Repository", + "Repository": "RSPM", + "Requirements": [ + "R", + "R6", + "callr", + "collections", + "fs", + "jsonlite", + "lintr", + "parallel", + "roxygen2", + "stringi", + "styler", + "tools", + "utils", + "xml2", + "xmlparsedata" + ], + "Hash": "fbea0dd12b4f5dedbe3654e4b9cbbddc" + }, "later": { "Package": "later", "Version": "1.3.0", @@ -1006,6 +1049,19 @@ ], "Hash": "e9d21e79848e02e524bea6f5bd53e7e4" }, + "progress": { + "Package": "progress", + "Version": "1.2.2", + "Source": "Repository", + "Repository": "RSPM", + "Requirements": [ + "R6", + "crayon", + "hms", + "prettyunits" + ], + "Hash": "14dc9f7a3c91ebb14ec5bb9208a07061" + }, "promises": { "Package": "promises", "Version": "1.2.0.1", @@ -1090,6 +1146,28 @@ ], "Hash": "8f25ebe2ec38b1f2aef3b0d2ef76f6c4" }, + "readxl": { + "Package": "readxl", + "Version": "1.4.2", + "Source": "Repository", + "Repository": "RSPM", + "Requirements": [ + "R", + "cellranger", + "cpp11", + "progress", + "tibble", + "utils" + ], + "Hash": "2e6020b1399d95f947ed867045e9ca17" + }, + "rematch": { + "Package": "rematch", + "Version": "1.0.1", + "Source": "Repository", + "Repository": "RSPM", + "Hash": "c66b930d20bb6d858cd18e1cebcfae5c" + }, "rematch2": { "Package": "rematch2", "Version": "2.1.2", @@ -1102,7 +1180,7 @@ }, "remotes": { "Package": "remotes", - "Version": "2.4.2", + "Version": "2.4.2.1", "Source": "Repository", "Repository": "RSPM", "Requirements": [ @@ -1112,17 +1190,17 @@ "tools", "utils" ], - "Hash": "227045be9aee47e6dda9bb38ac870d67" + "Hash": "63d15047eb239f95160112bcadc4fcb9" }, "renv": { "Package": "renv", - "Version": "0.17.0", + "Version": "1.0.0", "Source": "Repository", "Repository": "RSPM", "Requirements": [ "utils" ], - "Hash": "ce3065fc1a0b64a859f55ac3998d6927" + "Hash": "c321cd99d56443dbffd1c9e673c0c1a2" }, "rex": { "Package": "rex", @@ -1173,7 +1251,7 @@ "Package": "roxygen2", "Version": "7.2.3", "Source": "Repository", - "Repository": "CRAN", + "Repository": "RSPM", "Requirements": [ "R", "R6", @@ -1310,14 +1388,14 @@ }, "staged.dependencies": { "Package": "staged.dependencies", - "Version": "0.2.8", + "Version": "0.3.1", "Source": "GitHub", "RemoteType": "github", "RemoteHost": "api.github.com", "RemoteUsername": "openpharma", "RemoteRepo": "staged.dependencies", "RemoteRef": "main", - "RemoteSha": "ce7c112ba3d75cf48e4dd6310b3140ab0ec3b486", + "RemoteSha": "1ab184a029bef8839a57bb6acd1c5c919cf1fd89", "Requirements": [ "desc", "devtools", @@ -1338,7 +1416,7 @@ "withr", "yaml" ], - "Hash": "89f2e1d1009601f58f64b7092abcc0d7" + "Hash": "ea298f9fb221a8c7ca4c9e55e9c29b48" }, "stringi": { "Package": "stringi", diff --git a/renv/profiles/4.3/renv/settings.dcf b/renv/profiles/4.3/renv/settings.dcf deleted file mode 100644 index fd205f80..00000000 --- a/renv/profiles/4.3/renv/settings.dcf +++ /dev/null @@ -1,10 +0,0 @@ -bioconductor.version: -external.libraries: -ignored.packages: admiral, admiraldev, admiral.test, admiralci -package.dependency.fields: Imports, Depends, LinkingTo -r.version: -snapshot.type: implicit -use.cache: TRUE -vcs.ignore.cellar: TRUE -vcs.ignore.library: TRUE -vcs.ignore.local: TRUE diff --git a/renv/profiles/4.3/renv/settings.json b/renv/profiles/4.3/renv/settings.json new file mode 100644 index 00000000..4922677e --- /dev/null +++ b/renv/profiles/4.3/renv/settings.json @@ -0,0 +1,25 @@ +{ + "bioconductor.version": null, + "external.libraries": [], + "ignored.packages": [ + "admiral", + "admiraldev", + "admiral.test", + "admiralci", + "pharmaversesdtm" + ], + "package.dependency.fields": [ + "Imports", + "Depends", + "LinkingTo" + ], + "ppm.enabled": null, + "ppm.ignored.urls": [], + "r.version": null, + "snapshot.type": "custom", + "use.cache": true, + "vcs.ignore.cellar": true, + "vcs.ignore.library": true, + "vcs.ignore.local": true, + "vcs.manage.ignores": true +} diff --git a/renv/settings.dcf b/renv/settings.dcf deleted file mode 100644 index fd205f80..00000000 --- a/renv/settings.dcf +++ /dev/null @@ -1,10 +0,0 @@ -bioconductor.version: -external.libraries: -ignored.packages: admiral, admiraldev, admiral.test, admiralci -package.dependency.fields: Imports, Depends, LinkingTo -r.version: -snapshot.type: implicit -use.cache: TRUE -vcs.ignore.cellar: TRUE -vcs.ignore.library: TRUE -vcs.ignore.local: TRUE diff --git a/renv/settings.json b/renv/settings.json new file mode 100644 index 00000000..1db5da30 --- /dev/null +++ b/renv/settings.json @@ -0,0 +1,24 @@ +{ + "bioconductor.version": null, + "external.libraries": [], + "ignored.packages": [ + "admiral", + "admiraldev", + "pharmaversesdtm", + "admiralci" + ], + "package.dependency.fields": [ + "Imports", + "Depends", + "LinkingTo" + ], + "ppm.enabled": null, + "ppm.ignored.urls": [], + "r.version": null, + "snapshot.type": "custom", + "use.cache": true, + "vcs.ignore.cellar": true, + "vcs.ignore.library": true, + "vcs.ignore.local": true, + "vcs.manage.ignores": true +} diff --git a/staged_dependencies.yaml b/staged_dependencies.yaml index 333435b8..af176a9d 100644 --- a/staged_dependencies.yaml +++ b/staged_dependencies.yaml @@ -3,6 +3,6 @@ current_repo: repo: pharmaverse/admiraldev host: https://github.com upstream_repos: - - repo: pharmaverse/admiral.test + - repo: pharmaverse/pharmaversesdtm host: https://github.com downstream_repos: diff --git a/tests/testthat/test-assertions.R b/tests/testthat/test-assertions.R index 0a0fd597..6f1208ff 100644 --- a/tests/testthat/test-assertions.R +++ b/tests/testthat/test-assertions.R @@ -1,29 +1,33 @@ # assert_has_variables ---- -## Test 1: error if a required variable is missing ---- -test_that("assert_has_variables Test 1: error if a required variable is missing", { +## Test 1: error if a required variable is missing (deprecation warn) ---- +test_that("assert_has_variables Test 1: error if a required variable is missing (deprecation warn)", { # nolint data <- tibble::tribble( ~USUBJID, "1" ) - expect_error( - assert_has_variables(data, "TRT01P"), - "Required variable `TRT01P` is missing." + expect_warning( + try(assert_has_variables(data, "TRT01P"), silent = TRUE), + class = "lifecycle_warning_deprecated" ) - expect_error( - assert_has_variables(admiral.test::admiral_dm, c("TRT01P", "AVAL")) + expect_warning( + try(assert_has_variables(pharmaversesdtm::dm, c("TRT01P", "AVAL")), silent = TRUE), + class = "lifecycle_warning_deprecated" ) }) -## Test 2: no error if a required variable exists ---- -test_that("assert_has_variables Test 2: no error if a required variable exists", { +## Test 2: no error if a required variable exists (deprecation warn) ---- +test_that("assert_has_variables Test 2: no error if a required variable exists (deprecation warn)", { # nolint data <- tibble::tribble( ~USUBJID, "1" ) - expect_error(assert_has_variables(data, "USUBJID"), NA) + expect_warning( + try(assert_has_variables(data, "USUBJID"), silent = TRUE), + class = "lifecycle_warning_deprecated" + ) }) # assert_filter_cond ---- @@ -186,7 +190,7 @@ test_that("assert_data_frame Test 13: error if required variables are missing", assert_data_frame(dataset, required_vars = exprs(STUDYID, USUBJID)) } - admiral_dm <- admiral.test::admiral_dm %>% select(-c(STUDYID, USUBJID)) + admiral_dm <- pharmaversesdtm::dm %>% select(-c(STUDYID, USUBJID)) expect_error( example_fun(admiral_dm) @@ -199,7 +203,7 @@ test_that("assert_data_frame Test 14: error if required variable is missing", { assert_data_frame(dataset, required_vars = exprs(STUDYID, USUBJID)) } - admiral_dm <- admiral.test::admiral_dm %>% select(-c(USUBJID)) + admiral_dm <- pharmaversesdtm::dm %>% select(-c(USUBJID)) expect_error( example_fun(admiral_dm) @@ -416,7 +420,7 @@ test_that("assert_symbol Test 25: `assert_symbol` does not throw an error if `ar v <- enexpr(var) } - admiral_dm <- admiral.test::admiral_dm + admiral_dm <- pharmaversesdtm::dm example_fun <- function(arg) { assert_symbol(arg) @@ -433,7 +437,7 @@ test_that("assert_symbol Test 25: `assert_symbol` does not throw an error if `ar ## Test 26: `assert_expr` does not throw an error if `arg` is an expression ---- test_that("assert_expr Test 26: `assert_expr` does not throw an error if `arg` is an expression", { expect_invisible( - assert_expr(var <- expr(admiral.test::admiral_dm)) + assert_expr(var <- expr(pharmaversesdtm::dm)) ) }) @@ -491,9 +495,9 @@ test_that("assert_vars Test 31: error if some elements of `arg` are not unquoted # assert_order_vars ---- ## Test 32: warn if assert_order_vars() is called ---- test_that("assert_order_vars Test 32: warn if assert_order_vars() is called", { - expect_warning( + expect_error( assert_order_vars(arg <- exprs(USUBJID)), - class = "lifecycle_warning_deprecated" + class = "lifecycle_error_deprecated" ) }) @@ -712,8 +716,8 @@ test_that("assert_named Test 51: error if no elements are named", { }) # assert_named_exprs ---- -## Test 52: error if `arg` is not a named list of expressions ---- -test_that("assert_named_exprs Test 52: error if `arg` is not a named list of expressions", { +## Test 52: error if `arg` is not a named list of expressions (deprecation warn) ---- +test_that("assert_named_exprs Test 52: error if `arg` is not a named list of expressions (deprecation warn)", { # nolint example_fun <- function(arg) { assert_named_exprs(arg) } @@ -721,33 +725,50 @@ test_that("assert_named_exprs Test 52: error if `arg` is not a named list of exp arg <- list("test") names(arg) <- c("") - expect_error(example_fun(5)) - expect_error(example_fun(admiral.test::admiral_dm)) - expect_error(example_fun(list(1, 2, TRUE))) - expect_error(example_fun(arg)) + expect_warning( + try(example_fun(5), silent = TRUE), + class = "lifecycle_warning_deprecated" + ) + expect_warning( + try(example_fun(pharmaversesdtm::dm), silent = TRUE), + class = "lifecycle_warning_deprecated" + ) + expect_warning( + try(example_fun(list(1, 2, TRUE)), silent = TRUE), + class = "lifecycle_warning_deprecated" + ) + expect_warning( + try(example_fun(arg), silent = TRUE), + class = "lifecycle_warning_deprecated" + ) }) -## Test 53: no error if `arg` is NULL and optional is TRUE ---- -test_that("assert_named_exprs Test 53: no error if `arg` is NULL and optional is TRUE", { +## Test 53: no error if `arg` is NULL and optional is TRUE (deprecation warn) ---- +test_that("assert_named_exprs Test 53: no error if `arg` is NULL and optional is TRUE (deprecation warn)", { # nolint example_fun <- function(arg) { assert_named_exprs(arg, optional = TRUE) } - expect_invisible( - example_fun(NULL) + expect_warning( + try(example_fun(NULL), silent = TRUE), + class = "lifecycle_warning_deprecated" ) }) -## Test 54: no error if `arg` is a named list of expressions ---- -test_that("assert_named_exprs Test 54: no error if `arg` is a named list of expressions", { +## Test 54: no error if `arg` is a named list of expressions (deprecation warn) ---- +test_that("assert_named_exprs Test 54: no error if `arg` is a named list of expressions (deprecation warn)", { # nolint example_fun <- function(arg) { assert_named_exprs(arg) } - expect_invisible( - example_fun( - rlang::exprs() - ) + expect_warning( + try( + example_fun( + rlang::exprs() + ), + silent = TRUE + ), + class = "lifecycle_warning_deprecated" ) }) @@ -799,23 +820,32 @@ test_that("assert_function Test 58: error if `params` is missing with no defau # assert_function_param ---- -## Test 59: no error if `arg` is a parameter of a function ---- -test_that("assert_function_param Test 59: no error if `arg` is a parameter of a function", { +## Test 59: no error if `arg` is a parameter of a function (deprecation warn) ---- +test_that("assert_function_param Test 59: no error if `arg` is a parameter of a function (deprecation warn)", { # nolint hello <- function(name) { print(sprintf("Hello %s", name)) } - expect_invisible(assert_function_param("hello", "name")) + expect_warning( + try(assert_function_param("hello", params = "name"), silent = TRUE), + class = "lifecycle_warning_deprecated" + ) }) -## Test 60: error if expected function parameters are missing ---- -test_that("assert_function_param Test 60: error if expected function parameters are missing", { +## Test 60: error if expected function parameters are missing (deprecation warn) ---- +test_that("assert_function_param Test 60: error if expected function parameters are missing (deprecation warn)", { # nolint hello <- function(name) { print(sprintf("Hello %s", name)) } - expect_error(assert_function_param("hello", "surname")) - expect_error(assert_function_param("hello", params = c("surname", "firstname"))) + expect_warning( + try(assert_function_param("hello", "surname"), silent = TRUE), + class = "lifecycle_warning_deprecated" + ) + expect_warning( + try(assert_function_param("hello", params = c("surname", "firstname")), silent = TRUE), + class = "lifecycle_warning_deprecated" + ) }) # assert_unit ---- @@ -1058,7 +1088,7 @@ test_that("assert_list_element Test 80: error if the elements do not fulfill the ## Test 81: error if there is a one to many mapping ---- test_that("assert_one_to_one Test 81: error if there is a one to many mapping", { expect_error( - assert_one_to_one(admiral.test::admiral_dm, exprs(DOMAIN), exprs(USUBJID)) + assert_one_to_one(pharmaversesdtm::dm, exprs(DOMAIN), exprs(USUBJID)) ) admiraldev_environment$one_to_many <- NULL }) @@ -1066,7 +1096,7 @@ test_that("assert_one_to_one Test 81: error if there is a one to many mapping", ## Test 82: error if there is a many to one mapping ---- test_that("assert_one_to_one Test 82: error if there is a many to one mapping", { expect_error( - assert_one_to_one(admiral.test::admiral_dm, exprs(USUBJID), exprs(DOMAIN)) + assert_one_to_one(pharmaversesdtm::dm, exprs(USUBJID), exprs(DOMAIN)) ) admiraldev_environment$many_to_one <- NULL }) diff --git a/tests/testthat/test-datasets.R b/tests/testthat/test-datasets.R deleted file mode 100644 index 563a1b4f..00000000 --- a/tests/testthat/test-datasets.R +++ /dev/null @@ -1,13 +0,0 @@ -# get_dataset ---- -## Test 1: get_dataset works ---- -test_that("get_dataset Test 1: get_dataset works", { - expect_equal(NULL, get_dataset("one_to_many")) -}) - -## Test 2: get_dataset gives error works ---- -test_that("get_dataset Test 2: get_dataset works", { - expect_error( - get_dataset("test"), - "`name` must be one of 'one_to_many' or 'many_to_one' but is 'test'" - ) -}) diff --git a/tests/testthat/test-dev_utilities.R b/tests/testthat/test-dev_utilities.R index 0c83d82f..b440ad8f 100644 --- a/tests/testthat/test-dev_utilities.R +++ b/tests/testthat/test-dev_utilities.R @@ -79,9 +79,9 @@ test_that("vars2chr Test 8: returns character vector", { ## Test 9: warning if quosures argument is used ---- test_that("vars2chr Test 9: warning if quosures argument is used", { - expect_warning( + expect_error( vars2chr(quosures = rlang::quos(STUDYID, USUBJID)), - class = "lifecycle_warning_deprecated" + class = "lifecycle_error_deprecated" ) }) diff --git a/tests/testthat/test-get.R b/tests/testthat/test-get.R index 165497a0..1f53a726 100644 --- a/tests/testthat/test-get.R +++ b/tests/testthat/test-get.R @@ -63,9 +63,9 @@ test_that("get_source_vars Test 5: NULL returns NULL", { ## Test 6: warning if quosures argument is used ---- test_that("get_source_vars Test 6: warning if quosures argument is used", { - expect_warning( + expect_error( get_source_vars(quosures = rlang::quos(DTHDOM = "AE", DTHSEQ = AESEQ)), - class = "lifecycle_warning_deprecated" + class = "lifecycle_error_deprecated" ) }) ## Test 7: no source vars returns NULL ---- @@ -75,3 +75,17 @@ test_that("get_source_vars Test 7: no source vars returns NULL", { NULL ) }) + +# get_dataset ---- +## Test 8: get_dataset works ---- +test_that("get_dataset Test 8: get_dataset works", { + expect_equal(NULL, get_dataset("one_to_many")) +}) + +## Test 9: get_dataset works ---- +test_that("get_dataset Test 9: get_dataset works", { + expect_error( + get_dataset("test"), + "`name` must be one of 'one_to_many' or 'many_to_one' but is 'test'" + ) +}) diff --git a/tests/testthat/test-quo.R b/tests/testthat/test-quo.R index 579cd728..fdeacc4e 100644 --- a/tests/testthat/test-quo.R +++ b/tests/testthat/test-quo.R @@ -1,40 +1,6 @@ -# quo_c ---- -## Test 1: issues deprecation warning ---- -test_that("quo_c Test 1: issues deprecation warning", { - expect_error( - quo_c(quo(USUBJID), quo(STUDYID)), - class = "lifecycle_error_deprecated" - ) -}) - -## Test 2: `quo_c` works in concatenating and indexing quosures ---- -test_that("quo_c Test 2: `quo_c` works in concatenating and indexing quosures", { - x <- quo(USUBJID) - y <- quo(STUDYID) - - expect_error( - quo_c(x, NULL, y)[[1]], - class = "lifecycle_error_deprecated" - ) - expect_error( - object = quo_c(x, NULL, y)[[2]], - class = "lifecycle_error_deprecated" - ) -}) - -## Test 3: `quo_c` returns error if non-quosures are input ---- -test_that("quo_c Test 3: `quo_c` returns error if non-quosures are input", { - USUBJID <- "01-701-1015" # nolint - - expect_error( - object = quo_c(quo(USUBJID), USUBJID), - class = "lifecycle_error_deprecated" - ) -}) - # expr_c ---- -## Test 4: concatenating and indexing expressions ---- -test_that("expr_c Test 4: concatenating and indexing expressions", { +## Test 1: concatenating and indexing expressions ---- +test_that("expr_c Test 1: concatenating and indexing expressions", { x <- expr(USUBJID) y <- expr(STUDYID) @@ -48,54 +14,32 @@ test_that("expr_c Test 4: concatenating and indexing expressions", { ) }) -## Test 5: concatenating named list of expressions ---- -test_that("expr_c Test 5: concatenating named list of expressions", { +## Test 2: concatenating named list of expressions ---- +test_that("expr_c Test 2: concatenating named list of expressions", { expect_equal( expected = exprs(PARAMCD = "DOSE", PARAMN = 1), object = expr_c(exprs(PARAMCD = "DOSE", PARAMN = 1, NULL)) ) }) -## Test 6: concatenating list and single expression ---- -test_that("expr_c Test 6: concatenating list and single expression", { +## Test 3: concatenating list and single expression ---- +test_that("expr_c Test 3: concatenating list and single expression", { expect_equal( expected = exprs(PARAMCD, PARAM, AVAL), object = expr_c(exprs(PARAMCD, PARAM), expr(AVAL)) ) }) -## Test 7: returns error if non-expressions are input ---- -test_that("expr_c Test 7: returns error if non-expressions are input", { +## Test 4: returns error if non-expressions are input ---- +test_that("expr_c Test 4: returns error if non-expressions are input", { expect_error( object = expr_c(expr(USUBJID), mean) ) }) -# quo_not_missing ---- -## Test 8: issues deprecation warning ---- -test_that("quo_not_missing Test 8: issues deprecation warning", { - test_fun <- function(x) { - x <- enquo(x) - !isTRUE(quo_not_missing(x)) - } - expect_error( - test_fun(my_variable), - class = "lifecycle_error_deprecated" - ) -}) - -## Test 9: `quo_not_missing` throws an Error if missing argument ---- -test_that("quo_not_missing Test 9: `quo_not_missing` throws an Error if missing argument", { - test_fun <- function(x) { - x <- enquo(x) - isTrue(quo_not_missing(x)) - } - expect_error(test_fun()) # missing argument -> throws error -}) - # replace_values_by_names ---- -## Test 10: names of expressions replace value ---- -test_that("replace_values_by_names Test 10: names of expressions replace value", { +## Test 5: names of expressions replace value ---- +test_that("replace_values_by_names Test 5: names of expressions replace value", { z <- exprs(USUBJID, STUDYID) z_noname <- replace_values_by_names(z) @@ -122,8 +66,8 @@ test_that("replace_values_by_names Test 10: names of expressions replace value", ) }) -## Test 11: names of argument is NULL ---- -test_that("replace_values_by_names Test 11: names of argument is NULL", { +## Test 6: names of argument is NULL ---- +test_that("replace_values_by_names Test 6: names of argument is NULL", { z <- exprs(USUBJID, STUDYID) names(z) <- NULL @@ -133,26 +77,17 @@ test_that("replace_values_by_names Test 11: names of argument is NULL", { ) }) -## Test 12: warning if quosures argument is used ---- -test_that("replace_values_by_names Test 12: warning if quosures argument is used", { +## Test 7: warning if quosures argument is used ---- +test_that("replace_values_by_names Test 7: warning if quosures argument is used", { expect_error( replace_values_by_names(quosures = rlang::quos(STUDYID, USUBJID)), class = "lifecycle_error_deprecated" ) }) -# replace_symbol_in_quo ---- -## Test 13: error if called ---- -test_that("replace_symbol_in_quo Test 13: error if called", { - expect_error( - replace_symbol_in_quo(), - class = "lifecycle_error_deprecated" - ) -}) - # replace_symbol_in_expr ---- -## Test 14: symbol is replaced ---- -test_that("replace_symbol_in_expr Test 14: symbol is replaced", { +## Test 8: symbol is replaced ---- +test_that("replace_symbol_in_expr Test 8: symbol is replaced", { expect_equal( expected = expr(AVAL.join), object = replace_symbol_in_expr( @@ -163,8 +98,8 @@ test_that("replace_symbol_in_expr Test 14: symbol is replaced", { ) }) -## Test 15: partial match is not replaced ---- -test_that("replace_symbol_in_expr Test 15: partial match is not replaced", { +## Test 9: partial match is not replaced ---- +test_that("replace_symbol_in_expr Test 9: partial match is not replaced", { expect_equal( expected = expr(AVALC), object = replace_symbol_in_expr( @@ -175,8 +110,8 @@ test_that("replace_symbol_in_expr Test 15: partial match is not replaced", { ) }) -## Test 16: symbol in expression is replaced ---- -test_that("replace_symbol_in_expr Test 16: symbol in expression is replaced", { +## Test 10: symbol in expression is replaced ---- +test_that("replace_symbol_in_expr Test 10: symbol in expression is replaced", { expect_equal( expected = expr(desc(AVAL.join)), object = replace_symbol_in_expr( @@ -188,8 +123,8 @@ test_that("replace_symbol_in_expr Test 16: symbol in expression is replaced", { }) # add_suffix_to_vars ---- -## Test 17: with single variable ---- -test_that("add_suffix_to_vars Test 17: with single variable", { +## Test 11: with single variable ---- +test_that("add_suffix_to_vars Test 11: with single variable", { expect_equal( expected = exprs(ADT, desc(AVAL.join), AVALC), object = add_suffix_to_vars( @@ -200,8 +135,8 @@ test_that("add_suffix_to_vars Test 17: with single variable", { ) }) -## Test 18: with more than one variable ---- -test_that("add_suffix_to_vars Test 18: with more than one variable", { +## Test 12: with more than one variable ---- +test_that("add_suffix_to_vars Test 12: with more than one variable", { expect_equal( expected = exprs(ADT, desc(AVAL.join), AVALC.join), object = add_suffix_to_vars( diff --git a/tests/testthat/test-tmp_vars.R b/tests/testthat/test-tmp_vars.R index 321ad6c1..eae38569 100644 --- a/tests/testthat/test-tmp_vars.R +++ b/tests/testthat/test-tmp_vars.R @@ -1,4 +1,4 @@ -dm <- select(admiral.test::admiral_dm, USUBJID) +dm <- select(pharmaversesdtm::dm, USUBJID) # get_new_tmp_var ---- ## Test 1: creating temporary variables works ---- diff --git a/tests/testthat/test-warnings.R b/tests/testthat/test-warnings.R index 23df263e..a0288440 100644 --- a/tests/testthat/test-warnings.R +++ b/tests/testthat/test-warnings.R @@ -1,7 +1,7 @@ # warn_if_vars_exist ---- ## Test 1: warning if a variable already exists in the input dataset ---- test_that("warn_if_vars_exist Test 1: warning if a variable already exists in the input dataset", { - dm <- admiral.test::admiral_dm + dm <- pharmaversesdtm::dm expect_warning( warn_if_vars_exist(dm, "AGE"), @@ -21,11 +21,12 @@ test_that("warn_if_vars_exist Test 1: warning if a variable already exists in th ) }) -# warn_if_invalud_dtc ---- +# warn_if_invalid_dtc ---- ## Test 2: Warning if vector contains unknown datetime format ---- -test_that("warn_if_invalud_dtc Test 2: Warning if vector contains unknown datetime format", { +test_that("warn_if_invalid_dtc Test 2: Warning if vector contains unknown datetime format", { expect_warning( - warn_if_invalid_dtc(dtc = "20210406T12:30:30") + warn_if_invalid_dtc(dtc = "20210406T12:30:30"), + "Dataset contains incorrect datetime format:" ) }) diff --git a/vignettes/dummy_issue.png b/vignettes/dummy_issue.png new file mode 100644 index 00000000..645ea663 Binary files /dev/null and b/vignettes/dummy_issue.png differ diff --git a/vignettes/git_usage.Rmd b/vignettes/git_usage.Rmd index df704911..fc54e79f 100644 --- a/vignettes/git_usage.Rmd +++ b/vignettes/git_usage.Rmd @@ -20,18 +20,17 @@ knitr::opts_chunk$set( # Introduction -This article will give you an overview of how the `{admiral}` project is utilizing the version-control software `git` and the website GitHub while working with RStudio. We will go over the primary branches that house the source code for the `{admiral}` project as well as how we use **Feature** branches to address **Issues**. Issues can range from bugs to enhancement that have been identified or requested by developers, users or testers. We also provide the bare minimum of `git` commands needed to get up and running. Please refer to the [Resource](#github_resources) section for more in-depth guidance on using `git` and GitHub. Finally, we discuss the release process and schedule for `{admiral}`. +This article will give you an overview of how the `{admiral}` project is utilizing the version-control software `git` and the website GitHub while working with RStudio. We will go over the primary branches that house the source code for the `{admiral}` project as well as how we use **Feature** branches to address **Issues**. Issues can range from bugs to enhancements that have been identified or requested by developers, users or testers. We also provide the bare minimum of `git` commands needed to get up and running. Please refer to the [Resource](#github_resources) section for more in-depth guidance on using `git` and GitHub. # Branches - The `main` branch contains the latest **released** version and should not be used for development. You can find the released versions [here](https://GitHub.com/pharmaverse/admiral/releases) -- The `devel` branch contains the latest development version of the package. You will always be branching off and pulling into the `devel` branch. +- The `devel` branch contains the latest development version of the package. You will always be branching off and pulling into the `devel` branch. This is set as the default branch on GitHub. - The `gh-pages` branches contains the code used to render this website you are looking at right now! - The `patch` branch is reserved for special hot fixes to address bugs. More info in [Hot Fix Release](release_strategy.html#hot-fix-release) -- The `pre-release` branch is used to as an intermediate step to releasing the package from `main`. More info in [Quarterly Release section](release_strategy.html#quarterly-release) -- The `main`, `devel`, `gh-pages`, `patch` and `pre-release` branches are under protection. If you try and push changes to these branches you will get an error unless you are an administrator. +- The `main`, `devel`, `gh-pages`, `patch` branches are under protection. If you try and push changes to these branches you will get an error unless you are an administrator. -- **Feature** branches are where actual development related to a specific issue happens. Feature branches are merged into `devel` once a pull request is merged. Check out the [Pull Request Review Guidance](pr_review_guidance.html). +- **Feature** branches are where actual development related to a specific issue happens. Feature branches are merged into `devel` once a pull request is merged. Check out the [Pull Request Review Guidance](pr_review_guidance.html) for more guidance on merging into `devel`. # Working with Feature Branches @@ -40,13 +39,13 @@ Feature Branches are where most developers will work when addressing Issues. ## Implementing an Issue -Each feature branch must be related to an issue. +Each feature branch must be related to an issue. We encourage new developers to only work on one issue at a time. ### Naming Branches The name of the branch must be prefixed with the issue number, followed by a short but meaningful description and the `@` suffix. The latter would be `@devel` in most cases. As an example, given an issue #94 "Program function to derive `LSTALVDT`", the branch name would be `94_derive_var_lstalvdt@devel`. -The `@` suffix is used in our CI/CD pipelines, e.g. when running `R CMD check`. It ensures that {admiral}'s upstream dependencies such as {admiral.test} are installed from the specified target branch. So when the target branch is set to `@devel` the upstream dependencies will be installed from the `devel` branch rather than installing the latest released version. This ensures that we test the development version of {admiral} against the development versions of its upstream dependencies. That way all packages are kept in sync. +The `@` suffix is used in our CI/CD pipelines, e.g. when running `R CMD check`. It ensures that `{admiral}`'s dependencies such as `{pharmaversesdtm}` and `{admiraldev}` are installed from the specified target branch. So when the target branch is set to `@devel` the dependencies will be installed from those package's respective `devel` branches rather than installing the latest released version. This ensures that we test the development version of `{admiral}` against the development versions of its dependencies. That way all packages are kept in sync. ### Create a New Feature Branch from the Terminal (from `devel`) @@ -60,7 +59,7 @@ You can also create a feature branch in GitHub. - Switch to the `devel` branch - Type in your new feature branch name -- Click Create branch: `` from `devel` +- Click Create branch: `@devel` from `devel` - Be Sure to Pull down newly created branch into RStudio ```{r, echo = FALSE} @@ -82,12 +81,34 @@ You can also make use of the Git Tab within RStudio to commit your changes. A be knitr::include_graphics("github_committ.png", dpi = 144) ``` +### Commit Message Etiquette + +We require developers to **insert the issue number** into each commit message. Placing the issue number in your commit message allows reviewers to quickly find discussion surrounding your issue. When pushed to GitHub the issue number will be hyperlinked to the issue tracker, a powerful tool for discussion and traceability, which we think is valuable in a highly regulated industry like Pharma. + +Below are styles of commit messaging permitted: + +### Style 1: + +* `feat: #94 skeleton of function developed` +* `chore: #94 styler and lintr update` +* `docs: #94 parameters and details sections compelted` + +### Style 2: + +* `#94 skeleton of function developed` +* `#94 styler and lintr update` +* `#94 parameters and details sections compelted` + +### Style 3: + +* `skeleton of function developed (#94)` +* `styler and lintr update (#94)` +* `parameters and details sections compelted (#94)` -**NOTE:** Placing the issue number in your commit message allows new developers to quickly find discussion surrounding your issue. When pushed to GitHub the issue number will hyperlink to the issue tracker. A powerful tool for discussion. ## Pull request -We recommend a thorough read through of the articles, [Pull Request Review Guidance](pr_review_guidance.html) and the [Programming Strategy](programming_strategy.html) for in-depth discussions on a doing a proper Pull Request. Pull Request authors will benefit from shorter review times by closely following the guidance provided in those two articles. Below we discuss some simple `git` commands in the terminal and on GitHub for doing a Pull Request. We recommend doing the Pull Request in GitHub only and not through the terminal. +We recommend a thorough read through of the articles, [Pull Request Review Guidance](pr_review_guidance.html) and the [Programming Strategy](programming_strategy.html) for in-depth discussions on a doing a proper Pull Request.Pull Request authors will benefit from shorter review times by closely following the guidance provided in those two articles. Below we discuss some simple `git` commands in the terminal and on GitHub for doing a Pull Request. We recommend doing the Pull Request in GitHub only and not through the terminal. Once all changes are committed, push the updated branch to GitHub: `git push -u origin ` @@ -95,13 +116,13 @@ Once all changes are committed, push the updated branch to GitHub: In GitHub, under **Pull requests**, the user will either have a "Compare and pull request" button and/or a "Create Pull Request". The first button will be created for you if GitHub detects recent changes you have made. The branch to merge with must be the `devel` branch (base = `devel`) and the compare branch is the new branch to merge - as shown in the below picture. Please **pay close attention** to the branch you are merging into! The issue must be linked to the pull request in the "Development" field of the -Pull Request. +Pull Request. In most cases, this will linkage will automatically close the issue and move to the Done column on our project board. ```{r, echo = FALSE} knitr::include_graphics("github_linked_issues_dark.png", dpi = 144) ``` -Once you have completed the Pull Request you will see all committed changes are then available for the reviewer. A reviewer must be specified in the Pull Request. It is recommended to write a brief summary to your reviewers so they can quickly come up to speed on your Pull Request. Pictures are nice too, which are easy to do in GitHub! Use any Screen Capture software and Copy and Paste into your summary. +Once you have completed the Pull Request you will see all committed changes are then available for the reviewer. A reviewer must be specified in the Pull Request. It is recommended to write a brief summary to your reviewers so they can quickly come up to speed on your Pull Request. Images of your updates are nice too, which are easy to do in GitHub! Use any Screen Capture software and Copy and Paste into your summary. ```{r, echo = FALSE} knitr::include_graphics("github_create_pr.png", dpi = 144) @@ -120,10 +141,7 @@ before the Pull Request is merged Once the review is completed, the reviewer will merge the Pull Request and the feature branch will automatically be deleted. -After merging the Pull Request the corresponding issue must be moved to the -"Done" column on the "admiral core board" by the developer. **The issue -must not be closed**. It will be closed automatically once the `devel` branch is -merged into the `main` branch. +After merging the Pull Request please check that corresponding has been moved to the done column on the Project Board. Also, please make sure that the issue has closed. ```{r, echo = FALSE} diff --git a/vignettes/package_extensions.Rmd b/vignettes/package_extensions.Rmd new file mode 100644 index 00000000..99b2752e --- /dev/null +++ b/vignettes/package_extensions.Rmd @@ -0,0 +1,114 @@ +--- +title: "Package Extensions" +output: + rmarkdown::html_vignette + +vignette: > + %\VignetteIndexEntry{Package Extensions} + %\VignetteEngine{knitr::rmarkdown} + +--- + +```{css, echo = FALSE} +.github-button { + display: inline-block; + padding: 2px 5px; + background-color: #e5e5e5; + color: #333; + border: 0px solid #ccc; + border-radius: 20px; + font-size: 1em; + margin: 0 0px; +} + +.github-button.firstissue { + background-color: #7057FF; + color: #fff; +} + +.github-button.helpwanted { + background-color: #008672; + color: #fff; +} + +``` + + +```{r setup, include = FALSE} +knitr::opts_chunk$set( + collapse = TRUE, + comment = "#>" +) +``` + +## Introduction + +`{admiral}` is made up of a family of packages and we foresee this only growing over time to cover more specific areas such as TA (Therapeutic Area) package extensions, with a wider range of companies and individuals getting on board to join development efforts. This step-by-step guidance talks through our recommendations on how new development teams would go about creating such package extensions. It is critical that this guidance is followed, as our users need to feel a consistent experience when working across `{admiral}` packages. If an `{admiral}` package extension doesn't follow these conventions then we wouldn't include it under pharmaverse and as part of the `{admiral}` family. + +## Step-by-step Guidance to Create a Package Extension +_Note: The ordering numbers below are suggested but don't all need to strictly be followed in this sequence._ + +1. Raise the need for a new `{admiral}` package extension on the `{admiral}` [Slack channel](https://app.slack.com/client/T028PB489D3/C02M8KN8269), or directly with the `{admiral}` package maintainer. The naming convention needs to be `{admiralxxx}` and we request that the scope is not targeted overly narrow, for example instead of a package extension for HIV we'd prefer one across virology. Otherwise the number of packages may become unmanageable. + +1. Once agreed, reach out to other company contacts working in similar areas to see if a collaborative development can be achieved. _Our recommendation here is always to target at least 2 companies to start so that any implementation remains robust and we protect from going down a company-specific route. However, consider that if more than 4 or 5 companies get involved too early it may slow down decision-making._ + +1. From the companies that agree to co-develop, identify a lead from each. One company should act as the driver for the overall package extension and put forward a product owner and technical lead who ultimately have final say on any contentious decisions. The product owner would cover project decisions (e.g. around scope and priorities), whereas the technical lead would cover technical decisions (e.g. around design and implementation). _The technical lead should either: a) already be significantly involved in the `{admiral}` core development team as a developer/contributor, or b) join the core development team simultaneously._ This is so as to ensure that the design is kept true to the manifesto and of consistent style and quality with respect to `{admiral}` standards. + +1. Agree on a charter and expectations of each company, e.g. we usually ask for at least 3 developers with at least 25% capacity and a mix of R, GitHub and TA experience. Within the charter make sure the scope and timelines are clear. _It is important here not to try to boil the ocean. Focus first on the very common endpoints required as a foundation and then the package can build up from here via contributions from both the co-development companies and also the wider across-industry admiral community. If useful, the `{admiralonco}` charter could be shared as a guide._ + +1. Each company should start to identify the required developer resources. Then each developer is required to complete the `{admiral`} [dummy issue for onboarding](https://github.com/pharmaverse/admiral/issues/1839), as well as reading up on the [admiraldev documentation](https://pharmaverse.github.io/admiraldev/devel/index.html), - especially the developer guides, which all need to be followed for package extensions. +![Dummy issue for new developers](https://github.com/pharmaverse/admiraldev/raw/devel/vignettes/dummy_issue.png){width=100%} + +1. Optionally it can be useful to host a kick-off meeting to decide how the team will work, for which we recommend agile/scrum practices. + +1. Set up a "admiralxxx_dev" channel on Slack to add all team members to for informal team chat, and agree a way to share working documents across the co-development team. We recommend to use a new folder on the pharmaverse MS Teams - Michael Rimler (michael.s.rimler@gsk.com) could help with this as our rep on the PHUSE board. + +1. A useful starter development activity could be to look into `{pharmaversesdtm}` to check that the test data there is sufficient for your TA needs, e.g. for `{admiralonco}` we had to generate new test data for SDTM domains such as RS and TU. Note that no personal data should be used here (even if anonymized) and it is important to keep any data generated in-line with the CDISC pilot data we use here, i.e. use same USUBJIDs as DM etc. + +1. Optionally draft, agree and sign a collaboration agreement if the collaborating companies so wish, as this could be useful for protecting secondary IP such as company standard specifications that may be shared within the team. An example is stored [here](https://github.com/pharmaverse/pharmaverse/blob/main/content/contribute/Pharmaverse%20Collaborative%20Agreement%20(template).docx), but work with your Legal teams as required. + +1. Share company-specific implementations and specifications to be able to harmonize into your design strategy for the package extension. _Here it is important to remain pragmatic and consider a higher perspective than any one company. Engage your company standards representatives and where you find discrepancies across company approaches then question if you really need to be doing things differently here (do health authorities or patients benefit at all if you do?). Also consider that we always expect a level of company-specifics to be covered in the internal company package extensions._ + +1. Set up a new public GitHub repo under the [pharmaverse org](https://github.com/pharmaverse) using [admiraltemplate](https://github.com/pharmaverse/admiraltemplate) - this includes set-up pieces (such as CI/CD checks and issue/PR templates) that will enable your package to stay consistent with others in the admiral family, as well as the same core package dependencies and versions. See the `{admiraltemplate}` [Quick Start Guide](https://pharmaverse.github.io/admiraltemplate/cran-release/#quick-start-guide-for-template) _Note that this step requires org member access which could be granted by of the pharmaverse council reps, who are admins for this org. Also you are free to add additional package dependencies as needed assuming only reliable packages are used, but they must not depend on newer versions of other packages (always reply "no" if updates are suggested during installation)._ + + +1. Once the repo is available the technical lead could be granted admin access to this repo and then could set up a GitHub team with the same name as the package extension to assign required access for all other co-development team members. Most will only require write access, but you may choose to give the other leads admin access as well so that never a bottle-neck waiting on one person. + +1. Update the template license file in your repo by adding the co-development company names in place of Roche & GSK - for `{admiral}` package extensions we use Apache 2.0, which is our preferred permissive license. Agree with the co-development companies any required extra wording for the copyright/IP section. + +1. Set up a project board, such as [this](https://github.com/orgs/pharmaverse/projects/12), to help manage your backlog. +![admiral core project board](https://github.com/pharmaverse/admiraldev/raw/devel/vignettes/project_board.png){width=100%} + +1. Assuming you work under agile/scrum, then create a product backlog, prioritize and make a sprint plan. + +1. The intention is always to re-use as much as possible from `{admiral}` core package. If you find anything additional needed for the package extension, you should first question whether it might be a common need for other TAs and if so consider instead raising an issue to `{admiral}` core. When designing new functions always try to stay aligned with the [Programming Strategy](https://pharmaverse.github.io/admiraldev/devel/articles/programming_strategy.html). + +1. Start development of your foundational first release 0.1.0. Follow a consistent [Development Process](https://pharmaverse.github.io/admiraldev/devel/articles/development_process.html) to `{admiral}`. + +1. Line up testers from your companies and others and set expectations around when you believe a stable version would be available for user testing. You can use the admiral Slack community to raise interest to get involved. + +1. Add a pharmaverse badge to your README: https://pharmaverse.org/contribute/badges/ - needs support from a pharmaverse council rep.\ +[](https://pharmaverse.org/contribute/badges/) + +1. Raise an `{admiral}` repo issue to ensure your package extension site is linked from the core `{admiral}` site here [here](https://pharmaverse.github.io/admiral/cran-release/).` + +1. It is important that the `{admiral}` family of packages keep to a similar release schedule and cadence, in order to ease adoption by our users and to give clear expectations. The `{admiral}` core package cadence of releases is one every quarter on a fixed schedule (every first Monday of the last month of a quarter - March, June, September, December). The core package will set the release schedule for the package extensions to follow, i.e. once `{admiral}` releases we'd expect package extension releases targeted within a 2 week window. These releases are communicated via our Slack channel as well as at our quarterly user community meetings. + +1. Once you are happy your package extension has been well tested and is at a sufficient state then make a submission to CRAN. The technical lead should be named as maintainer. After the CRAN release, you should advertise this via Slack & LinkedIn. + + +1. Plan any future further enhancements and make issues. When your team feels ready you can open up to development contributions for these from the wider community - see [this page](https://pharmaverse.github.io/admiral/cran-release/). Please use the good first issue (ideal for new starters) & help wanted (ideal for more experienced contributors) issue labels. + +**Note**: the core `{admiral}` team will carry out periodic reviews of of the extension package contents to ensure nothing is duplicated and ensure standards and best practices are followed. The frequency of these reviews is to be agreed upon by the technical leads of the core and extension packages. + +## Lessons Learned + +These are some of the lessons learned from previous package extensions: + +* Since ADaM is conceived as TA-agnostic, and TA standards can widely differ across companies, TA package extensions shouldn't contain many new functions. That is, most functionality required to create and ADaM should be present in `{admiral}`, with localized and limited exceptions for truly TA-specific variables/endpoints. As such, _the R folder in package extensions should be relatively lean_! + +* Connected to the above, a package extension is more than just R functions - it is also vignettes examples and template programs. In fact, these are just as important as the R functions itself, because that is what the users will turn to for guidance. + +* Making sure the package is always up-to-date with respect to new `{admiral}` releases (e.g. due to the deprecation of functions) is a crucial task. Maintaining the package long-term is the only way to ensure its success. + +* _Beware of developing just for the sake of developing!_ You may find that you reach a point of stasis in your extension package journey, where there is not much need for new development. In that case, it vital to avoid working on tangential tasks. Instead, the focus should be on ensuring that existing is as fit-for-purpose as possible. diff --git a/vignettes/pr_review_guidance.Rmd b/vignettes/pr_review_guidance.Rmd index da7c8390..248936a5 100644 --- a/vignettes/pr_review_guidance.Rmd +++ b/vignettes/pr_review_guidance.Rmd @@ -19,15 +19,15 @@ knitr::opts_chunk$set( # Introduction -This document is intended to be guidance for creators and reviewers of pull requests (PRs) in the `{admiral}` package. PR authors will benefit from shorter review times by closely following the guidance provided here. +This document is intended to be guidance for creators and reviewers of pull requests (PRs) in the `{admiral}` package family. PR authors will benefit from shorter review times by closely following the guidance provided here. -A pull request into the `devel` branch signifies that an issue that has been "addressed". This issue might be a bug, a feature request or a documentation update. For transparency, we keep the issue open until the `devel` branch is merged into the `main` branch, which usually coincides with a release of `{admiral}` to CRAN. This ensures that repeat issues are not raised and if they are raised are quickly marked as duplicates and closed. +A pull request into the `devel` branch signifies that an issue has been "addressed". This issue might be a bug, a feature request or a documentation update. Once a Pull Request is merged into `devel` branch, then the issue(s) can be closed. -Closely following the below guidance will ensure that our all our "addressed" issues auto-close once we merge `devel` into `main`. +Closely following the below guidance will ensure that our all our "addressed" issues auto-close once we merge `devel`. # Review Criteria -For a pull request to be merged into `devel` it needs to pass the automated `R CMD check`, `lintr`, and `task-list-completed` workflows on GitHub at a minimum. The first two checks can be run locally using the `devtools::check()` and `lintr::lint_package()` commands and are recommended to be done before pushing to GitHub. The `task-list-completed` workflow is exclusive to GitHub and will be discussed later. In addition, the PR creator and reviewer should make sure that +For a pull request to be merged into `devel` it needs to pass the automated CI checks that will appear at the bottom of the Pull Request. In addition, the PR creator and reviewer should make sure that - the [Programming Strategy](programming_strategy.html) and [Development Process](development_process.html) are followed @@ -49,12 +49,16 @@ For a pull request to be merged into `devel` it needs to pass the automated `R C - examples print relevant source variables and newly created variables and/or records in their output -- the `NEWS.md` file is updated with an entry that explains the new features or changes - -- the author of a function is listed in the `DESCRIPTION` file +- the `NEWS.md` file is updated with an entry that explains the new features or changes if the change is user-specific or warrants a mention as a development milestone - all files affected by the implemented changes, e.g. vignettes and templates, are updated +## Codeowners and PR Guidance + +As the creator of a PR, the assignment of a reviewer can be unclear. For most PRs, feel free to select a few members of the core development team. These individuals scan each repository on a regular basis as well and may provide his/her review even if not originally included as a selected reviewer. + +Sometimes, the development of a function or a vignette falls under a specific-topic, e.g. labs or PK/PD. Please ensure you include an appropriate reviewer if you are modifying files that rely on domain-expertise. We try to maintain an active list for domain-specific topics that will automatically tag an appropriate reviewer using our `CODEOWNERS` file, located in the `.github` folder. If you are interested in being a codeowner, reach out to the development team. + # So much Red Tape! The `{admiral}` development team is aware and sympathetic to the great many checks, processes and documents needed to work through in order to do a compliant Pull Request. The `task-list-completed` GitHub workflow was created to help reduce this burden on contributors by providing a standardized checklist that compiles information from the Pull Request Review Guidance, [Programming Strategy](programming_strategy.html) and [Development Process](development_process.html) vignettes. @@ -87,7 +91,9 @@ knitr::include_graphics("./pr_review_actions.png") Please don't hesitate to reach out to the `{admiral}` team on [Slack](https://app.slack.com/client/T028PB489D3/C02M8KN8269) or through the [GitHub Issues](https://github.com/pharmaverse/admiral/issues) tracker if you think this checklist needs to be amended or further clarity is needed on a check box item. -# GitHub Actions/Workflows +**Note for Reviewers:** We recommend the use of Squash and Merge when merging in a Pull Request. This will create a clean commit history when doing a final merge of `devel` into `main`. + +# GitHub Actions/CI Workflows The `task-list-completed` workflow is one of the several workflows/actions used within `{admiral}`. These workflows live in the `.github/workflows` folder and it is important to understand their use and how to remedy if the workflow fails. Workflows defined here are responsible for assuring high package quality standards without compromising performance, security, or reproducibility. @@ -150,86 +156,3 @@ Spellchecks are performed by this workflow, and the `{spelling}` R package is us ### `style.yml` Code style is enforced via the `styler` R package. Custom style configurations, if any, will be honored by this workflow. Failed workflows are indicative of unstyled code. - -# Common R CMD Check Issues - -`R CMD check` is a command line tool that checks R packages against a standard set of criteria. For a pull request to pass the check must not issue any notes, warnings or errors. Below is a list of common issues and how to resolve them. - -## Check Fails Only on One Version - -If the `R CMD check` workflow fails only on one or two R versions it can be helpful to reproduce the testing environment locally. - -To reproduce a particular R version environment open the `{admiral}` project in the corresponding R version, comment the line `source("renv/activate.R")` in the `.Rprofile` file, restart the R session and then run the following commands in the R console. - -``` r -Sys.setenv(R_REMOTES_NO_ERRORS_FROM_WARNINGS = "true") - -if (!dir.exists(".library")) { - dir.create(".library") -} - -base_recommended_pkgs <- row.names(installed.packages(priority = "high")) -for (pkg in base_recommended_pkgs) { - path <- file.path(.Library, pkg) - cmd <- sprintf("cp -r %s .library", path) - system(cmd) -} -assign(".lib.loc", ".library", envir = environment(.libPaths)) - -r_version <- getRversion() -if (grepl("^4.1", r_version)) { - options(repos = "https://packagemanager.posit.co/cran/2021-05-03/") -} else if (grepl("^4.2", r_version)) { - options(repos = "https://packagemanager.posit.co/cran/2022-01-03/") -} else if (grepl("^4.3", r_version)) { - options(repos = "https://packagemanager.posit.co/cran/2023-04-20/") -} else { - options(repos = "https://cran.rstudio.com") -} - -if (!requireNamespace("remotes", quietly = TRUE)) { - install.packages("remotes") -} -remotes::install_deps(dependencies = TRUE) -remotes::install_github("pharmaverse/admiral.test", ref = "devel") -remotes::install_github("pharmaverse/admiraldev", ref = "devel") -rcmdcheck::rcmdcheck() -``` - -This will ensure that the exact package versions we use in the workflow are installed into the hidden folder `.library`. That way your existing R packages are *not* overwritten. - -## Package Dependencies - - > checking package dependencies ... ERROR - Namespace dependency not required: ‘pkg’ - -Add `pkg` to the `Imports` or `Suggests` field in the `DESCRIPTION` file. In general, dependencies should be listed in the `Imports` field. However, if a package is only used inside vignettes or unit tests it should be listed in `Suggests` because all `{admiral}` functions would work without these "soft" dependencies being installed. - -## Global Variables - - ❯ checking R code for possible problems ... NOTE - function_xyz: no visible binding for global variable ‘some_var’ - -Add `some_var` to the list of "global" variables in `R/globals.R`. - -## Undocumented Function Parameter - - ❯ checking Rd \usage sections ... WARNING - Undocumented arguments in documentation object 'function_xyz' - ‘some_param’ - -Add an `@param some_param` section in the header of `function_xyz()` and run `devtools::document()` afterwards. - -## Outdated Documentation - - ❯ checking for code/documentation mismatches ... WARNING - Codoc mismatches from documentation object 'function_xyz': - ... - Argument names in code not in docs: - new_param_name - Argument names in docs not in code: - old_param_name - Mismatches in argument names: - Position: 6 Code: new_param_name Docs: old_param_name - -The name of a parameter has been changed in the function code but not yet in the header. Change `@param old_param_name` to `@param new_param_name` and run `devtools::document()`. diff --git a/vignettes/programming_strategy.Rmd b/vignettes/programming_strategy.Rmd index 83704cbf..bf0b09f5 100644 --- a/vignettes/programming_strategy.Rmd +++ b/vignettes/programming_strategy.Rmd @@ -146,12 +146,15 @@ documentation of `set_admiral_options()`. | Other Common Function Name Terms | Description | |----------------------------------------------|-----------------------------------------------------------------------------------------------------| -| `_merged_` / `_joined_` / `_extreme_` | Functions that follow the generic function user-guide. | +| `_merged_` / `_joined_` / `_extreme_` | Functions that follow the [generic function user-guide](https://pharmaverse.github.io/admiral/cran-release/articles/generic.html). | Please note that the appropriate *var*/*vars* prefix should be used for all cases in which the function creates any variable(s), regardless of the presence of a `new_var` argument in the function call. +Oftentimes when creating a new `derive_var` or `derive_param` function there may be some sort of non-trivial calculation involved that you may want to write a customized function for. This is when creating a `compute_` function becomes appropriate, such that the calculation portion is contained in one step as part of the overall `derive_` function, reducing clutter in the main function body and assisting in debugging. In addition, a `compute_` function should be implemented if the calculation could be used for more than one derivation. For example `compute_bmi()` could be used to derive a baseline BMI variable in ADSL (based on baseline weight and baseline height variables) and could also be used to derive a BMI parameter in ADVS (based on weight and height parameters). Please see `compute_age_years()` and `derive_var_age_years()` as another example. + + ## Function Arguments The default value of optional arguments should be `NULL`. @@ -202,26 +205,30 @@ added, it should be `param.` For example: `new_var`, `new_var_unit`, Arguments which expect a boolean or boolean vector must start with a verb, e.g., `is_imputed` or `impute_date`. +Arguments which only expect one value or variable name must be a singular version of the word(s), e.g., `missing_value` or `new_var`. Arguments which expect several values or variable names (as a list, expressions, etc.) must be a plural version of the word(s), e.g., `missing_values` or `new_vars`. ## List of Common Arguments - -| Argument Name | Description | +| Argument Name | Description | |------------------|--------------------------------------------------------------------------------------------------------------------| | `dataset` | The input dataset. Expects a data.frame or a tibble. | +| `dataset_ref` | The reference dataset, e.g. ADSL. Typically includes just one observation per subject. | +| `dataset_add` | An additional dataset. Used in some `derive_xx` and `filter_xx` functions to access variables from an additional dataset. | | `by_vars` | Variables to group by. | -| `order` | List of expressions for sorting a dataset, e.g., `exprs(PARAMCD, AVISITN, desc(AVAL))`. | +| `order` | List of expressions for sorting a dataset, e.g., `exprs(PARAMCD, AVISITN, desc(AVAL))`. | | `new_var` | Name of a single variable to be added to the dataset. | | `new_vars` | List of variables to be added to the dataset. | -| `new_var_unit` | Name of the unit variable to be added. It should be the unit of the variable specified for the `new_var` argument. | +| `new_var_unit` | Name of the unit variable to be added. It should be the unit of the variable specified for the `new_var` argument. | | `filter` | Expression to filter a dataset, e.g., `PARAMCD == "TEMP"`. | | `start_date` | The start date of an event/interval. Expects a date object. | | `end_date` | The end date of an event/interval. Expects a date object. | | `start_dtc` | (Partial) start date/datetime in ISO 8601 format. | | `dtc` | (Partial) date/datetime in ISO 8601 format. | | `date` | Date of an event / interval. Expects a date object. | -| `set_values_to` | List of variable name-value pairs. Use `process_set_values_to()` for processing the value and providing user friendly error messages. | | `subject_keys` | Variables to uniquely identify a subject, defaults to `exprs(STUDYID, USUBJID)`. In function formals, use `subject_keys = get_admiral_option("subject_keys")` | - +| `set_values_to` | List of variable name-value pairs. Use `process_set_values_to()` for processing the value and providing user friendly error messages. | +| `keep_source_vars` | Specifies which variables from the selected observations should be kept. The default of the argument should be `exprs(everything())`. The primary difference between `set_values_to` and `keep_source_vars` is that `keep_source_vars` only selects and retains the variables from a source dataset, so e.g. `keep_source_vars = exprs(DOMAIN)` would join + keep the `DOMAIN` variable, whereas `set_values_to` can make renaming and inline function changes such as `set_values_to = exprs(LALVDOM = DOMAIN)` | +| `missing_value` | A singular value to be entered if the data is missing. | +| `missing_values` | A named list of expressions where the names are variables in the dataset and the values are a value to be entered if the data is missing, e.g., `exprs(BASEC = "MISSING", BASE = -1)`. | ## Source Code Formatting @@ -317,9 +324,9 @@ This rule is applicable only if both functions are part of `{admiral}`. Every function that is exported from the package must have an accompanying header that should be formatted according to the [roxygen2](https://roxygen2.r-lib.org/) convention. -In addition to the roxygen2 tags, `@keywords` is also used. +In addition to the standard roxygen2 tags, the `@family` and `@keywords` tags are also used. -The keywords are used to categorize the function. Please see section "Categorization of functions". +The family/keywords are used to categorize the function, which is used both on our website and the internal package help pages. Please see section [Categorization of functions](programming_strategy.html#categorization-of-functions). An example is given below: @@ -582,8 +589,7 @@ function/argument should be used instead. The documentation will be updated at: + the description level for a function, -+ the keywords will be replaced with `deprecated` -+ the `@family` roxygen tag will become `deprecated` ++ the `@keywords` and`@family` roxygen tags will be replaced with `deprecated` ```{r, eval=FALSE} #' Title of the function diff --git a/vignettes/project_board.png b/vignettes/project_board.png new file mode 100644 index 00000000..ba578912 Binary files /dev/null and b/vignettes/project_board.png differ diff --git a/vignettes/rcmd_issues.Rmd b/vignettes/rcmd_issues.Rmd new file mode 100644 index 00000000..6f7dc3f0 --- /dev/null +++ b/vignettes/rcmd_issues.Rmd @@ -0,0 +1,104 @@ +--- +title: "R CMD Issues" +output: + rmarkdown::html_vignette: + toc: true + toc_depth: 2 +vignette: > + %\VignetteIndexEntry{R CMD Issues} + %\VignetteEngine{knitr::rmarkdown} + %\VignetteEncoding{UTF-8} +--- + +```{r, include = FALSE} +knitr::opts_chunk$set( + collapse = TRUE, + comment = "#>" +) +``` + +# Common R CMD Check Issues + +`R CMD check` is a command line tool that checks R packages against a standard set of criteria. For a pull request to pass the check must not issue any notes, warnings or errors. Below is a list of common issues and how to resolve them. + +## Check Fails Only on One Version + +If the `R CMD check` workflow fails only on one or two R versions it can be helpful to reproduce the testing environment locally. + +To reproduce a particular R version environment open the `{admiral}` project in the corresponding R version, comment the line `source("renv/activate.R")` in the `.Rprofile` file, restart the R session and then run the following commands in the R console. + +``` r +Sys.setenv(R_REMOTES_NO_ERRORS_FROM_WARNINGS = "true") + +if (!dir.exists(".library")) { + dir.create(".library") +} + +base_recommended_pkgs <- row.names(installed.packages(priority = "high")) +for (pkg in base_recommended_pkgs) { + path <- file.path(.Library, pkg) + cmd <- sprintf("cp -r %s .library", path) + system(cmd) +} +assign(".lib.loc", ".library", envir = environment(.libPaths)) + +r_version <- getRversion() +if (grepl("^4.1", r_version)) { + options(repos = "https://packagemanager.posit.co/cran/2021-05-03/") +} else if (grepl("^4.2", r_version)) { + options(repos = "https://packagemanager.posit.co/cran/2022-01-03/") +} else if (grepl("^4.3", r_version)) { + options(repos = "https://packagemanager.posit.co/cran/2023-04-20/") +} else { + options(repos = "https://cran.rstudio.com") +} + +if (!requireNamespace("remotes", quietly = TRUE)) { + install.packages("remotes") +} +remotes::install_deps(dependencies = TRUE) +remotes::install_github("pharmaverse/pharmaversesdtm", ref = "devel") +remotes::install_github("pharmaverse/admiraldev", ref = "devel") +rcmdcheck::rcmdcheck() +``` + +This will ensure that the exact package versions we use in the workflow are installed into the hidden folder `.library`. That way your existing R packages are *not* overwritten. + +## Package Dependencies + + > checking package dependencies ... ERROR + Namespace dependency not required: ‘pkg’ + +Add `pkg` to the `Imports` or `Suggests` field in the `DESCRIPTION` file. In general, dependencies should be listed in the `Imports` field. However, if a package is only used inside vignettes or unit tests it should be listed in `Suggests` because all `{admiral}` functions would work without these "soft" dependencies being installed. + +## Global Variables + + ❯ checking R code for possible problems ... NOTE + function_xyz: no visible binding for global variable ‘some_var’ + +Add `some_var` to the list of "global" variables in `R/globals.R`. + +## Undocumented Function Parameter + + ❯ checking Rd \usage sections ... WARNING + Undocumented arguments in documentation object 'function_xyz' + ‘some_param’ + +Add an `@param some_param` section in the header of `function_xyz()` and run `devtools::document()` afterwards. + +## Outdated Documentation + + ❯ checking for code/documentation mismatches ... WARNING + Codoc mismatches from documentation object 'function_xyz': + ... + Argument names in code not in docs: + new_param_name + Argument names in docs not in code: + old_param_name + Mismatches in argument names: + Position: 6 Code: new_param_name Docs: old_param_name + +The name of a parameter has been changed in the function code but not yet in the header. Change `@param old_param_name` to `@param new_param_name` and run `devtools::document()`. + +For further reading we recommend the [R-pkg manual r-cmd chapter](https://r-pkgs.org/r-cmd-check.html) + diff --git a/vignettes/test_data_guidance.Rmd b/vignettes/test_data_guidance.Rmd new file mode 100644 index 00000000..7c1aa005 --- /dev/null +++ b/vignettes/test_data_guidance.Rmd @@ -0,0 +1,20 @@ +--- +title: "Test Data Guidance" +output: rmarkdown::html_vignette +vignette: > + %\VignetteIndexEntry{Test Data Guidance} + %\VignetteEngine{knitr::rmarkdown} +--- + +```{r setup, include = FALSE} +knitr::opts_chunk$set( + collapse = TRUE, + comment = "#>" +) +``` + +There are two test data packages that enable any Pharmaverse package development team to re-use test SDTM and ADaM: + +- [`{pharmaversesdtm}`](https://github.com/pharmaverse/pharmaversesdtm): a data package that stores test SDTM data. If the current available data does not meet your need, update or add the new data in this package based on the instructions provided on the [How to Update](https://pharmaverse.github.io/pharmaversesdtm/cran-release/). + +- [`{pharmaverseadam}`](https://github.com/pharmaverse/pharmaverseadam): a data package that stores test ADaM data created from {admiral} templates. There is an integration test that runs {admiral} templates and compares them with the stored version. If differences are found, it then triggers an action: either accepting the difference and storing the new ADaM, or rejecting it and identifying the cause of the differences in the templates. diff --git a/vignettes/unit_test_guidance.Rmd b/vignettes/unit_test_guidance.Rmd index b85a3287..45ad4f8f 100644 --- a/vignettes/unit_test_guidance.Rmd +++ b/vignettes/unit_test_guidance.Rmd @@ -121,6 +121,19 @@ your function justifies it, e.g. see the test script: https://github.com/pharmav Don’t forget to add a unit test for each exported function. +## Snapshot Testing + +Standard unit tests are not always convenient to record the expected behavior with code. +Some challenges include: + + - Output that is large, making it painful to define the reference output, and bloating the size of the test file and making it hard to navigate. + - Text output that includes many characters like quotes and newlines that require special handling in a string. + - Binary formats like plots or images, which are very difficult to describe in code: i.e. the plot looks right, the error message is useful to a human, the print method uses color effectively. + +For these situations, testthat provides an alternative mechanism: snapshot tests. +Snapshot tests record results in a separate human readable file and records the results, including output, messages, warnings, and errors. +Review the [{testthat} snapshot vignette](https://testthat.r-lib.org/articles/snapshotting.html) for details. + ## Set up the Test Script Within the `tests/testthat` folder of the project, add a script with the naming diff --git a/vignettes/writing_vignettes.Rmd b/vignettes/writing_vignettes.Rmd index ba72accc..94bfb18a 100644 --- a/vignettes/writing_vignettes.Rmd +++ b/vignettes/writing_vignettes.Rmd @@ -127,10 +127,10 @@ function so that it is displayed consistently across the vignettes.E.g. ```{r, include=FALSE} library(lubridate) library(dplyr) -library(admiral.test) +library(pharmaversesdtm) library(DT) -data(admiral_vs) +data(vs) ``` ```{r, eval=FALSE, echo=TRUE} @@ -190,7 +190,7 @@ workflow will always describe the data read to demonstrate the use of the `{admi + Each sub-section within the programming workflow should be tagged (e.g. [Step1] (#step)), so that the user can go on the relevant section from the programming workflow (in addition to the Table of -contents). Don’t use a tag with a number but use a meaningful name (e.g. do not use `(#link1)`, +contents). Don't use a tag with a number but use a meaningful name (e.g. do not use `(#link1)`, but use `(#this_action)`) + the last section should link to a template script.