Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 38 additions & 55 deletions R/import-standalone-check_pkg_installed.R
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
# ---
# repo: insightsengineering/standalone
# file: standalone-check_pkg_installed.R
# last-updated: 2025-02-03
# last-updated: 2025-10-03
# license: https://unlicense.org
# dependencies: standalone-cli_call_env.R
# imports: [rlang, dplyr, tidyr]
Expand All @@ -17,6 +17,9 @@
# ## Changelog
# 2025-02-03
# - `get_pkg_dependencies()` was updated to use base r equivalents for `str_extract()` and `str_remove_all()`.
#
# 2025-10-03
# - `skip_if_pkg_not_installed()` was added.

# nocov start
# styler: off
Expand All @@ -38,6 +41,9 @@
#'
#' - `get_min_version_required()` will return, if any, the minimum version of `pkg` required by `ref`.
#'
#' - `skip_if_pkg_not_installed()` checks whether packages are installed (with the minimum required version)
#' and skips tests if any are not installed.
#'
#' @param pkg (`character`)\cr
#' vector of package names to check.
#' @param call (`environment`)\cr
Expand Down Expand Up @@ -83,18 +89,13 @@ check_pkg_installed <- function(pkg,
if (!is.character(ref) && !is.null(ref)) cli::cli_abort("{.arg ref} must be a string.")

# get min version data -------------------------------------------------------
df_pkg_min_version <-
get_min_version_required(pkg = pkg, ref = ref)
df_pkg_min_version <- get_min_version_required(pkg = pkg, ref = ref)

# prompt user to install package ---------------------------------------------
rlang::check_installed(
pkg = df_pkg_min_version$pkg,
version = df_pkg_min_version$version,
compare = df_pkg_min_version$compare,
call = call
) |>
# this can be removed after this issue is resolved https://github.com/r-lib/rlang/issues/1694
suppressWarnings()
)
}

#' @inheritParams check_pkg_installed
Expand All @@ -108,14 +109,11 @@ is_pkg_installed <- function(pkg,
df_pkg_min_version <-
get_min_version_required(pkg = pkg, ref = ref)


# check installation TRUE/FALSE ----------------------------------------------
rlang::is_installed(
pkg = df_pkg_min_version$pkg,
version = df_pkg_min_version$version,
compare = df_pkg_min_version$compare
) |>
# this can be removed after this issue is resolved https://github.com/r-lib/rlang/issues/1694
suppressWarnings()
pkg = df_pkg_min_version$pkg
)
}

#' @inheritParams check_pkg_installed
Expand All @@ -140,47 +138,20 @@ get_pkg_dependencies <- function(pkg = utils::packageName(), lib.loc = NULL) {
unclass() |>
dplyr::as_tibble() |>
dplyr::select(
dplyr::any_of(c(
"Package", "Version", "Imports", "Depends",
"Suggests", "Enhances", "LinkingTo"
))
) |>
dplyr::rename(
reference_pkg = "Package",
reference_pkg_version = "Version"
dplyr::any_of(c("Imports", "Depends", "Suggests", "Enhances", "LinkingTo"))
) |>
tidyr::pivot_longer(
-dplyr::all_of(c("reference_pkg", "reference_pkg_version")),
values_to = "pkg",
names_to = "dependency_type",
) |>
tidyr::separate_rows("pkg", sep = ",") |>
tidyr::pivot_longer(cols = dplyr::everything(), names_to = NULL, values_to = "pkg") |>
tidyr::separate_longer_delim(dplyr::everything(), delim = ",") |>
dplyr::mutate(
pkg = trimws(
x = gsub(x = .data$pkg, pattern = "\\s+", replacement = " "),
which = "both", whitespace = "[ \t\r\n]"
)
) |>
dplyr::filter(!is.na(.data$pkg)) |>
tidyr::separate(
.data$pkg,
into = c("pkg", "version"),
sep = " ", extra = "merge", fill = "right"
) |>
dplyr::mutate(
compare = as.character(ifelse(regexpr("[>=<]+", .data$version) > 0,
regmatches(.data$version, regexpr("[>=<]+", .data$version)),
NA)),
version = gsub(pattern = "[\\(\\) >=<]", replacement = "", x = .data$version)
)
}

.empty_pkg_deps_df <- function() {
dplyr::tibble(
reference_pkg = character(0L), reference_pkg_version = character(0L),
dependency_type = character(0L), pkg = character(0L),
version = character(0L), compare = character(0L)
)
dplyr::tibble(pkg = character(0L))
}

