Skip to content

Commit 8afb512

Browse files
Merge branch 'release/0.3.0'
2 parents a498a4d + b8e36f8 commit 8afb512

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

64 files changed

+1068
-885
lines changed

.travis.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@ matrix:
2929
- _R_CHECK_CONNECTIONS_LEFT_OPEN_=true
3030
- _R_CHECK_LENGTH_1_CONDITION_=true
3131
- _R_CHECK_LENGTH_1_LOGIC2_=true
32-
- os: osx
32+
- _R_CLASS_MATRIX_ARRAY_=true
33+
- os: osx
3334
r: oldrel
3435
- os: osx
3536
r: release

DESCRIPTION

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
Package: progressr
2-
Version: 0.2.1
2+
Version: 0.3.0
33
Title: A Unifying API for Progress Updates
4-
Description: A minimal API for reporting progress updates upstream. The design is to separate the representation of progress updates from how they are presented. What type of progress to signal is controlled by the developer. How these progress updates are rendered is controlled by the end user. For instance, some users may prefer visual feedback such as a horizontal progress bar in the terminal, whereas others may prefer auditory feedback.
4+
Description: A minimal, unifying API for scripts and packages to report progress updates. By design, it allows the developer to focus on what progress that should be reported on, without having to worry about how to present it. The end user has full control on how, where, and when to render these progress updates, e.g. in the terminal using 'utils::txtProgressBar()' or 'progress::progress_bar()', in a graphical user interface using 'utils::winProgressBar()', 'tcltk::tkProgressBar()' or 'shiny::withProgress()', via the speakers using 'beep::beepr()', or on a file system via the size of a file. Anyone can add additional, customized, progression handlers. The 'progressr' package uses R's condition framework for signaling progress updated. Because of this, progress can be reported from almost anywhere in R, e.g. from classical for and while loops, from map-reduce APIs like the 'lapply()' family of functions, 'purrr', 'plyr', and 'foreach'. It will also work with parallel processing via the 'future' framework, e.g. 'future.apply::future_lapply()', 'furrr::map()', and 'foreach' with 'doFuture'.
55
Authors@R: c(
66
person("Henrik", "Bengtsson", role=c("aut", "cre", "cph"),
77
email = "[email protected]"))
@@ -14,18 +14,15 @@ Suggests:
1414
tcltk,
1515
beepr,
1616
pbmcapply,
17-
plyr,
1817
progress,
19-
foreach,
2018
purrr,
21-
future (>= 1.15.1),
19+
foreach,
20+
plyr,
2221
doFuture,
22+
future (>= 1.16.0),
2323
future.apply,
2424
furrr,
25-
shiny,
26-
notifier
27-
Remotes:
28-
gaborcsardi/notifier@d92b1b6
25+
shiny
2926
URL: https://github.com/HenrikBengtsson/progressr
3027
BugReports: https://github.com/HenrikBengtsson/progressr/issues
3128
RoxygenNote: 7.0.2

NEWS

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,20 @@
11
Package: progressr
22
==================
33

4+
Version: 0.3.0 [2020-01-20]
5+
6+
NEW FEATURES:
7+
8+
* progressor() gained offset and slope arguments 'a' and 'b', and functional
9+
argument 'transform'.
10+
11+
* handlers() gained argument 'append' to make it easier to append handlers.
12+
13+
BUG FIXES:
14+
15+
* A progression condition with amount = 0 would not update the message.
16+
17+
418
Version: 0.2.1 [2020-01-04]
519

620
BUG FIXES:

OVERVIEW.md

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,11 @@ Design motto:
1212

1313
## Two Minimal APIs
1414

15-
| Developer's API | End-user's API |
16-
|-----------------------|-----------------------------|
17-
| `p <- progressor(n)` | `with_progress(expr)` |
18-
| `p(msg, ...)` | `handlers(...)` |
19-
| | `options(progressr.*=...)` |
15+
| Developer's API | End-user's API |
16+
|-------------------------------|-----------------------------|
17+
| `p <- progressor(n)` | `with_progress(expr)` |
18+
| `p <- progressor(along = x)` | `handlers(...)` |
19+
| `p(msg, ...)` | |
2020

