Skip to content

Commit 5c524e3

Browse files
Future "evaluator" function that implements the new FutureBackend should never be called
1 parent 83e22f2 commit 5c524e3

10 files changed

+48
-171
lines changed

R/backend_api-ClusterFutureBackend-class.R

+1-5
Original file line numberDiff line numberDiff line change
@@ -51,11 +51,7 @@
5151
#'
5252
#' @export
5353
cluster <- function(..., persistent = FALSE, workers = availableWorkers(), envir = parent.frame()) {
54-
f <- Future(..., envir = envir)
55-
f[["workers"]] <- workers
56-
f[["persistent"]] <- persistent
57-
class(f) <- c("ClusterFuture", "MultiprocessFuture", "Future")
58-
f
54+
stop("INTERNAL ERROR: The future::cluster() function implements the FutureBackend and should never be called directly")
5955
}
6056
class(cluster) <- c("cluster", "multiprocess", "future", "function")
6157
attr(cluster, "init") <- TRUE

R/backend_api-MulticoreFutureBackend-class.R

+1-4
Original file line numberDiff line numberDiff line change
@@ -69,10 +69,7 @@
6969
#'
7070
#' @export
7171
multicore <- function(..., workers = availableCores(constraints = "multicore"), envir = parent.frame()) {
72-
f <- Future(..., envir = envir)
73-
f[["workers"]] <- workers
74-
class(f) <- c("MulticoreFuture", "MultiprocessFuture", "Future")
75-
f
72+
stop("INTERNAL ERROR: The future::multicore() function implements the FutureBackend and should never be called directly")
7673
}
7774
class(multicore) <- c("multicore", "multiprocess", "future", "function")
7875

R/backend_api-MultisessionFutureBackend-class.R

+1-4
Original file line numberDiff line numberDiff line change
@@ -65,10 +65,7 @@
6565
#'
6666
#' @export
6767
multisession <- function(..., workers = availableCores(), lazy = FALSE, rscript_libs = .libPaths(), envir = parent.frame()) {
68-
f <- Future(..., lazy = lazy, envir = envir)
69-
f[["workers"]] <- workers
70-
class(f) <- c("MultisessionFuture", "MultiprocessFuture", "Future")
71-
f
68+
stop("INTERNAL ERROR: The future::multisession() function implements the FutureBackend and should never be called directly")
7269
}
7370
class(multisession) <- c("multisession", "cluster", "multiprocess", "future", "function")
7471
attr(multisession, "init") <- TRUE

R/backend_api-SequentialFutureBackend-class.R

+1-3
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,7 @@
2727
#' @aliases uniprocess
2828
#' @export
2929
sequential <- function(..., envir = parent.frame()) {
30-
f <- Future(..., envir = envir)
31-
class(f) <- c("SequentialFuture", "UniprocessFuture", "Future")
32-
f
30+
stop("INTERNAL ERROR: The future::sequential() function implements the FutureBackend and should never be called directly")
3331
}
3432
class(sequential) <- c("sequential", "uniprocess", "future", "function")
3533

R/utils_api-plan.R

+24-21
Original file line numberDiff line numberDiff line change
@@ -103,28 +103,31 @@
103103
## recursive loop caused by other plan() calls.
104104
attr(evaluator, "init") <- "done"
105105