#' @inheritParams check_pkg_installed
Expand All @@ -200,17 +171,29 @@ get_min_version_required <- function(pkg, ref = utils::packageName(), lib.loc =
)
}

# get the package_ref deps and subset on requested pkgs, also supplement df with pkgs
# that may not be proper deps of the reference package (these pkgs don't have min versions)
res <-
get_pkg_dependencies(ref, lib.loc = lib.loc) |>
dplyr::filter(.data$pkg %in% .env$pkg) |>
dplyr::full_join(
dplyr::tibble(pkg = pkg),
by = "pkg"
)
# get the package_ref deps and subset on requested pkgs
res <- get_pkg_dependencies(ref, lib.loc = lib.loc) |>
dplyr::filter(grepl(paste0(paste0(.env$pkg, "(\\s|$)"), collapse = "|"), .data$pkg))

# supplement df with pkgs that may not be proper deps of the reference package (these pkgs don't have min versions)
pkg_add <- which(sapply(pkg, \(x) !grepl(x, paste0(res$pkg, collapse = "|")))) |> names()
res |>
dplyr::full_join(dplyr::tibble(pkg = pkg_add), by = "pkg")
}

res
skip_if_pkg_not_installed <- function(pkg,
ref = utils::packageName()) {
pkg_deps <- get_min_version_required(pkg, ref = ref)
for (p in pkg_deps$pkg) {
pkg_installed <- rlang::is_installed(p)
if (!pkg_installed) {
# skip if any required package is not installed
testthat::skip(message = paste(
"Required package", shQuote(p, type = "sh"), "is not installed"
))
}
}
invisible()
}

# nocov end
Expand Down
2 changes: 1 addition & 1 deletion tests/testthat/test-ard_attributes.R
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
skip_if_not(is_pkg_installed("withr"))
skip_if_pkg_not_installed("withr")

test_that("ard_attributes() works", {
withr::local_options(list(width = 120))
Expand Down
2 changes: 1 addition & 1 deletion tests/testthat/test-ard_hierarchical.R
Original file line number Diff line number Diff line change
Expand Up @@ -348,7 +348,7 @@ test_that("ard_hierarchical_count() errors with incomplete factor columns", {
})

test_that("ard_hierarchical_count() provides correct results with 10+ groups", {
skip_if_not(is_pkg_installed("withr"))
skip_if_pkg_not_installed("withr")
withr::local_seed(1)

expect_silent(
Expand Down
2 changes: 1 addition & 1 deletion tests/testthat/test-ard_tabulate.R
Original file line number Diff line number Diff line change
Expand Up @@ -1108,7 +1108,7 @@ test_that("ard_tabulate() follows ard structure", {

test_that("ard_tabulate() with hms times", {
# originally reported in https://github.com/ddsjoberg/gtsummary/issues/1893
skip_if_not_installed("hms")
skip_if_pkg_not_installed("hms")
withr::local_package("hms")

ADSL2 <-
Expand Down
2 changes: 1 addition & 1 deletion tests/testthat/test-options.R
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
skip_if_not(is_pkg_installed("withr"))
skip_if_pkg_not_installed("withr")

test_that("options(cards.round_type)", {
# test that the p is rounded to zero (ie rounded to even) for aliases called by `apply_fmt_fun()`
Expand Down
2 changes: 1 addition & 1 deletion tests/testthat/test-shuffle_ard.R
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
skip_if_not(is_pkg_installed("withr"))
skip_if_pkg_not_installed("withr")

test_that("shuffle/trim works", {
withr::local_options(list(width = 200))
Expand Down
2 changes: 1 addition & 1 deletion tests/testthat/test-tidy_ard_column_order.R
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
test_that("tidy_ard_column_order() works", {
skip_if_not(is_pkg_installed("withr"))
skip_if_pkg_not_installed("withr")
withr::local_seed(1)

# ensure 10+ groups are ordered correctly
Expand Down
2 changes: 1 addition & 1 deletion tests/testthat/test-tidy_ard_row_order.R
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
test_that("tidy_ard_row_order() works", {
skip_if_not(is_pkg_installed("withr"))
skip_if_pkg_not_installed("withr")
withr::local_options(list(width = 120))
withr::local_seed(1)

Expand Down
Loading