2121

2222

@@ -26,12 +26,12 @@ Assume that we have a function `slow_sum()` for adding up the values in a vector
2626

2727
```r
2828
slow_sum <- function(x) {
29-
progress <- progressr::progressor(along = x)
29+
p <- progressr::progressor(along = x)
3030
sum <- 0
3131
for (kk in seq_along(x)) {
3232
Sys.sleep(0.1)
3333
sum <- sum + x[kk]
34-
progress(message = sprintf("Added %g", x[kk]))
34+
p(message = sprintf("Added %g", x[kk]))
3535
}
3636
sum
3737
}
@@ -75,7 +75,7 @@ This progress handler will present itself as:
7575
[==================>---------------------------] 40% Added 4
7676
```
7777

78-
To set the default progress handler(s) in all your R sessions, call `progressr::handlers(...)` in your <code>~/.Rprofile</code> file. An alternative, which avoids loading the **progressr** package if never used, is to set `options(progressr.handlers = progress_handler)`.
78+
To set the default progress handler(s) in all your R sessions, call `progressr::handlers(...)` in your <code>~/.Rprofile</code> file.
7979

8080

8181

R/ascii_alert_handler.R

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
#' Auditory Progression Feedback
2+
#'
3+
#' A progression handler based on `cat("\a", file=stderr())`.
4+
#'
5+
#' @inheritParams make_progression_handler
6+
#'
7+
#' @param symbol (character string) The character symbol to be outputted,
8+
#' which by default is the ASCII BEL character (`'\a'` = `'\007'`) character.
9+
#'
10+
#' @param file (connection) A [base::connection] to where output should be sent.
11+
#'
12+
#' @param \ldots Additional arguments passed to [make_progression_handler()].
13+
#'
14+
#' @example incl/ascii_alert_handler.R
15+
#'
16+
#' @export
17+
ascii_alert_handler <- function(symbol = "\a", file = stderr(), intrusiveness = getOption("progressr.intrusiveness.auditory", 5.0), target = c("terminal", "audio"), ...) {
18+
reporter <- local({
19+
list(
20+
update = function(config, state, progression, ...) {
21+
if (state$enabled && progression$amount != 0) cat(file = file, symbol)
22+
}
23+
)
24+
})
25+
26+
make_progression_handler("ascii_alert", reporter, intrusiveness = intrusiveness, ...)
27+
}

R/beepr_handler.R

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
#' Auditory Progression Feedback
2+
#'
3+
#' A progression handler for [beepr::beep()].
4+
#'
5+
#' @inheritParams make_progression_handler
6+
#'
7+
#' @param initiate,update,finish (integer) Indices of [beepr::beep()] sounds to
8+
#' play when progress starts, is updated, and completes. For silence, use `NA_integer_`.
9+
#'
10+
#' @param \ldots Additional arguments passed to [make_progression_handler()].
11+
#'
12+
#' @example incl/beepr_handler.R
13+
#'
14+
#' @section Requirements:
15+
#' This progression handler requires the \pkg{beepr} package.
16+
#'
17+
#' @export
18+
beepr_handler <- function(initiate = 2L, update = 10L, finish = 11L, intrusiveness = getOption("progressr.intrusiveness.auditory", 5.0), target = "audio", ...) {
19+
## Used for package testing purposes only when we want to perform
20+
## everything except the last part where the backend is called
21+
if (!is_fake("beepr_handler")) {
22+
beepr_beep <- beepr::beep
23+
} else {
24+
beepr_beep <- function(sound, expr) NULL
25+
}
26+
27+
beep <- function(sound) {
28+
## Silence?
29+
if (is.na(sound)) return()
30+
beepr_beep(sound)
31+
}
32+
33+
## Reporter state
34+
reporter <- local({
35+
list(
36+
initiate = function(config, state, progression, ...) {
37+
if (!state$enabled || config$times == 1L) return()
38+
beep(initiate)
39+
},
40+
41+
update = function(config, state, progression, ...) {
42+
if (!state$enabled || progression$amount == 0 || config$times <= 2L) return()
43+
beep(update)
44+
},
45+
46+
finish = function(config, state, progression, ...) {
47+
if (!state$enabled) return()
48+
beep(finish)
49+
}
50+
)
51+
})
52+
53+
make_progression_handler("beepr", reporter, intrusiveness = intrusiveness, ...)
54+
}

