Skip to content

Commit

Permalink
Now stdout=FALSE sinks to null devices and stdout=NA does not interce…
Browse files Browse the repository at this point in the history
…pt output (as in previous versions of the future package) [#232]
  • Loading branch information
HenrikBengtsson committed Jul 10, 2018
1 parent 4d4f721 commit f92ffe4
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 20 deletions.
42 changes: 30 additions & 12 deletions R/Future-class.R
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,11 @@
#' @param substitute If TRUE, argument \code{expr} is
#' \code{\link[base]{substitute}()}:ed, otherwise not.
#'
#' @param stdout If TRUE, then the standard output is captured, and
#' re-outputted when \code{value()} is called. If FALSE, the
#' standard output is \emph{not} captured.
#' @param stdout If TRUE (default), then the standard output is captured,
#' and re-outputted when \code{value()} is called.
#' If FALSE, any output is silenced (by sinking it to the null device as
#' it is outputted).
#' If NA (not recommended), output is \emph{not} intercepted.
#'
#' @param globals (optional) a logical, a character vector, or a named list
#' to control how globals are handled.
Expand Down Expand Up @@ -80,7 +82,7 @@ Future <- function(expr = NULL, envir = parent.frame(), substitute = FALSE, stdo
}
}

stop_if_not(is.logical(stdout), length(stdout) == 1L, !is.na(stdout))
stop_if_not(is.logical(stdout), length(stdout) == 1L)

if (!is.null(globals)) {
stop_if_not(is.list(globals),
Expand Down Expand Up @@ -682,12 +684,23 @@ makeExpression <- function(expr, stdout = TRUE, local = TRUE, globals.onMissing
.(enter)

## Capture standard output?
if (.(stdout)) {
## NOTE: Capturing to a raw connection is much more efficient
## than to a character connection, cf.
## https://www.jottr.org/2014/05/26/captureoutput/
...future.stdout <- rawConnection(raw(0L), open = "w")
sink(...future.stdout, type = "output", append = FALSE, split = FALSE)
if (is.na(.(stdout))) { ## stdout = NA
## Don't capture, but also don't block any output
} else {
if (.(stdout)) { ## stdout = TRUE
## Capture all output
## NOTE: Capturing to a raw connection is much more efficient
## than to a character connection, cf.
## https://www.jottr.org/2014/05/26/captureoutput/
...future.stdout <- rawConnection(raw(0L), open = "w")
} else { ## stdout = FALSE
## Silence all output by sending it to the void
...future.stdout <- file(
switch(.Platform$OS.type, windows = "NUL", "/dev/null"),
open = "w"
)
}
sink(...future.stdout, type = "output", split = FALSE)
on.exit(if (!is.null(...future.stdout)) {
sink(type = "output", split = FALSE)
close(...future.stdout)
Expand Down Expand Up @@ -723,9 +736,14 @@ makeExpression <- function(expr, stdout = TRUE, local = TRUE, globals.onMissing
.(exit)
})

if (.(stdout)) {
if (is.na(.(stdout))) {
} else {
sink(type = "output", split = FALSE)
...future.result$stdout <- rawToChar(rawConnectionValue(...future.stdout))
if (.(stdout)) {
...future.result$stdout <- rawToChar(
rawConnectionValue(...future.stdout)
)
}
close(...future.stdout)
...future.stdout <- NULL
}
Expand Down
8 changes: 5 additions & 3 deletions man/Future-class.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 5 additions & 5 deletions tests/non-exportable,connections.R
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,17 @@ message("- Run-time error")

## Assert we can detect the reference
res <- tryCatch({
f <- future(cat("world\n", file = con), stdout = FALSE)
f <- future(cat("world\n", file = con), stdout = NA)
}, FutureWarning = identity)
print(res)
stopifnot(inherits(res, "FutureWarning"),
grepl("non-exportable reference", conditionMessage(res)))

## ISSUE: When using stdout = TRUE below, a connection will be opened on
## the worker (due to sink:ing), which then will be hijacked by the
## ISSUE: When using stdout = TRUE/FALSE below, a connection will be opened
## on the worker (due to sink:ing), which then will be hijacked by the
## global 'con' connection in the below expression. Because of this, we
## have to test with stdout = FALSE.
f <- future(cat("world\n", file = con), stdout = FALSE)
## have to test with stdout = NA.
f <- future(cat("world\n", file = con), stdout = NA)
res <- tryCatch({
v <- value(f)
}, error = identity)
Expand Down

0 comments on commit f92ffe4

Please sign in to comment.