From 8afbf1a635a35f872d657a85af8e04290c019b52 Mon Sep 17 00:00:00 2001 From: Aleksander Chlebowski Date: Thu, 26 Sep 2024 11:16:26 +0200 Subject: [PATCH 01/11] extend defunction call to data in create_app_id --- R/utils.R | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/R/utils.R b/R/utils.R index 36cd81f564..a0e0c07d89 100644 --- a/R/utils.R +++ b/R/utils.R @@ -284,9 +284,8 @@ create_app_id <- function(data, modules) { } else if (inherits(data, "teal_data_module")) { deparse1(body(data$server)) } - modules <- lapply(modules, defunction) - rlang::hash(list(data = data, modules = modules)) + rlang::hash(defunction(list(data = data, modules = modules))) } #' Go through list and extract bodies of encountered functions as string, recursively. From 1c1555f1cfdf0247cf2f3393e4e5030084344704 Mon Sep 17 00:00:00 2001 From: Aleksander Chlebowski Date: Thu, 26 Sep 2024 11:40:09 +0200 Subject: [PATCH 02/11] apply defunciton to data objects in .get_hashes_code --- R/module_init_data.R | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/R/module_init_data.R b/R/module_init_data.R index 7990a2bb0a..4fb39380da 100644 --- a/R/module_init_data.R +++ b/R/module_init_data.R @@ -172,6 +172,12 @@ srv_init_data <- function(id, data, modules, filter = teal_slices()) { #' @keywords internal #' .get_hashes_code <- function(data, datanames = .teal_data_ls(data)) { + # The existence of functions cause problems when calculating hashes + # because they have environments that have parents on the search list. + vars <- ls(get_env(data)) + for (qvar in ls(get_env(data))) { + data <- within(data, qvar <- defunction(qvar), qvar = as.symbol(qvar)) + } vapply( datanames, function(dataname, datasets) { From 12e5611daad9e15749ce47956ca9620a4dc4c917 Mon Sep 17 00:00:00 2001 From: Aleksander Chlebowski Date: Thu, 26 Sep 2024 11:45:55 +0200 Subject: [PATCH 03/11] amend documentation --- R/module_init_data.R | 4 ++++ R/utils.R | 2 ++ man/create_app_id.Rd | 6 ++++++ man/dot-get_hashes_code.Rd | 6 ++++++ 4 files changed, 18 insertions(+) diff --git a/R/module_init_data.R b/R/module_init_data.R index 4fb39380da..a8bddd2b3a 100644 --- a/R/module_init_data.R +++ b/R/module_init_data.R @@ -165,6 +165,10 @@ srv_init_data <- function(id, data, modules, filter = teal_slices()) { #' Get code that tests the integrity of the reproducible data #' +#' @section Functions: +#' Data objects that are functions are converted to strings represencting their body +#' in order to strip their enclosing environments. +#' #' @param data (`teal_data`) object holding the data #' @param datanames (`character`) names of `datasets` #' diff --git a/R/utils.R b/R/utils.R index a0e0c07d89..4b05d42338 100644 --- a/R/utils.R +++ b/R/utils.R @@ -269,6 +269,8 @@ build_app_title <- function( #' App ID is a hash of the app's data and modules. #' See "transferring snapshots" section in ?snapshot. #' +#' @inheritSection .get_hashes_code Functions +#' #' @param data (`teal_data` or `teal_data_module`) as accepted by `init` #' @param modules (`teal_modules`) object as accepted by `init` #' diff --git a/man/create_app_id.Rd b/man/create_app_id.Rd index 62656beddb..e06aa46dc9 100644 --- a/man/create_app_id.Rd +++ b/man/create_app_id.Rd @@ -22,4 +22,10 @@ Calculate app ID that will be used to stamp filter state snapshots. App ID is a hash of the app's data and modules. See "transferring snapshots" section in ?snapshot. } +\section{Functions}{ + +Data objects that are functions are converted to strings represencting their body +in order to strip their enclosing environments. +} + \keyword{internal} diff --git a/man/dot-get_hashes_code.Rd b/man/dot-get_hashes_code.Rd index 07280ef587..53c7d76c2e 100644 --- a/man/dot-get_hashes_code.Rd +++ b/man/dot-get_hashes_code.Rd @@ -17,4 +17,10 @@ A character vector with the code lines. \description{ Get code that tests the integrity of the reproducible data } +\section{Functions}{ + +Data objects that are functions are converted to strings represencting their body +in order to strip their enclosing environments. +} + \keyword{internal} From 2264c1ffc7f9107da5290bd0886a0581220ced11 Mon Sep 17 00:00:00 2001 From: Aleksander Chlebowski Date: Mon, 30 Sep 2024 10:45:10 +0200 Subject: [PATCH 04/11] fix typo in docs --- R/module_init_data.R | 2 +- man/create_app_id.Rd | 2 +- man/dot-get_hashes_code.Rd | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/R/module_init_data.R b/R/module_init_data.R index 8a5acc9867..3711f56c02 100644 --- a/R/module_init_data.R +++ b/R/module_init_data.R @@ -169,7 +169,7 @@ srv_init_data <- function(id, data, modules, filter = teal_slices()) { #' Get code that tests the integrity of the reproducible data #' #' @section Functions: -#' Data objects that are functions are converted to strings represencting their body +#' Data objects that are functions are converted to strings representing their body #' in order to strip their enclosing environments. #' #' @param data (`teal_data`) object holding the data diff --git a/man/create_app_id.Rd b/man/create_app_id.Rd index e06aa46dc9..c64d83c1a4 100644 --- a/man/create_app_id.Rd +++ b/man/create_app_id.Rd @@ -24,7 +24,7 @@ See "transferring snapshots" section in ?snapshot. } \section{Functions}{ -Data objects that are functions are converted to strings represencting their body +Data objects that are functions are converted to strings representing their body in order to strip their enclosing environments. } diff --git a/man/dot-get_hashes_code.Rd b/man/dot-get_hashes_code.Rd index 909521604c..bc66886a0e 100644 --- a/man/dot-get_hashes_code.Rd +++ b/man/dot-get_hashes_code.Rd @@ -19,7 +19,7 @@ Get code that tests the integrity of the reproducible data } \section{Functions}{ -Data objects that are functions are converted to strings represencting their body +Data objects that are functions are converted to strings representing their body in order to strip their enclosing environments. } From 46662c87c4cf20c6beb28dd8b07beb9ea94c54ae Mon Sep 17 00:00:00 2001 From: Aleksander Chlebowski Date: Mon, 30 Sep 2024 19:48:51 +0200 Subject: [PATCH 05/11] tighten recursion condition in defunciton --- R/utils.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/utils.R b/R/utils.R index 4669cd7433..21498ff427 100644 --- a/R/utils.R +++ b/R/utils.R @@ -303,7 +303,7 @@ create_app_id <- function(data, modules) { #' @keywords internal #' @noRd defunction <- function(x) { - if (is.list(x)) { + if (checkmate::test_list(x)) { lapply(x, defunction) } else if (is.function(x)) { deparse1(body(x)) From f77e91975f4448136487173cc65e2e94a2465461 Mon Sep 17 00:00:00 2001 From: Aleksander Chlebowski Date: Wed, 2 Oct 2024 11:19:58 +0200 Subject: [PATCH 06/11] clean up merge artefacts --- R/module_init_data.R | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/R/module_init_data.R b/R/module_init_data.R index 3711f56c02..cc5d2ea30a 100644 --- a/R/module_init_data.R +++ b/R/module_init_data.R @@ -181,8 +181,8 @@ srv_init_data <- function(id, data, modules, filter = teal_slices()) { .get_hashes_code <- function(data, datanames = ls(teal.code::get_env(data))) { # Functions cause problems when calculating hashes # because they have environments that have parents on the search list. - vars <- ls(get_env(data)) - for (qvar in ls(get_env(data))) { + vars <- ls(teal.code::get_env(data)) + for (qvar in ls(teal.code::get_env(data))) { data <- within(data, qvar <- defunction(qvar), qvar = as.symbol(qvar)) } From c3b50b9d1768fbb9bfb0f9d37b02b59099159f43 Mon Sep 17 00:00:00 2001 From: Aleksander Chlebowski Date: Wed, 2 Oct 2024 11:27:57 +0200 Subject: [PATCH 07/11] loop over datanames, not all items --- R/module_init_data.R | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/R/module_init_data.R b/R/module_init_data.R index cc5d2ea30a..34441c5d91 100644 --- a/R/module_init_data.R +++ b/R/module_init_data.R @@ -181,9 +181,8 @@ srv_init_data <- function(id, data, modules, filter = teal_slices()) { .get_hashes_code <- function(data, datanames = ls(teal.code::get_env(data))) { # Functions cause problems when calculating hashes # because they have environments that have parents on the search list. - vars <- ls(teal.code::get_env(data)) - for (qvar in ls(teal.code::get_env(data))) { - data <- within(data, qvar <- defunction(qvar), qvar = as.symbol(qvar)) + for (d in datanames) { + data <- within(data, d <- defunction(d), d = as.symbol(d)) } vapply( From be7cbb1b17b3c256438578e2a0f6152841a415d3 Mon Sep 17 00:00:00 2001 From: Aleksander Chlebowski Date: Wed, 2 Oct 2024 15:46:24 +0200 Subject: [PATCH 08/11] fix within call in .get_hashes_data --- R/module_init_data.R | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/R/module_init_data.R b/R/module_init_data.R index 34441c5d91..931b6038fa 100644 --- a/R/module_init_data.R +++ b/R/module_init_data.R @@ -182,9 +182,8 @@ srv_init_data <- function(id, data, modules, filter = teal_slices()) { # Functions cause problems when calculating hashes # because they have environments that have parents on the search list. for (d in datanames) { - data <- within(data, d <- defunction(d), d = as.symbol(d)) + data <- within(data, var <- defunction(val), var = d, val = as.symbol(d)) } - vapply( datanames, function(dataname, datasets) { From 183779beba740073aa502f517b957778b6e929dd Mon Sep 17 00:00:00 2001 From: Aleksander Chlebowski Date: Wed, 2 Oct 2024 16:33:27 +0200 Subject: [PATCH 09/11] add unit test for defunction --- tests/testthat/test-utils.R | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tests/testthat/test-utils.R b/tests/testthat/test-utils.R index 4904c46461..ec7efe17cf 100644 --- a/tests/testthat/test-utils.R +++ b/tests/testthat/test-utils.R @@ -176,3 +176,16 @@ testthat::test_that("defunction recursively goes down a list", { y ) }) + +testthat::test_that("defunction leaves lists with other classes intact", { + # styler: off + x <- list( + "character" = "character", + "data.frame" = head(mtcars) + ) + + testthat::expect_identical( + defunction(x), + x + ) +}) From 230478f1fd5d07d4258bbca532d3ea1ea6429a78 Mon Sep 17 00:00:00 2001 From: Aleksander Chlebowski Date: Thu, 3 Oct 2024 10:10:18 +0200 Subject: [PATCH 10/11] move defunction call outside of within --- R/module_init_data.R | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/R/module_init_data.R b/R/module_init_data.R index 931b6038fa..0584fa7148 100644 --- a/R/module_init_data.R +++ b/R/module_init_data.R @@ -181,13 +181,10 @@ srv_init_data <- function(id, data, modules, filter = teal_slices()) { .get_hashes_code <- function(data, datanames = ls(teal.code::get_env(data))) { # Functions cause problems when calculating hashes # because they have environments that have parents on the search list. - for (d in datanames) { - data <- within(data, var <- defunction(val), var = d, val = as.symbol(d)) - } vapply( datanames, function(dataname, datasets) { - hash <- rlang::hash(data[[dataname]]) + hash <- rlang::hash(defunction(data[[dataname]])) sprintf( "stopifnot(%s == %s) # @linksto %s", deparse1(bquote(rlang::hash(.(as.name(dataname))))), From 221b32dd6b210347321787be696a4bdea7437207 Mon Sep 17 00:00:00 2001 From: Aleksander Chlebowski Date: Thu, 3 Oct 2024 10:21:52 +0200 Subject: [PATCH 11/11] remove unused argument in anon function --- R/module_init_data.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/module_init_data.R b/R/module_init_data.R index 0584fa7148..9d31054ea2 100644 --- a/R/module_init_data.R +++ b/R/module_init_data.R @@ -183,7 +183,7 @@ srv_init_data <- function(id, data, modules, filter = teal_slices()) { # because they have environments that have parents on the search list. vapply( datanames, - function(dataname, datasets) { + function(dataname) { hash <- rlang::hash(defunction(data[[dataname]])) sprintf( "stopifnot(%s == %s) # @linksto %s",