R/debug_handler.R

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
#' Textual Progression Feedback for Debug Purposes
2+
#'
3+
#' @inheritParams make_progression_handler
4+
#'
5+
#' @param \ldots Additional arguments passed to [make_progression_handler()].
6+
#'
7+
#' @example incl/debug_handler.R
8+
#'
9+
#' @export
10+
debug_handler <- function(interval = getOption("progressr.interval", 0), intrusiveness = getOption("progressr.intrusiveness.debug", 0), target = "terminal", ...) {
11+
reporter <- local({
12+
t_init <- NULL
13+
14+
add_to_log <- function(config, state, progression, ...) {
15+
t <- Sys.time()
16+
if (is.null(t_init)) t_init <<- t
17+
dt <- difftime(t, t_init, units = "secs")
18+
delay <- difftime(t, progression$time, units = "secs")
19+
message <- paste(c(state$message, ""), collapse = "")
20+
entry <- list(now(t), dt, delay, progression$type, state$step, config$max_steps, state$delta, message, config$clear, state$enabled, paste0(progression$status, ""))
21+
msg <- do.call(sprintf, args = c(list("%s(%.3fs => +%.3fs) %s: %d/%d (%+d) '%s' {clear=%s, enabled=%s, status=%s}"), entry))
22+
message(msg)
23+
}
24+
25+
list(
26+
reset = function(...) {
27+
t_init <<- NULL
28+
},
29+
30+
initiate = function(...) {
31+
add_to_log("initiate", ...)
32+
},
33+
34+
update = function(...) {
35+
add_to_log("update", ...)
36+
},
37+
38+
finish = function(...) {
39+
add_to_log("finish", ...)
40+
}
41+
)
42+
})
43+
44+
make_progression_handler("debug", reporter, intrusiveness = intrusiveness, ...)
45+
}

R/filesize_handler.R

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
#' Progression Updates Reflected as the Size of a File
2+
#'
3+
#' @inheritParams make_progression_handler
4+
#'
5+
#' @param file (character) A filename.
6+
#'
7+
#' @param \ldots Additional arguments passed to [make_progression_handler()].
8+
#'
9+
#' @examples
10+
#' \donttest{\dontrun{
11+
#' handlers(filesize_handler(file = "myscript.progress"))
12+
#' with_progress(y <- slow_sum(1:100))
13+
#' }}
14+
#'
15+
#' @importFrom utils file_test
16+
#' @export
17+
filesize_handler <- function(file = "default.progress", intrusiveness = getOption("progressr.intrusiveness.file", 5), target = "file", ...) {
18+
reporter <- local({
19+
set_file_size <- function(config, state, progression) {
20+
ratio <- state$step / config$max_steps
21+
size <- round(100 * ratio)
22+
current_size <- file.size(file)
23+
if (is.na(current_size)) file.create(file, showWarnings = FALSE)
24+
if (size == 0L) return()
25+
if (progression$amount == 0) return()
26+
27+
head <- sprintf("%g/%g: ", state$step, config$max_steps)
28+
nhead <- nchar(head)
29+
tail <- sprintf(" [%d%%]", round(100 * ratio))
30+
ntail <- nchar(tail)
31+
mid <- paste0(state$message, "")
32+
nmid <- nchar(mid)
33+
padding <- size - (nhead + nmid + ntail)
34+
if (padding <= 0) {
35+
msg <- paste(head, mid, tail, sep = "")
36+
if (padding < 0) msg <- substring(msg, first = 1L, last = size)
37+
} else if (padding > 0) {
38+
mid <- paste(c(mid, " ", rep(".", times = padding - 1L)), collapse = "")
39+
msg <- paste(head, mid, tail, sep = "")
40+
}
41+
42+
cat(file = file, append = FALSE, msg)
43+
}
44+
45+
list(
46+
initiate = function(config, state, progression, ...) {
47+
set_file_size(config = config, state = state, progression = progression)
48+
},
49+
50+
update = function(config, state, progression, ...) {
51+
set_file_size(config = config, state = state, progression = progression)
52+
},
53+
54+
finish = function(config, state, progression, ...) {
55+
if (config$clear) {
56+
if (file_test("-f", file)) file.remove(file)
57+
} else {
58+
set_file_size(config = config, state = state, progression = progression)
59+
}
60+
}
61+
)
62+
})
63+
64+
make_progression_handler("filesize", reporter, intrusiveness = intrusiveness, ...)
65+
}