106-
## Create dummy future to trigger setup (minimum overhead)
107-
f <- evaluator(NA, label = "future-plan-test",
108-
globals = FALSE, lazy = FALSE)
109-
110-
## Cleanup, by resolving it
111-
## (otherwise the garbage collector would have to do it)
112-
res <- tryCatch({
113-
value(f)
114-
}, FutureError = identity)
115-
if (inherits(res, "FutureError")) {
116-
res[["message"]] <- paste0(
117-
"Initialization of plan() failed, because the test future used for validation failed. The reason was: ", conditionMessage(res))
118-
stop(res)
119-
}
120-
121-
if (!identical(res, NA)) {
122-
res <- if (is.null(res)) {
123-
"NULL"
124-
} else {
125-
commaq(res)
106+
## Non-FutureBackend backends are initiated by calling the evaluator
107+
if (is.null(attr(evaluator, "backend"))) {
108+
## Create dummy future to trigger setup (minimum overhead)
109+
f <- evaluator(NA, label = "future-plan-test",
110+
globals = FALSE, lazy = FALSE)
111+
112+
## Cleanup, by resolving it
113+
## (otherwise the garbage collector would have to do it)
114+
res <- tryCatch({
115+
value(f)
116+
}, FutureError = identity)
117+
if (inherits(res, "FutureError")) {
118+
res[["message"]] <- paste0(
119+
"Initialization of plan() failed, because the test future used for validation failed. The reason was: ", conditionMessage(res))
120+
stop(res)
121+
}
122+
123+
if (!identical(res, NA)) {
124+
res <- if (is.null(res)) {
125+
"NULL"
126+
} else {
127+
commaq(res)
128+
}
129+
stop(FutureError(sprintf("Initialization of plan() failed, because the value of the test future is not NA as expected: %s", res)))
126130
}
127-
stop(FutureError(sprintf("Initialization of plan() failed, because the value of the test future is not NA as expected: %s", res)))
128131
}
129132

130133
if (debug) {

tests/cluster-missing-future-pkg.R

+1
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ for (type in types) {
4747

4848
res <- tryCatch({
4949
plan(cluster, workers = cl)
50+
value(future(NA))
5051
}, error = identity)
5152
print(res)
5253
stopifnot(inherits(res, "FutureError"))

tests/future,labels.R

+9-5
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,15 @@ for (strategy in strategies) {
1111
for (label in list(NULL, sprintf("strategy = %s", strategy))) {
1212
fcn <- get(strategy, mode = "function")
1313
stopifnot(inherits(fcn, strategy))
14-
f <- fcn(42, label = label)
15-
print(f)
16-
stopifnot(identical(f$label, label))
17-
v <- value(f)
18-
stopifnot(v == 42)
14+
15+
## Non-FutureBackend:s 'evaluator' functions can be called directly
16+
if (is.null(attr(fcn, "backend"))) {
17+
f <- fcn(42, label = label)
18+
print(f)
19+
stopifnot(identical(f$label, label))
20+
v <- value(f)
21+
stopifnot(v == 42)
22+
}
1923

2024
f <- future(42, label = label)
2125
print(f)

tests/globals,tricky.R

+4-3
Original file line numberDiff line numberDiff line change
@@ -141,16 +141,15 @@ for (cores in 1:availCores) {
141141
message(sprintf("value(b) = %g", value(b)))
142142
stopifnot(value(b) == 2)
143143

144-
145144
## BUG FIX: In future (<= 1.0.0) a global 'pkg' would be
146145
## overwritten by the name of the last package attached
147146
## by the future.
148147
pkg <- "foo"
149-
f <- sequential({ pkg })
148+
f <- future({ pkg })
150149
v <- value(f)
151150
message(sprintf("value(f) = %s", sQuote(v)))
152151
stopifnot(pkg == "foo", v == "foo")
153-
152+
154153
message(sprintf("Method for identifying globals: '%s' ... DONE", method))
155154
}
156155

@@ -178,6 +177,8 @@ for (cores in 1:availCores) {
178177
v <- value(f)
179178
message(sprintf("value(f) = %s", sQuote(v)))
180179
stopifnot(v == TRUE)
180+
181+
plan(sequential)
181182
} ## for (strategy ...)
182183

183184
message(sprintf("Testing with %d cores ... DONE", cores))

tests/multicore.R

-124
This file was deleted.

tests/plan.R

+6-2
Original file line numberDiff line numberDiff line change
@@ -190,8 +190,12 @@ plan(cluster, workers = cl)
190190
## %plan% can operate on any expression, so it
191191
## works just as an withPlan({ ... }, plan = ...)
192192
fun <- { plan("next") } %plan% sequential
193-
f <- fun(1)
194-
stopifnot(inherits(f, "SequentialFuture"), !f$lazy, inherits(f, "SequentialFuture"))
193+
194+
## Non-FutureBackend:s should be called directly
195+
if (is.null(attr(fun, "backend"))) {
196+
f <- fun(1)
197+
stopifnot(inherits(f, "SequentialFuture"), !f$lazy, inherits(f, "SequentialFuture"))
198+
}
195199

196200
x %<-% { a <- 1 } %plan% sequential
197201
stopifnot(inherits(plan("next"), "cluster"))

0 commit comments

Comments
 (0)