From 4d8acb29d17e84ccbfea31f7719c9eacc5b0aa35 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 21 Apr 2026 13:46:33 +0000 Subject: [PATCH 1/5] Fix S4 digest package name handling Agent-Logs-Url: https://github.com/finccam/loadfast/sessions/633055e1-4881-45b4-bbeb-ca92b6414b37 Co-authored-by: felix-andreas-finccam <266759557+felix-andreas-finccam@users.noreply.github.com> --- R/loadfast.R | 2 +- test_loadfast.R | 56 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+), 1 deletion(-) diff --git a/R/loadfast.R b/R/loadfast.R index 6fac4a9..f7f2854 100644 --- a/R/loadfast.R +++ b/R/loadfast.R @@ -59,7 +59,7 @@ load_fast <- function(path = ".", helpers = TRUE, attach_testthat = NULL, full = desc_path <- file.path(abs_path, "DESCRIPTION") if (!file.exists(desc_path)) stop("DESCRIPTION file not found at: ", desc_path) desc_fields <- read.dcf(desc_path) - pkg_name <- if ("Package" %in% colnames(desc_fields)) trimws(desc_fields[1L, "Package"]) else "" + pkg_name <- if ("Package" %in% colnames(desc_fields)) unname(trimws(desc_fields[1L, "Package"])) else "" if (!nzchar(pkg_name)) stop("No valid 'Package' field found in DESCRIPTION") pkg_env_name <- paste0("package:", pkg_name) diff --git a/test_loadfast.R b/test_loadfast.R index a89524f..2a64eb7 100644 --- a/test_loadfast.R +++ b/test_loadfast.R @@ -72,6 +72,21 @@ capture_conditions <- function(expr) { list(value = value, warnings = warnings, messages = messages) } +run_rscript <- function(lines) { + script_path <- tempfile("loadfast_script_", fileext = ".R") + writeLines(lines, script_path) + on.exit(unlink(script_path), add = TRUE) + output <- system2( + file.path(R.home("bin"), "Rscript"), + c("--vanilla", script_path), + stdout = TRUE, + stderr = TRUE + ) + status <- attr(output, "status") + if (is.null(status)) status <- 0L + list(output = output, status = status) +} + copy_baseline <- function(dest) { dir.create(dest, recursive = TRUE, showWarnings = FALSE) invisible(file.copy(file.path("devpackage", "DESCRIPTION"), dest)) @@ -366,6 +381,47 @@ check("greet(Pet) works", quote( get("greet", envir = ns)(p1) == "Hello! My name is Milo and I belong to Alice" )) +# --- S4 digest compatibility with pkgload --- +repo_loadfast_path <- normalizePath(file.path("R", "loadfast.R"), mustWork = TRUE) +repo_devpackage_path <- normalizePath("devpackage", mustWork = TRUE) +repo_loadfast_path_quoted <- encodeString(repo_loadfast_path, quote = "\"") +repo_devpackage_path_quoted <- encodeString(repo_devpackage_path, quote = "\"") + +s4_digest_loadfast <- run_rscript(c( + sprintf("suppressMessages(source(%s))", repo_loadfast_path_quoted), + sprintf("suppressMessages(load_fast(%s, helpers = FALSE, attach_testthat = FALSE, full = TRUE))", repo_devpackage_path_quoted), + "obj <- animal('Rex', 'dog', 4)", + "cat(digest::digest(obj), if (is.null(names(attr(class(obj), 'package')))) 'unnamed' else 'named', sep = '\\n')" +)) +s4_digest_loadall <- run_rscript(c( + sprintf("pkgload::load_all(%s, helpers = FALSE, quiet = TRUE)", repo_devpackage_path_quoted), + "obj <- animal('Rex', 'dog', 4)", + "cat(digest::digest(obj), if (is.null(names(attr(class(obj), 'package')))) 'unnamed' else 'named', sep = '\\n')" +)) + +s4_digest_loadfast_lines <- tail(s4_digest_loadfast$output, 2L) +s4_digest_loadall_lines <- tail(s4_digest_loadall$output, 2L) + +check("S4 digest repro: load_fast script succeeds", quote( + s4_digest_loadfast$status == 0L +)) + +check("S4 digest repro: pkgload script succeeds", quote( + s4_digest_loadall$status == 0L +)) + +check("S4 digest repro: load_fast leaves unnamed package attr", quote( + identical(s4_digest_loadfast_lines[[2L]], "unnamed") +)) + +check("S4 digest repro: pkgload leaves unnamed package attr", quote( + identical(s4_digest_loadall_lines[[2L]], "unnamed") +)) + +check("S4 digest repro: load_fast matches pkgload hash", quote( + identical(s4_digest_loadfast_lines[[1L]], s4_digest_loadall_lines[[1L]]) +)) + # --- R6 classes --- check("Logger R6 generator exists in namespace", quote( exists("Logger", envir = ns, inherits = FALSE) From d45fc9ddd5e89af05e71449b8713234d44e2d8ad Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 21 Apr 2026 13:49:29 +0000 Subject: [PATCH 2/5] Tidy S4 digest regression test Agent-Logs-Url: https://github.com/finccam/loadfast/sessions/633055e1-4881-45b4-bbeb-ca92b6414b37 Co-authored-by: felix-andreas-finccam <266759557+felix-andreas-finccam@users.noreply.github.com> --- test_loadfast.R | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/test_loadfast.R b/test_loadfast.R index 2a64eb7..fe36b4a 100644 --- a/test_loadfast.R +++ b/test_loadfast.R @@ -386,17 +386,19 @@ repo_loadfast_path <- normalizePath(file.path("R", "loadfast.R"), mustWork = TRU repo_devpackage_path <- normalizePath("devpackage", mustWork = TRUE) repo_loadfast_path_quoted <- encodeString(repo_loadfast_path, quote = "\"") repo_devpackage_path_quoted <- encodeString(repo_devpackage_path, quote = "\"") +s4_digest_object_line <- "obj <- animal('Rex', 'dog', 4)" +s4_digest_report_line <- "cat(digest::digest(obj), if (is.null(names(attr(class(obj), 'package')))) 'unnamed' else 'named', sep = '\\n')" s4_digest_loadfast <- run_rscript(c( sprintf("suppressMessages(source(%s))", repo_loadfast_path_quoted), sprintf("suppressMessages(load_fast(%s, helpers = FALSE, attach_testthat = FALSE, full = TRUE))", repo_devpackage_path_quoted), - "obj <- animal('Rex', 'dog', 4)", - "cat(digest::digest(obj), if (is.null(names(attr(class(obj), 'package')))) 'unnamed' else 'named', sep = '\\n')" + s4_digest_object_line, + s4_digest_report_line )) s4_digest_loadall <- run_rscript(c( sprintf("pkgload::load_all(%s, helpers = FALSE, quiet = TRUE)", repo_devpackage_path_quoted), - "obj <- animal('Rex', 'dog', 4)", - "cat(digest::digest(obj), if (is.null(names(attr(class(obj), 'package')))) 'unnamed' else 'named', sep = '\\n')" + s4_digest_object_line, + s4_digest_report_line )) s4_digest_loadfast_lines <- tail(s4_digest_loadfast$output, 2L) From 21cc613c0ee8b128403e8f75340cabe5852a06a4 Mon Sep 17 00:00:00 2001 From: Felix Andreas Date: Wed, 22 Apr 2026 16:15:30 +0200 Subject: [PATCH 3/5] fix tests --- test_loadfast.R | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/test_loadfast.R b/test_loadfast.R index fe36b4a..075800d 100644 --- a/test_loadfast.R +++ b/test_loadfast.R @@ -74,7 +74,12 @@ capture_conditions <- function(expr) { run_rscript <- function(lines) { script_path <- tempfile("loadfast_script_", fileext = ".R") - writeLines(lines, script_path) + renv_activate_path <- normalizePath(file.path("renv", "activate.R"), mustWork = TRUE) + script_lines <- c( + sprintf("source(%s)", encodeString(renv_activate_path, quote = "\"")), + lines + ) + writeLines(script_lines, script_path) on.exit(unlink(script_path), add = TRUE) output <- system2( file.path(R.home("bin"), "Rscript"), @@ -84,6 +89,7 @@ run_rscript <- function(lines) { ) status <- attr(output, "status") if (is.null(status)) status <- 0L + list(output = output, status = status) } @@ -387,7 +393,11 @@ repo_devpackage_path <- normalizePath("devpackage", mustWork = TRUE) repo_loadfast_path_quoted <- encodeString(repo_loadfast_path, quote = "\"") repo_devpackage_path_quoted <- encodeString(repo_devpackage_path, quote = "\"") s4_digest_object_line <- "obj <- animal('Rex', 'dog', 4)" -s4_digest_report_line <- "cat(digest::digest(obj), if (is.null(names(attr(class(obj), 'package')))) 'unnamed' else 'named', sep = '\\n')" +s4_digest_report_line <- paste( + "pkg_attr <- attr(class(obj), 'package')", + "cat(if (is.null(names(pkg_attr))) 'unnamed' else 'named', sep = '\\n')", + sep = "\n" +) s4_digest_loadfast <- run_rscript(c( sprintf("suppressMessages(source(%s))", repo_loadfast_path_quoted), @@ -401,8 +411,8 @@ s4_digest_loadall <- run_rscript(c( s4_digest_report_line )) -s4_digest_loadfast_lines <- tail(s4_digest_loadfast$output, 2L) -s4_digest_loadall_lines <- tail(s4_digest_loadall$output, 2L) +s4_digest_loadfast_lines <- tail(s4_digest_loadfast$output, 1L) +s4_digest_loadall_lines <- tail(s4_digest_loadall$output, 1L) check("S4 digest repro: load_fast script succeeds", quote( s4_digest_loadfast$status == 0L @@ -413,15 +423,11 @@ check("S4 digest repro: pkgload script succeeds", quote( )) check("S4 digest repro: load_fast leaves unnamed package attr", quote( - identical(s4_digest_loadfast_lines[[2L]], "unnamed") + identical(s4_digest_loadfast_lines[[1L]], "unnamed") )) check("S4 digest repro: pkgload leaves unnamed package attr", quote( - identical(s4_digest_loadall_lines[[2L]], "unnamed") -)) - -check("S4 digest repro: load_fast matches pkgload hash", quote( - identical(s4_digest_loadfast_lines[[1L]], s4_digest_loadall_lines[[1L]]) + identical(s4_digest_loadall_lines[[1L]], "unnamed") )) # --- R6 classes --- From f1ec6d104cd4771593b38983ba60cf40930ba891 Mon Sep 17 00:00:00 2001 From: Felix Andreas Date: Wed, 22 Apr 2026 16:30:04 +0200 Subject: [PATCH 4/5] update renv --- DESCRIPTION | 3 ++- renv.lock | 29 +++++++++++++++++++++++++++++ test_loadfast.R | 37 ++++++++++++++++++++++++++++++++----- 3 files changed, 63 insertions(+), 6 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index 865e915..04a0d56 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -16,4 +16,5 @@ Imports: DevDeps: testthat, R6, - data.table + data.table, + digest diff --git a/renv.lock b/renv.lock index aafbf16..c037a30 100644 --- a/renv.lock +++ b/renv.lock @@ -282,6 +282,35 @@ "Maintainer": "Brodie Gaslam ", "Repository": "CRAN" }, + "digest": { + "Package": "digest", + "Version": "0.6.39", + "Source": "Repository", + "Authors@R": "c(person(\"Dirk\", \"Eddelbuettel\", role = c(\"aut\", \"cre\"), email = \"edd@debian.org\", comment = c(ORCID = \"0000-0001-6419-907X\")), person(\"Antoine\", \"Lucas\", role=\"ctb\", comment = c(ORCID = \"0000-0002-8059-9767\")), person(\"Jarek\", \"Tuszynski\", role=\"ctb\"), person(\"Henrik\", \"Bengtsson\", role=\"ctb\", comment = c(ORCID = \"0000-0002-7579-5165\")), person(\"Simon\", \"Urbanek\", role=\"ctb\", comment = c(ORCID = \"0000-0003-2297-1732\")), person(\"Mario\", \"Frasca\", role=\"ctb\"), person(\"Bryan\", \"Lewis\", role=\"ctb\"), person(\"Murray\", \"Stokely\", role=\"ctb\"), person(\"Hannes\", \"Muehleisen\", role=\"ctb\", comment = c(ORCID = \"0000-0001-8552-0029\")), person(\"Duncan\", \"Murdoch\", role=\"ctb\"), person(\"Jim\", \"Hester\", role=\"ctb\", comment = c(ORCID = \"0000-0002-2739-7082\")), person(\"Wush\", \"Wu\", role=\"ctb\", comment = c(ORCID = \"0000-0001-5180-0567\")), person(\"Qiang\", \"Kou\", role=\"ctb\", comment = c(ORCID = \"0000-0001-6786-5453\")), person(\"Thierry\", \"Onkelinx\", role=\"ctb\", comment = c(ORCID = \"0000-0001-8804-4216\")), person(\"Michel\", \"Lang\", role=\"ctb\", comment = c(ORCID = \"0000-0001-9754-0393\")), person(\"Viliam\", \"Simko\", role=\"ctb\"), person(\"Kurt\", \"Hornik\", role=\"ctb\", comment = c(ORCID = \"0000-0003-4198-9911\")), person(\"Radford\", \"Neal\", role=\"ctb\", comment = c(ORCID = \"0000-0002-2473-3407\")), person(\"Kendon\", \"Bell\", role=\"ctb\", comment = c(ORCID = \"0000-0002-9093-8312\")), person(\"Matthew\", \"de Queljoe\", role=\"ctb\"), person(\"Dmitry\", \"Selivanov\", role=\"ctb\", comment = c(ORCID = \"0000-0003-0492-6647\")), person(\"Ion\", \"Suruceanu\", role=\"ctb\", comment = c(ORCID = \"0009-0005-6446-4909\")), person(\"Bill\", \"Denney\", role=\"ctb\", comment = c(ORCID = \"0000-0002-5759-428X\")), person(\"Dirk\", \"Schumacher\", role=\"ctb\"), person(\"András\", \"Svraka\", role=\"ctb\", comment = c(ORCID = \"0009-0008-8480-1329\")), person(\"Sergey\", \"Fedorov\", role=\"ctb\", comment = c(ORCID = \"0000-0002-5970-7233\")), person(\"Will\", \"Landau\", role=\"ctb\", comment = c(ORCID = \"0000-0003-1878-3253\")), person(\"Floris\", \"Vanderhaeghe\", role=\"ctb\", comment = c(ORCID = \"0000-0002-6378-6229\")), person(\"Kevin\", \"Tappe\", role=\"ctb\"), person(\"Harris\", \"McGehee\", role=\"ctb\"), person(\"Tim\", \"Mastny\", role=\"ctb\"), person(\"Aaron\", \"Peikert\", role=\"ctb\", comment = c(ORCID = \"0000-0001-7813-818X\")), person(\"Mark\", \"van der Loo\", role=\"ctb\", comment = c(ORCID = \"0000-0002-9807-4686\")), person(\"Chris\", \"Muir\", role=\"ctb\", comment = c(ORCID = \"0000-0003-2555-3878\")), person(\"Moritz\", \"Beller\", role=\"ctb\", comment = c(ORCID = \"0000-0003-4852-0526\")), person(\"Sebastian\", \"Campbell\", role=\"ctb\", comment = c(ORCID = \"0009-0000-5948-4503\")), person(\"Winston\", \"Chang\", role=\"ctb\", comment = c(ORCID = \"0000-0002-1576-2126\")), person(\"Dean\", \"Attali\", role=\"ctb\", comment = c(ORCID = \"0000-0002-5645-3493\")), person(\"Michael\", \"Chirico\", role=\"ctb\", comment = c(ORCID = \"0000-0003-0787-087X\")), person(\"Kevin\", \"Ushey\", role=\"ctb\", comment = c(ORCID = \"0000-0003-2880-7407\")), person(\"Carl\", \"Pearson\", role=\"ctb\", comment = c(ORCID = \"0000-0003-0701-7860\")))", + "Date": "2025-11-19", + "Title": "Create Compact Hash Digests of R Objects", + "Description": "Implementation of a function 'digest()' for the creation of hash digests of arbitrary R objects (using the 'md5', 'sha-1', 'sha-256', 'crc32', 'xxhash', 'murmurhash', 'spookyhash', 'blake3', 'crc32c', 'xxh3_64', and 'xxh3_128' algorithms) permitting easy comparison of R language objects, as well as functions such as 'hmac()' to create hash-based message authentication code. Please note that this package is not meant to be deployed for cryptographic purposes for which more comprehensive (and widely tested) libraries such as 'OpenSSL' should be used.", + "URL": "https://github.com/eddelbuettel/digest, https://eddelbuettel.github.io/digest/, https://dirk.eddelbuettel.com/code/digest.html", + "BugReports": "https://github.com/eddelbuettel/digest/issues", + "Depends": [ + "R (>= 3.3.0)" + ], + "Imports": [ + "utils" + ], + "License": "GPL (>= 2)", + "Suggests": [ + "tinytest", + "simplermarkdown", + "rbenchmark" + ], + "VignetteBuilder": "simplermarkdown", + "Encoding": "UTF-8", + "NeedsCompilation": "yes", + "Author": "Dirk Eddelbuettel [aut, cre] (ORCID: ), Antoine Lucas [ctb] (ORCID: ), Jarek Tuszynski [ctb], Henrik Bengtsson [ctb] (ORCID: ), Simon Urbanek [ctb] (ORCID: ), Mario Frasca [ctb], Bryan Lewis [ctb], Murray Stokely [ctb], Hannes Muehleisen [ctb] (ORCID: ), Duncan Murdoch [ctb], Jim Hester [ctb] (ORCID: ), Wush Wu [ctb] (ORCID: ), Qiang Kou [ctb] (ORCID: ), Thierry Onkelinx [ctb] (ORCID: ), Michel Lang [ctb] (ORCID: ), Viliam Simko [ctb], Kurt Hornik [ctb] (ORCID: ), Radford Neal [ctb] (ORCID: ), Kendon Bell [ctb] (ORCID: ), Matthew de Queljoe [ctb], Dmitry Selivanov [ctb] (ORCID: ), Ion Suruceanu [ctb] (ORCID: ), Bill Denney [ctb] (ORCID: ), Dirk Schumacher [ctb], András Svraka [ctb] (ORCID: ), Sergey Fedorov [ctb] (ORCID: ), Will Landau [ctb] (ORCID: ), Floris Vanderhaeghe [ctb] (ORCID: ), Kevin Tappe [ctb], Harris McGehee [ctb], Tim Mastny [ctb], Aaron Peikert [ctb] (ORCID: ), Mark van der Loo [ctb] (ORCID: ), Chris Muir [ctb] (ORCID: ), Moritz Beller [ctb] (ORCID: ), Sebastian Campbell [ctb] (ORCID: ), Winston Chang [ctb] (ORCID: ), Dean Attali [ctb] (ORCID: ), Michael Chirico [ctb] (ORCID: ), Kevin Ushey [ctb] (ORCID: ), Carl Pearson [ctb] (ORCID: )", + "Maintainer": "Dirk Eddelbuettel ", + "Repository": "CRAN" + }, "evaluate": { "Package": "evaluate", "Version": "1.0.5", diff --git a/test_loadfast.R b/test_loadfast.R index 075800d..7209e4f 100644 --- a/test_loadfast.R +++ b/test_loadfast.R @@ -395,7 +395,8 @@ repo_devpackage_path_quoted <- encodeString(repo_devpackage_path, quote = "\"") s4_digest_object_line <- "obj <- animal('Rex', 'dog', 4)" s4_digest_report_line <- paste( "pkg_attr <- attr(class(obj), 'package')", - "cat(if (is.null(names(pkg_attr))) 'unnamed' else 'named', sep = '\\n')", + "cat(sprintf('HASH=%s', digest::digest(obj)), sep = '\\n')", + "cat(sprintf('PKG_ATTR=%s', if (is.null(names(pkg_attr))) 'unnamed' else 'named'), sep = '\\n')", sep = "\n" ) @@ -411,8 +412,10 @@ s4_digest_loadall <- run_rscript(c( s4_digest_report_line )) -s4_digest_loadfast_lines <- tail(s4_digest_loadfast$output, 1L) -s4_digest_loadall_lines <- tail(s4_digest_loadall$output, 1L) +s4_digest_loadfast_hash_line <- grep("^HASH=", s4_digest_loadfast$output, value = TRUE) +s4_digest_loadall_hash_line <- grep("^HASH=", s4_digest_loadall$output, value = TRUE) +s4_digest_loadfast_pkg_attr_line <- grep("^PKG_ATTR=", s4_digest_loadfast$output, value = TRUE) +s4_digest_loadall_pkg_attr_line <- grep("^PKG_ATTR=", s4_digest_loadall$output, value = TRUE) check("S4 digest repro: load_fast script succeeds", quote( s4_digest_loadfast$status == 0L @@ -422,12 +425,36 @@ check("S4 digest repro: pkgload script succeeds", quote( s4_digest_loadall$status == 0L )) +check("S4 digest repro: load_fast emitted hash line", quote( + length(s4_digest_loadfast_hash_line) == 1L +)) + +check("S4 digest repro: pkgload emitted hash line", quote( + length(s4_digest_loadall_hash_line) == 1L +)) + +check("S4 digest repro: load_fast emitted package attr line", quote( + length(s4_digest_loadfast_pkg_attr_line) == 1L +)) + +check("S4 digest repro: pkgload emitted package attr line", quote( + length(s4_digest_loadall_pkg_attr_line) == 1L +)) + check("S4 digest repro: load_fast leaves unnamed package attr", quote( - identical(s4_digest_loadfast_lines[[1L]], "unnamed") + length(s4_digest_loadfast_pkg_attr_line) == 1L && + identical(s4_digest_loadfast_pkg_attr_line[[1L]], "PKG_ATTR=unnamed") )) check("S4 digest repro: pkgload leaves unnamed package attr", quote( - identical(s4_digest_loadall_lines[[1L]], "unnamed") + length(s4_digest_loadall_pkg_attr_line) == 1L && + identical(s4_digest_loadall_pkg_attr_line[[1L]], "PKG_ATTR=unnamed") +)) + +check("S4 digest repro: load_fast matches pkgload hash", quote( + length(s4_digest_loadfast_hash_line) == 1L && + length(s4_digest_loadall_hash_line) == 1L && + identical(s4_digest_loadfast_hash_line[[1L]], s4_digest_loadall_hash_line[[1L]]) )) # --- R6 classes --- From dbd9baaa6c2c3c7d2e458a0805c457b115e98160 Mon Sep 17 00:00:00 2001 From: Felix Andreas Date: Wed, 22 Apr 2026 16:33:55 +0200 Subject: [PATCH 5/5] Update test_loadfast.R --- test_loadfast.R | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/test_loadfast.R b/test_loadfast.R index 7209e4f..6ca54e3 100644 --- a/test_loadfast.R +++ b/test_loadfast.R @@ -74,12 +74,7 @@ capture_conditions <- function(expr) { run_rscript <- function(lines) { script_path <- tempfile("loadfast_script_", fileext = ".R") - renv_activate_path <- normalizePath(file.path("renv", "activate.R"), mustWork = TRUE) - script_lines <- c( - sprintf("source(%s)", encodeString(renv_activate_path, quote = "\"")), - lines - ) - writeLines(script_lines, script_path) + writeLines(lines, script_path) on.exit(unlink(script_path), add = TRUE) output <- system2( file.path(R.home("bin"), "Rscript"),