R/handlers.R

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@
55
#' If this vector is empty, then an empty set of progression handlers will
66
#' be set.
77
#'
8+
#' @param append (logical) If FALSE, the specified progression handlers
9+
#' replace the current ones, otherwise appended to them.
10+
#'
811
#' @param on_missing (character) If `"error"`, an error is thrown if one of
912
#' the progression handlers does not exists. If `"warning"`, a warning
1013
#' is produces and the missing handlers is ignored. If `"ignore"`, the
@@ -24,12 +27,12 @@
2427
#' @example incl/handlers.R
2528
#'
2629
#' @export
27-
handlers <- function(..., on_missing = c("error", "warning", "ignore"), default = txtprogressbar_handler) {
30+
handlers <- function(..., append = FALSE, on_missing = c("error", "warning", "ignore"), default = txtprogressbar_handler) {
2831
args <- list(...)
2932

3033
## Get the current set of progression handlers?
3134
if (length(args) == 0L) {
32-
if (!is.list(default)) default <- list(default)
35+
if (!is.list(default) && !is.null(default)) default <- list(default)
3336
return(getOption("progressr.handlers", default))
3437
}
3538

@@ -82,5 +85,10 @@ handlers <- function(..., on_missing = c("error", "warning", "ignore"), default
8285
keep <- vapply(handlers, FUN = is.function, FUN.VALUE = FALSE)
8386
handlers <- handlers[keep]
8487

88+
if (append) {
89+
current <- getOption("progressr.handlers", list())
90+
if (length(current) > 0L) handlers <- c(current, handlers)
91+
}
92+
8593
options(progressr.handlers = handlers)[[1]]
8694
}

R/newline_handler.R

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
#' Textual Progression Feedback that outputs a Newline
2+
#'
3+
#' @inheritParams make_progression_handler
4+
#'
5+
#' @param symbol (character string) The character symbol to be outputted,
6+
#' which by default is the ASCII NL character (`'\n'` = `'\013'`) character.
7+
#'
8+
#' @param file (connection) A [base::connection] to where output should be sent.
9+
#'
10+
#' @param \ldots Additional arguments passed to [make_progression_handler()].
11+
#'
12+
#' @export
13+
newline_handler <- function(symbol = "\n", file = stderr(), intrusiveness = getOption("progressr.intrusiveness.debug", 0), target = "terminal", ...) {
14+
reporter <- local({
15+
list(
16+
initiate = function(...) cat(file = file, symbol),
17+
update = function(...) cat(file = file, symbol),
18+
finish = function(...) cat(file = file, symbol)
19+
)
20+
})
21+
22+
make_progression_handler("newline", reporter, intrusiveness = intrusiveness, ...)
23+
}

0 commit comments

Comments
 (0)