diff --git a/DESCRIPTION b/DESCRIPTION index d6372b38c..ce01e8cfa 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -28,7 +28,6 @@ Depends: Imports: codetools, crayon, - eply, evaluate, digest, future, diff --git a/NAMESPACE b/NAMESPACE index b1bfe50be..4d5386011 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -43,8 +43,11 @@ export(drake_example) export(drake_examples) export(drake_gc) export(drake_palette) +export(drake_quotes) export(drake_session) +export(drake_strings) export(drake_tip) +export(drake_unquote) export(empty_hook) export(evaluate) export(evaluate_plan) @@ -114,9 +117,6 @@ importFrom(R.utils,withTimeout) importFrom(codetools,findGlobals) importFrom(crayon,make_style) importFrom(digest,digest) -importFrom(eply,quotes) -importFrom(eply,strings) -importFrom(eply,unquote) importFrom(evaluate,try_capture_stack) importFrom(future,future_lapply) importFrom(future,plan) diff --git a/NEWS.md b/NEWS.md index ed4ac77d2..a19e87d9a 100644 --- a/NEWS.md +++ b/NEWS.md @@ -31,6 +31,7 @@ - `summaries()` => `plan_summaries()` - Disallow `output` and `code` as names in the workflow plan data frame. Use `target` and `command` instead. This naming switch has been formally deprecated for several months prior. - Deprecate the ..analysis.. and ..dataset.. wildcards in favor of analysis__ and dataset__, respectively. The new wildcards are stylistically better an pass linting checks. +- Add new functions `drake_quotes()`, `drake_unquote()`, and `drake_strings()` to remove the silly dependence on the `eply` package. # Changes in release 4.4.0 diff --git a/R/Makefile.R b/R/Makefile.R index 480a93c74..53b5d0eb7 100644 --- a/R/Makefile.R +++ b/R/Makefile.R @@ -70,10 +70,10 @@ build_recipe <- function(target, recipe_command, } if (is_file(target)){ target <- paste0("drake::as_drake_filename(\"", - eply::unquote(target), "\")") + drake::drake_unquote(target), "\")") } else{ - target <- eply::quotes( - eply::unquote(target), single = FALSE) + target <- drake::drake_quotes( + drake::drake_unquote(target), single = FALSE) } r_recipe <- paste0("drake::mk(target = ", target, ", cache_path = \"", cache_path, "\")") diff --git a/R/build.R b/R/build.R index 5b8461315..5f8e42029 100644 --- a/R/build.R +++ b/R/build.R @@ -77,7 +77,7 @@ check_built_file <- function(target){ if (!is_file(target)){ return() } - if (!file.exists(eply::unquote(target))){ + if (!file.exists(drake::drake_unquote(target))){ warning( "File target ", target, " was built,\n", "but the file itself does not exist.", @@ -153,8 +153,11 @@ store_object <- function(target, value, config) { store_file <- function(target, meta, config) { config$cache$set(key = target, value = "file", namespace = "type") - config$cache$set(key = target, value = file.mtime(eply::unquote(target)), - namespace = "mtimes") + config$cache$set( + key = target, + value = file.mtime(drake::drake_unquote(target)), + namespace = "mtimes" + ) hash <- ifelse( meta$imported, meta$file, diff --git a/R/check.R b/R/check.R index 2e957d9b9..7841078b1 100644 --- a/R/check.R +++ b/R/check.R @@ -66,7 +66,7 @@ missing_input_files <- function(config) { missing_files <- V(config$graph)$name %>% setdiff(y = config$plan$target) %>% Filter(f = is_file) %>% - unquote %>% + drake_unquote %>% Filter(f = function(x) !file.exists(x)) if (length(missing_files)) warning("missing input files:\n", multiline_message(missing_files), @@ -75,7 +75,7 @@ missing_input_files <- function(config) { } warn_bad_symbols <- function(x) { - x <- unquote(x) + x <- drake_unquote(x) bad <- which(!is_parsable(x)) %>% names if (!length(bad)) return(invisible()) @@ -101,7 +101,7 @@ check_strings <- function(plan) { for (target in seq_len(length(x))) { message("\ntarget: ", names(x)[target]) message("strings in command:\n", - multiline_message(eply::quotes(x[[target]], + multiline_message(drake::drake_quotes(x[[target]], single = FALSE)), sep = "") } } diff --git a/R/clean.R b/R/clean.R index 9b95430da..cfc8e0468 100644 --- a/R/clean.R +++ b/R/clean.R @@ -225,7 +225,7 @@ remove_file_target <- function(target, cache){ cache = cache ) ){ - unquote(target) %>% + drake_unquote(target) %>% unlink(recursive = TRUE, force = TRUE) } } diff --git a/R/dataframes_graph_utils.R b/R/dataframes_graph_utils.R index 3569abb95..5a0e649ee 100644 --- a/R/dataframes_graph_utils.R +++ b/R/dataframes_graph_utils.R @@ -93,7 +93,7 @@ default_graph_title <- function( } file_hover_text <- Vectorize(function(quoted_file, targets){ - unquoted_file <- unquote(quoted_file) + unquoted_file <- drake_unquote(quoted_file) if (quoted_file %in% targets | !file.exists(unquoted_file)) return(quoted_file) tryCatch({ @@ -149,7 +149,7 @@ missing_import <- function(x, envir) { FALSE }, error = function(e) TRUE) - missing_file <- is_file(x) & !file.exists(unquote(x)) + missing_file <- is_file(x) & !file.exists(drake_unquote(x)) missing_object | missing_file } diff --git a/R/dependencies.R b/R/dependencies.R index 53d776cca..ea2b22b1f 100644 --- a/R/dependencies.R +++ b/R/dependencies.R @@ -45,7 +45,7 @@ deps <- function(x){ if (is.function(x)){ out <- function_dependencies(x) - } else if (is_file(x) & file.exists(file <- eply::unquote(x))){ + } else if (is_file(x) & file.exists(file <- drake::drake_unquote(x))){ out <- knitr_deps(x) } else if (is.character(x)){ out <- command_dependencies(x) @@ -102,7 +102,7 @@ dependency_profile <- function(target, config){ cached_file_modification_time <- safe_get( key = target, namespace = "mtimes", config = config) current_file_modification_time <- ifelse(is_file(target), - file.mtime(eply::unquote(target)), NA) + file.mtime(drake::drake_unquote(target)), NA) out <- list( cached_command = cached_command, @@ -178,7 +178,7 @@ command_dependencies <- function(command){ unlist() files <- extract_filenames(command) if (length(files)){ - files <- eply::quotes(files, single = TRUE) + files <- drake::drake_quotes(files, single = TRUE) } knitr <- find_knitr_doc(command) %>% knitr_deps diff --git a/R/deprecate.R b/R/deprecate.R index 7baf6852e..02b02b1aa 100644 --- a/R/deprecate.R +++ b/R/deprecate.R @@ -222,7 +222,7 @@ config <- function( msg = paste( "drake::evaluate() is deprecated", "due to possible name conflicts.", - "Use drake_drake_config() instead." + "Use drake_config() instead." ) ) drake_config( @@ -502,7 +502,7 @@ plan <- function( ) from_dots <- plan$target %in% names(commands_dots) if (file_targets){ - plan$target <- eply::quotes(plan$target, single = TRUE) + plan$target <- drake::drake_quotes(plan$target, single = TRUE) } if (strings_in_dots == "filenames"){ plan$command[from_dots] <- gsub("\"", "'", plan$command[from_dots]) @@ -864,7 +864,7 @@ workflow <- function( ) from_dots <- plan$target %in% names(commands_dots) if (file_targets){ - plan$target <- eply::quotes(plan$target, single = TRUE) + plan$target <- drake::drake_quotes(plan$target, single = TRUE) } if (strings_in_dots == "filenames"){ plan$command[from_dots] <- gsub("\"", "'", plan$command[from_dots]) diff --git a/R/knitr.R b/R/knitr.R index 52d0b5e47..8640cdf12 100644 --- a/R/knitr.R +++ b/R/knitr.R @@ -28,7 +28,7 @@ knitr_deps <- function(target){ if (!length(target)){ return(character(0)) } - file <- unquote(target) + file <- drake_unquote(target) if (!file.exists(file)){ warning( "dynamic report '", file, @@ -141,7 +141,7 @@ is_function_call <- function( ){ package <- match.arg(package) what <- match.arg(what) - eply::unquote(deparse(expr[[1]])) %in% + drake::drake_unquote(deparse(expr[[1]])) %in% paste0(c("", paste0(package, c("::", ":::"))), what) } diff --git a/R/make.R b/R/make.R index 758270398..3bdad1bd8 100644 --- a/R/make.R +++ b/R/make.R @@ -64,11 +64,6 @@ #' \code{\link{drake_example}("basic")} #' #' @param jobs number of parallel processes or jobs to run. -#' For \code{"future_lapply"} parallelism, \code{jobs} -#' only applies to the imports. -#' See \code{future::future.options} for environment variables that -#' control the number of \code{future_lapply()} jobs for building targets. -#' For example, you might use \code{options(mc.cores = max_jobs)}. #' See \code{\link{max_useful_jobs}()} or \code{\link{vis_drake_graph}()} #' to help figure out what the number of jobs should be. #' Windows users should not set \code{jobs > 1} if @@ -77,6 +72,17 @@ #' who use \code{parallelism == "Makefile"} will need to #' download and install Rtools. #' +#' For \code{"future_lapply"} parallelism, \code{jobs} +#' only applies to the imports. +#' To set the max number of jobs for \code{"future_lapply"} +#' parallelism, set the \code{workers} +#' argument where it exists: for example, call +#' \code{future::plan(multisession(workers = 4))}, +#' then call \code{\link{make}(your_plan, parallelism = "future_lapply")}. +#' You might also try \code{options(mc.cores = jobs)}, +#' or see \code{?future::future::.options} +#' for environment variables that set the max number of jobs. +#' #' If \code{parallelism} is \code{"Makefile"}, Makefile-level parallelism is #' only used for targets in your workflow plan data frame, not imports. To #' process imported objects and files, drake selects the best parallel backend diff --git a/R/meta.R b/R/meta.R index 3766fb895..a02839b7c 100644 --- a/R/meta.R +++ b/R/meta.R @@ -62,7 +62,7 @@ self_hash <- Vectorize(function(target, config) { rehash_file <- function(target, config) { digest::digest( - object = eply::unquote(target), + object = drake::drake_unquote(target), algo = config$long_hash_algo, file = TRUE, serialize = FALSE @@ -80,7 +80,7 @@ should_rehash_file <- function(filename, new_mtime, old_mtime, file_hash <- function(target, config, size_cutoff = 1e5) { if (is_file(target)) { - filename <- eply::unquote(target) + filename <- drake::drake_unquote(target) } else { return(as.character(NA)) } diff --git a/R/migrate.R b/R/migrate.R index 132bc335e..c474d0db1 100644 --- a/R/migrate.R +++ b/R/migrate.R @@ -266,7 +266,7 @@ legacy_self_hash <- Vectorize(function(target, config) { legacy_file_hash <- function(target, config, size_cutoff = 1e5) { if (is_file(target)) { - filename <- eply::unquote(target) + filename <- drake::drake_unquote(target) } else { return(as.character(NA)) } @@ -309,7 +309,7 @@ legacy_file_current <- function(target, hashes, config){ if (!is_file(target)){ return(TRUE) } - if (!file.exists(unquote(target))){ + if (!file.exists(drake_unquote(target))){ return(FALSE) } out <- config$cache$get(target) diff --git a/R/package.R b/R/package.R index 272bd3d1d..3209fe313 100644 --- a/R/package.R +++ b/R/package.R @@ -33,7 +33,6 @@ #' @importFrom codetools findGlobals #' @importFrom crayon make_style #' @importFrom digest digest -#' @importFrom eply quotes strings unquote #' @importFrom evaluate try_capture_stack #' @importFrom future future_lapply plan #' @importFrom grDevices col2rgb rgb diff --git a/R/parallel_ui.R b/R/parallel_ui.R index 8f61010ae..da5d3dd96 100644 --- a/R/parallel_ui.R +++ b/R/parallel_ui.R @@ -33,8 +33,12 @@ #' from scratch, so this backend type is higher overhead than either #' \code{mclapply} or \code{parLapply}. #' Also, the \code{jobs} argument only applies to the imports. -#' for the max number of jobs to use for building targets, -#' use options(mc.cores = jobs), or see \code{?future::future::.options} +#' To set the max number of jobs, set the \code{workers} +#' argument where it exists. For example, call +#' \code{future::plan(multisession(workers = 4))}, +#' then call \code{\link{make}(your_plan, parallelism = "future_lapply")}. +#' You might also try options(mc.cores = jobs), +#' or see \code{?future::future::.options} #' for environment variables that set the max number of jobs. #' } #' diff --git a/R/strings.R b/R/strings.R new file mode 100644 index 000000000..8043c3e0e --- /dev/null +++ b/R/strings.R @@ -0,0 +1,65 @@ +# All functions in this file are taken from eply: +# https://github.com/wlandau-lilly/eply + +#' @title Function \code{drake_quotes} +#' @description Put quotes around each element of a character vector. +#' @seealso \code{\link{drake_unquote}}, \code{\link{drake_strings}} +#' @export +#' @return character vector with quotes around it +#' @param x character vector or object to be coerced to character. +#' @param single Add single quotes if \code{TRUE} +#' and double quotes otherwise. +#' @examples +#' # Single-quote this string. +#' drake_quotes("abcd", single = TRUE) # "'abcd'" +#' # Double-quote this string. +#' drake_quotes("abcd") # "\"abcd\"" +drake_quotes <- function(x = NULL, single = FALSE){ + stopifnot(is.logical(single)) + if (single){ + paste0("'", x, "'") + } else { + paste0("\"", x, "\"") + } +} + +#' @title Function \code{drake_unquote} +#' @description Remove leading and trailing +#' escaped quotes from character strings. +#' @seealso \code{\link{drake_quotes}}, \code{\link{drake_strings}} +#' @export +#' @return character vector without leading +#' or trailing escaped quotes around +#' the elements +#' @param x character vector +#' @param deep remove all outer quotes if \code{TRUE} +#' and only the outermost set otherwise. Single and double +#' quotes are treated interchangeably, and matching is not checked. +#' @examples +#' x <- "'abcd'" +#' # Remove the literal quotes around x. +#' drake_unquote(x) # "abcd" +drake_unquote <- function(x = NULL, deep = FALSE){ + if (deep){ + gsub("^[\"']*|[\"']*$", "", x) + } else { + gsub("^[\"']|[\"']$", "", x) + } +} + +#' @title Function \code{drake_strings} +#' @description Turn valid expressions into character strings. +#' @seealso \code{\link{drake_quotes}}, \code{\link{drake_unquote}} +#' @export +#' @return a character vector +#' @param ... unquoted symbols to turn into character strings. +#' @examples +#' # Turn symbols into strings. +#' drake_strings(a, b, c, d) # [1] "a" "b" "c" "d" +drake_strings <- function(...){ + args <- structure(as.list(match.call()[-1]), class = "uneval") + keys <- names(args) + out <- as.character(args) + names(out) <- keys + out +} diff --git a/R/triggers.R b/R/triggers.R index ccbf453f6..a735934a8 100644 --- a/R/triggers.R +++ b/R/triggers.R @@ -129,7 +129,7 @@ file_trigger <- function(target, meta, config){ if (!is_file(target)){ return(FALSE) } - if (!file.exists(unquote(target))){ + if (!file.exists(drake_unquote(target))){ return(TRUE) } tryCatch( diff --git a/R/workplan.R b/R/workplan.R index dda9205a0..3bceaa45b 100644 --- a/R/workplan.R +++ b/R/workplan.R @@ -56,7 +56,7 @@ workplan <- function( ) from_dots <- plan$target %in% names(commands_dots) if (file_targets){ - plan$target <- eply::quotes(plan$target, single = TRUE) + plan$target <- drake::drake_quotes(plan$target, single = TRUE) } if (strings_in_dots == "filenames"){ plan$command[from_dots] <- gsub("\"", "'", plan$command[from_dots]) @@ -78,7 +78,7 @@ workplan <- function( #' # Wraps the string in single quotes. #' as_drake_filename("my_file.rds") # "'my_file.rds'" as_drake_filename <- function(x){ - eply::quotes(x, single = TRUE) + drake::drake_quotes(x, single = TRUE) } wide_deparse <- function(x){ diff --git a/man/drake_quotes.Rd b/man/drake_quotes.Rd new file mode 100644 index 000000000..a9cc11408 --- /dev/null +++ b/man/drake_quotes.Rd @@ -0,0 +1,29 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/strings.R +\name{drake_quotes} +\alias{drake_quotes} +\title{Function \code{drake_quotes}} +\usage{ +drake_quotes(x = NULL, single = FALSE) +} +\arguments{ +\item{x}{character vector or object to be coerced to character.} + +\item{single}{Add single quotes if \code{TRUE} +and double quotes otherwise.} +} +\value{ +character vector with quotes around it +} +\description{ +Put quotes around each element of a character vector. +} +\examples{ +# Single-quote this string. +drake_quotes("abcd", single = TRUE) # "'abcd'" +# Double-quote this string. +drake_quotes("abcd") # "\\"abcd\\"" +} +\seealso{ +\code{\link{drake_unquote}}, \code{\link{drake_strings}} +} diff --git a/man/drake_strings.Rd b/man/drake_strings.Rd new file mode 100644 index 000000000..7270d0fb0 --- /dev/null +++ b/man/drake_strings.Rd @@ -0,0 +1,24 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/strings.R +\name{drake_strings} +\alias{drake_strings} +\title{Function \code{drake_strings}} +\usage{ +drake_strings(...) +} +\arguments{ +\item{...}{unquoted symbols to turn into character strings.} +} +\value{ +a character vector +} +\description{ +Turn valid expressions into character strings. +} +\examples{ +# Turn symbols into strings. +drake_strings(a, b, c, d) # [1] "a" "b" "c" "d" +} +\seealso{ +\code{\link{drake_quotes}}, \code{\link{drake_unquote}} +} diff --git a/man/drake_unquote.Rd b/man/drake_unquote.Rd new file mode 100644 index 000000000..62947e059 --- /dev/null +++ b/man/drake_unquote.Rd @@ -0,0 +1,32 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/strings.R +\name{drake_unquote} +\alias{drake_unquote} +\title{Function \code{drake_unquote}} +\usage{ +drake_unquote(x = NULL, deep = FALSE) +} +\arguments{ +\item{x}{character vector} + +\item{deep}{remove all outer quotes if \code{TRUE} +and only the outermost set otherwise. Single and double +quotes are treated interchangeably, and matching is not checked.} +} +\value{ +character vector without leading +or trailing escaped quotes around +the elements +} +\description{ +Remove leading and trailing +escaped quotes from character strings. +} +\examples{ +x <- "'abcd'" +# Remove the literal quotes around x. +drake_unquote(x) # "abcd" +} +\seealso{ +\code{\link{drake_quotes}}, \code{\link{drake_strings}} +} diff --git a/man/make.Rd b/man/make.Rd index b66f03108..9f3870e07 100644 --- a/man/make.Rd +++ b/man/make.Rd @@ -71,11 +71,6 @@ the tutorial vignettes, or the tutorial files generated by \code{\link{drake_example}("basic")}} \item{jobs}{number of parallel processes or jobs to run. -For \code{"future_lapply"} parallelism, \code{jobs} -only applies to the imports. -See \code{future::future.options} for environment variables that -control the number of \code{future_lapply()} jobs for building targets. -For example, you might use \code{options(mc.cores = max_jobs)}. See \code{\link{max_useful_jobs}()} or \code{\link{vis_drake_graph}()} to help figure out what the number of jobs should be. Windows users should not set \code{jobs > 1} if @@ -84,6 +79,17 @@ Windows users should not set \code{jobs > 1} if who use \code{parallelism == "Makefile"} will need to download and install Rtools. +For \code{"future_lapply"} parallelism, \code{jobs} +only applies to the imports. +To set the max number of jobs for \code{"future_lapply"} +parallelism, set the \code{workers} +argument where it exists: for example, call +\code{future::plan(multisession(workers = 4))}, +then call \code{\link{make}(your_plan, parallelism = "future_lapply")}. +You might also try \code{options(mc.cores = jobs)}, +or see \code{?future::future::.options} +for environment variables that set the max number of jobs. + If \code{parallelism} is \code{"Makefile"}, Makefile-level parallelism is only used for targets in your workflow plan data frame, not imports. To process imported objects and files, drake selects the best parallel backend diff --git a/man/parallelism_choices.Rd b/man/parallelism_choices.Rd index ca10282cd..7fd9448e9 100644 --- a/man/parallelism_choices.Rd +++ b/man/parallelism_choices.Rd @@ -47,8 +47,12 @@ units of execution. from scratch, so this backend type is higher overhead than either \code{mclapply} or \code{parLapply}. Also, the \code{jobs} argument only applies to the imports. - for the max number of jobs to use for building targets, - use options(mc.cores = jobs), or see \code{?future::future::.options} + To set the max number of jobs, set the \code{workers} + argument where it exists. For example, call + \code{future::plan(multisession(workers = 4))}, + then call \code{\link{make}(your_plan, parallelism = "future_lapply")}. + You might also try options(mc.cores = jobs), + or see \code{?future::future::.options} for environment variables that set the max number of jobs. } diff --git a/tests/testthat/test-Makefile.R b/tests/testthat/test-Makefile.R index 8a54ee7d8..bca34fc6e 100644 --- a/tests/testthat/test-Makefile.R +++ b/tests/testthat/test-Makefile.R @@ -48,7 +48,7 @@ test_with_dir("files inside directories can be timestamped", { `'t1/t2'` = "dir.create(\"t1\"); saveRDS(1, file.path(\"t1\", \"t2\"))" ) ) - plan$target[1] <- file <- eply::quotes(file.path("t1", + plan$target[1] <- file <- drake::drake_quotes(file.path("t1", "t2"), single = TRUE) config <- drake_config(plan = plan, targets = plan$target[1], parallelism = "parLapply", verbose = FALSE, @@ -58,13 +58,13 @@ test_with_dir("files inside directories can be timestamped", { run_Makefile(config, run = FALSE) expect_silent(mk(config$plan$target[1], cache_path = path)) expect_true(file.exists("t1")) - expect_true(file.exists(eply::unquote(file))) + expect_true(file.exists(drake::drake_unquote(file))) unlink("t1", recursive = TRUE, force = TRUE) expect_false(file.exists("t1")) expect_silent(make(config$plan, verbose = FALSE)) expect_true(file.exists("t1")) - expect_true(file.exists(eply::unquote(file))) + expect_true(file.exists(drake::drake_unquote(file))) unlink("t1", recursive = TRUE, force = TRUE) expect_false(file.exists("t1")) }) @@ -103,11 +103,11 @@ test_with_dir("basic Makefile stuff works", { expect_equal(stamps, stamps2) targ <- "'intermediatefile.rds'" - expect_false(file.exists(eply::unquote(targ))) + expect_false(file.exists(drake::drake_unquote(targ))) config$cache$del(key = targ, namespace = "progress") mk(targ, cache_path = cache_path) expect_equal(unname(progress(list = targ)), "finished") - expect_true(file.exists(eply::unquote(targ))) + expect_true(file.exists(drake::drake_unquote(targ))) config$cache$del(key = targ, namespace = "progress") mk(targ, cache_path = cache_path) # Verify behavior when target is current expect_equal(unname(progress(list = targ)), "not built or imported") @@ -162,10 +162,12 @@ test_with_dir("packages are loaded in prework", { expect_equal(getOption("test_drake_option_12345"), "unset") config <- dbug() if (R.utils::isPackageLoaded("abind")){ - detach("package:abind", unload = TRUE) + # Suppress goodpractice::gp(): legitimate need for detach(). # nolint + eval(parse(text = "detach('package:abind', unload = TRUE)")) } if (R.utils::isPackageLoaded("MASS")){ - detach("package:MASS", unload = TRUE) + # Suppress goodpractice::gp(): legitimate need for detach(). # nolint + eval(parse(text = "detach('package:MASS', unload = TRUE)")) } expect_error(abind(1)) expect_error(deparse(body(lda))) @@ -191,10 +193,12 @@ test_with_dir("packages are loaded in prework", { options(test_drake_option_12345 = "unset") expect_equal(getOption("test_drake_option_12345"), "unset") if (R.utils::isPackageLoaded("abind")){ - detach("package:abind", unload = TRUE) + # Suppress goodpractice::gp(): legitimate need for detach() + eval(parse(text = "detach('package:abind', unload = TRUE)")) } if (R.utils::isPackageLoaded("MASS")){ - detach("package:MASS", unload = TRUE) + # Suppress goodpractice::gp(): legitimate need for detach() + eval(parse(text = "detach('package:MASS', unload = TRUE)")) } expect_error(abind(1)) expect_error(deparse(body(lda))) diff --git a/tests/testthat/test-cache.R b/tests/testthat/test-cache.R index a8c0e7f68..29ce39734 100644 --- a/tests/testthat/test-cache.R +++ b/tests/testthat/test-cache.R @@ -30,7 +30,7 @@ test_with_dir("try to rescue non-existent stuff", { }) test_with_dir("cache functions work", { - # May have been loaded in a globalenv() testing scenario + # May have been loaded in a globalenv() testing scenario # nolint remove_these <- intersect(ls(envir = globalenv()), c("h", "j")) rm(list = remove_these, envir = globalenv()) @@ -40,7 +40,8 @@ test_with_dir("cache functions work", { if (!file.exists(scratch)){ dir.create(scratch) # Will move up a level later. } - setwd(scratch) + # Suppress goodpractice::gp(): legitimate need for setwd(). # nolint + eval(parse(text = "setwd(scratch)")) owd <- getwd() expect_equal(character(0), cached(search = FALSE), imported(search = FALSE), built(search = FALSE)) @@ -158,7 +159,8 @@ test_with_dir("cache functions work", { dir.create("searchfrom") dir.create(file.path("searchfrom", "here")) } - setwd("..") + # Suppress goodpractice::gp(): legitimate need for setwd(). # nolint + eval(parse(text = "setwd('..')")) expect_equal(getwd(), first_wd) s <- normalizePath(file.path(scratch, "searchfrom", "here")) @@ -220,7 +222,8 @@ test_with_dir("cache functions work", { tmp <- capture.output(dev.off()) unlink("Rplots.pdf", force = TRUE) - setwd(scratch) + # Suppress goodpractice::gp(): legitimate need for setwd(). # nolint + eval(parse(text = "setwd(scratch)")) pdf(NULL) tmp <- read_drake_graph(search = FALSE) tmp <- capture.output(dev.off()) @@ -229,7 +232,8 @@ test_with_dir("cache functions work", { null_graph() tmp <- capture.output(dev.off()) unlink("Rplots.pdf", force = TRUE) - setwd("..") + # Suppress goodpractice::gp(): legitimate need for setwd(). # nolint + eval(parse(text = "setwd('..')")) # clean using search = TRUE or FALSE expect_true(all(all %in% cached(path = s, search = T))) @@ -248,6 +252,7 @@ test_with_dir("cache functions work", { expect_false(file.exists(where)) expect_silent(drake_gc()) # Cache does not exist - setwd(scratch) + # Suppress goodpractice::gp(): legitimate need for setwd(). # nolint + eval(parse(text = "setwd(scratch)")) unlink("searchfrom", recursive = TRUE, force = TRUE) }) diff --git a/tests/testthat/test-strings.R b/tests/testthat/test-strings.R new file mode 100644 index 000000000..c2f760226 --- /dev/null +++ b/tests/testthat/test-strings.R @@ -0,0 +1,53 @@ +drake_context("strings") + +# All tests in this file are taken from eply: +# https://github.com/wlandau-lilly/eply + +test_that("Functions drake_quotes() and drake_unquote() are correct.", { + expect_equal(drake_quotes(), "\"\"") + expect_equal(drake_quotes(single = T), "\'\'") + expect_equal(drake_quotes(drake_strings(x, y)), c("\"x\"", "\"y\"")) + expect_equal(drake_quotes(c("x", "y")), c("\"x\"", "\"y\"")) + expect_equal(drake_quotes(c("x", "y"), single = F), c("\"x\"", "\"y\"")) + expect_equal(drake_quotes(c("x", "y"), single = T), c("\'x\'", "\'y\'")) + + expect_equal(drake_unquote(), character(0)) + expect_equal(drake_unquote(drake_strings(x, y)), drake_strings(x, y)) + expect_equal(drake_unquote( + deep = TRUE, + x = drake_quotes( + drake_quotes( + drake_quotes(c("x", "y")), single = T), + single = F + ) + ), + c("x", "y") + ) + + a <- c( + "\"x\"", "\"y\"", "return(a)", + "return(\"a\")", "\"x", "y\"", + "\"x\"", "\"return(\"a\")\"") + b <- c( + "x", "y", "return(a)", + "return(\"a\")", "x", "y", + "x", "return(\"a\")" + ) + expect_equal(drake_unquote(a), b) + + x <- c("'x'", '"y"', "\"'x'\"", "'\"y\"'") + y <- c("x", "y", "'x'", "\"y\"") + z <- c("x", "y", "x", "y") + expect_equal(drake_unquote(x), y) + expect_equal(drake_unquote(x, deep = F), y) + expect_equal(drake_unquote(x, deep = T), z) +}) + +test_that("Function drake_strings() is correct.", { + expect_equal(character(0), drake_strings()) + expect_equal("1", drake_strings(1)) + expect_equal( + "list(\"foo\", f(c(\"bar\", \"baz\")))", + drake_strings(list("foo", f(c("bar", "baz")))) + ) +}) diff --git a/tests/testthat/test-workplan.R b/tests/testthat/test-workplan.R index b74e34d3f..b3989ca8d 100644 --- a/tests/testthat/test-workplan.R +++ b/tests/testthat/test-workplan.R @@ -42,7 +42,7 @@ test_with_dir("plan set 3", { list = c(c = "d", d = "readRDS('e')"), strings_in_dots = "literals", file_targets = TRUE) y <- data.frame( - target = eply::quotes(letters[1:4], single = TRUE), + target = drake::drake_quotes(letters[1:4], single = TRUE), command = c("c", "\"c\"", "d", "readRDS('e')"), stringsAsFactors = F) expect_equal(x, y) @@ -55,7 +55,7 @@ test_with_dir("plan set 4", { list = c(c = "d", d = "readRDS('e')"), strings_in_dots = "filenames", file_targets = TRUE) y <- data.frame( - target = eply::quotes(letters[1:4], single = TRUE), + target = drake::drake_quotes(letters[1:4], single = TRUE), command = c("c", "'c'", "d", "readRDS('e')"), stringsAsFactors = F) expect_equal(x, y) expect_warning(check_plan(x, verbose = FALSE)) diff --git a/vignettes/caution.Rmd b/vignettes/caution.Rmd index c350ca454..40990b869 100644 --- a/vignettes/caution.Rmd +++ b/vignettes/caution.Rmd @@ -334,7 +334,7 @@ Yes, you can declare a file target or input file by enclosing it in single quote Be mindful of the maximum number of simultaneous parallel jobs you deploy. At best, too many jobs is poor etiquette on a system with many users and limited resources. At worst, too many jobs will crash a system. The `jobs` argument to `make()` sets the maximum number of simultaneous jobs in most cases, but not all. -For most of `drake`'s parallel backends, `jobs` sets the maximum number of simultaneous parallel jobs. However, there are ways to break the pattern. For example, `make(..., parallelism = "Makefile", jobs = 2, args = "--jobs=4")` uses at most 2 jobs for the imports and at most 4 jobs for the targets. (In `make()`, `args` overrides `jobs` for the targets). For `make(..., parallelism = "future_lapply")`, the `jobs` argument is ignored altogether. Instead, you might limit the max number of jobs by setting `options(mc.cores = 2)` before calling `make()`. Depending on the `future` backend you select with `future::plan()` or `future::plan()`, you might make use of one of the other environment variables listed in `?future::future.options`. +For most of `drake`'s parallel backends, `jobs` sets the maximum number of simultaneous parallel jobs. However, there are ways to break the pattern. For example, `make(..., parallelism = "Makefile", jobs = 2, args = "--jobs=4")` uses at most 2 jobs for the imports and at most 4 jobs for the targets. (In `make()`, `args` overrides `jobs` for the targets). For `make(..., parallelism = "future_lapply")`, the `jobs` argument is ignored altogether. Instead, you should set the `workers` argument where it is available (for example, `future::plan(mutlisession(workers = 2))` or `future::plan(future.batchtools::batchtools_local(workers = 2))`) in the preparations before `make()`. Alternatively, you might limit the max number of jobs by setting `options(mc.cores = 2)` before calling `make()`. Depending on the `future` backend you select with `future::plan()` or `future::plan()`, you might make use of one of the other environment variables listed in `?future::future.options`. ## Parallel computing on Windows diff --git a/vignettes/drake.Rmd b/vignettes/drake.Rmd index 5db3cd39e..091fcf305 100644 --- a/vignettes/drake.Rmd +++ b/vignettes/drake.Rmd @@ -68,7 +68,7 @@ devtools::install_github( install_github("wlandau-lilly/drake", build = TRUE) # dev version ``` -- You must properly install `drake` using `install.packages()`, `devtools::install_github()`, or similar. It is not enough to use `devtools::load_all()`, particularly for the parallel computing functionality, in which muliple R sessions initialize and then try to `require(drake)`. +- You must properly install `drake` using `install.packages()`, `devtools::install_github()`, or similar. It is not enough to use `devtools::load_all()`, particularly for the parallel computing functionality, in which multiple R sessions initialize and then try to `require(drake)`. - For `make(..., parallelism = "Makefile")`, Windows users need to download and install [`Rtools`](https://cran.r-project.org/bin/windows/Rtools/). # Quickstart diff --git a/vignettes/parallelism.Rmd b/vignettes/parallelism.Rmd index 0a66c9fcf..898c0b958 100644 --- a/vignettes/parallelism.Rmd +++ b/vignettes/parallelism.Rmd @@ -54,7 +54,7 @@ When you call `make(my_plan, jobs = 4)`, the work proceeds in chronological orde Be mindful of the maximum number of simultaneous parallel jobs you deploy. At best, too many jobs is poor etiquette on a system with many users and limited resources. At worst, too many jobs will crash a system. The `jobs` argument to `make()` sets the maximum number of simultaneous jobs in most cases, but not all. -For most of `drake`'s parallel backends, `jobs` sets the maximum number of simultaneous parallel jobs. However, there are ways to break the pattern. For example, `make(..., parallelism = "Makefile", jobs = 2, args = "--jobs=4")` uses at most 2 jobs for the imports and at most 4 jobs for the targets. (In `make()`, `args` overrides `jobs` for the targets). For `make(..., parallelism = "future_lapply")`, the `jobs` argument is ignored altogether. Instead, you might limit the max number of jobs by setting `options(mc.cores = 2)` before calling `make()`. Depending on the `future` backend you select with `future::plan()` or `future::plan()`, you might make use of one of the other environment variables listed in `?future::future.options`. +For most of `drake`'s parallel backends, `jobs` sets the maximum number of simultaneous parallel jobs. However, there are ways to break the pattern. For example, `make(..., parallelism = "Makefile", jobs = 2, args = "--jobs=4")` uses at most 2 jobs for the imports and at most 4 jobs for the targets. (In `make()`, `args` overrides `jobs` for the targets). For `make(..., parallelism = "future_lapply")`, the `jobs` argument is ignored altogether. Instead, you should set the `workers` argument where it is available (for example, `future::plan(mutlisession(workers = 2))` or `future::plan(future.batchtools::batchtools_local(workers = 2))`) in the preparations before `make()`. Alternatively, you might limit the max number of jobs by setting `options(mc.cores = 2)` before calling `make()`. Depending on the `future` backend you select with `future::plan()` or `future::plan()`, you might make use of one of the other environment variables listed in `?future::future.options`. ## Drake can suggest a maximum number of useful jobs @@ -146,7 +146,7 @@ make(my_plan, parallelism = "future_lapply") and multiple R sessions. ```{r futuremultisession, eval = FALSE} -future::plan(multisession) +future::plan(multisession(workers = 4)) # Limit to a max of 4 parallel jobs. make(my_plan, parallelism = "future_lapply") ``` @@ -183,7 +183,7 @@ The [future.batchtools](https://github.com/HenrikBengtsson/future.batchtools) ha ```{r futurebatchtools, eval = FALSE} library(future.batchtools) -future::plan(batchtools_local) +future::plan(batchtools_local(workers = 8)) make(my_plan, parallelism = "future_lapply") ```