Skip to content

Commit

Permalink
#106 progress bar for paginator, remove newline and OK printed messages
Browse files Browse the repository at this point in the history
bump version for change
add test for progress bar
  • Loading branch information
sckott committed Mar 25, 2019
1 parent ad7db17 commit 1ebd24f
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 29 deletions.
2 changes: 1 addition & 1 deletion DESCRIPTION
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Description: A simple HTTP client, with tools for making HTTP requests,
The package name is a play on curl, the widely used command line tool
for HTTP, and this package is built on top of the R package 'curl', an
interface to 'libcurl' (<https://curl.haxx.se/libcurl>).
Version: 0.7.3.9910
Version: 0.7.3.9931
License: MIT + file LICENSE
Authors@R: c(
person("Scott", "Chamberlain", role = c("aut", "cre"),
Expand Down
78 changes: 50 additions & 28 deletions R/paginator.R
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,15 @@
#' @param client an object of class `HttpClient`, from a call to [HttpClient]
#' @param by (character) how to paginate. Only 'query_params' supported for
#' now. In the future will support 'link_headers' and 'cursor'. See Details.
#' @param limit_param (character) the name of the limit parameter.
#' @param limit_param (character) the name of the limit parameter.
#' Default: limit
#' @param offset_param (character) the name of the offset parameter.
#' @param offset_param (character) the name of the offset parameter.
#' Default: offset
#' @param limit (numeric/integer) the maximum records wanted
#' @param limit_chunk (numeric/integer) the number by which to chunk requests,
#' e.g., 10 would be be each request gets 10 records
#' @param progress (logical) print a progress bar, using [utils::txtProgressBar].
#' Default: `FALSE`.
#' @details
#' **Methods**
#' \describe{
Expand Down Expand Up @@ -76,28 +78,28 @@
#'
#' @format NULL
#' @usage NULL
#'
#'
#' @section Methods to paginate:
#'
#'
#' Supported now:
#'
#'
#' - `query_params`: the most common way, so is the default. This method
#' involves setting how many records and what record to start at for each
#' involves setting how many records and what record to start at for each
#' request. We send these query parameters for you.
#'
#'
#' Supported later:
#'
#' - `link_headers`: link headers are URLS for the next/previous/last
#'
#' - `link_headers`: link headers are URLS for the next/previous/last
#' request given in the response header from the server. This is relatively
#' uncommon, though is recommended by JSONAPI and is implemented by a
#' well known API (GitHub).
#' uncommon, though is recommended by JSONAPI and is implemented by a
#' well known API (GitHub).
#' - `cursor`: this works by a single string given back in each response, to
#' be passed in the subsequent response, and so on until no more records
#' be passed in the subsequent response, and so on until no more records
#' remain. This is common in Solr
#'
#'
#' @return a list, with objects of class [HttpResponse()].
#' Responses are returned in the order they are passed in.
#'
#'
#' @examples \dontrun{
#' (cli <- HttpClient$new(url = "https://api.crossref.org"))
#' cc <- Paginator$new(client = cli, limit_param = "rows",
Expand All @@ -112,10 +114,18 @@
#' cc$content()
#' cc$parse()
#' lapply(cc$parse(), jsonlite::fromJSON)
#'
#'
#' # get full URLs for each request to be made
#' cc$url_fetch('works')
#' cc$url_fetch('works', query = list(query = "NSF"))
#'
#' # progress bar
#' (cli <- HttpClient$new(url = "https://api.crossref.org"))
#' cc <- Paginator$new(client = cli, limit_param = "rows",
#' offset_param = "offset", limit = 50, limit_chunk = 10,
#' progress = TRUE)
#' cc
#' cc$get('works')
#' }
Paginator <- R6::R6Class(
'Paginator',
Expand All @@ -127,6 +137,7 @@ Paginator <- R6::R6Class(
offset_param = NULL,
limit = NULL,
req = NULL,
progress = FALSE,

print = function(x, ...) {
cat("<crul paginator> ", sep = "\n")
Expand All @@ -139,21 +150,24 @@ Paginator <- R6::R6Class(
cat(paste0(" limit_param: ", self$limit_param %||% "<none>"), sep = "\n")
cat(paste0(" offset_param: ", self$offset_param %||% "<none>"), sep = "\n")
cat(paste0(" limit: ", self$limit %||% "<none>"), sep = "\n")
cat(paste0(" status: ",
cat(paste0(" progress: ", self$progress %||% ""), sep = "\n")
cat(paste0(" status: ",
if (length(private$resps) == 0) {
"not run yet"
"not run yet"
} else {
paste0(length(private$resps), " requests done")
}), sep = "\n")
invisible(self)
},

initialize = function(client, by = "query_params", limit_param, offset_param, limit, limit_chunk) {
initialize = function(client, by = "query_params", limit_param,
offset_param, limit, limit_chunk, progress = FALSE) {

## checks
if (!inherits(client, "HttpClient")) stop("'client' has to be an object of class 'HttpClient'",
if (!inherits(client, "HttpClient")) stop("'client' has to be an object of class 'HttpClient'",
call. = FALSE)
self$http_req <- client
if (by != "query_params") stop("'by' has to be 'query_params' for now",
if (by != "query_params") stop("'by' has to be 'query_params' for now",
call. = FALSE)
self$by <- by
if (!missing(limit_chunk)) {
Expand All @@ -170,12 +184,14 @@ Paginator <- R6::R6Class(
if (limit_chunk %% 1 != 0) stop("'limit' must be an integer")
}
self$limit <- limit
assert(progress, "logical")
self$progress <- progress

if (self$by == "query_params") {
# calculate pagination values
private$offset_iters <- c(0, seq(from=0, to=fround(self$limit, 10),
private$offset_iters <- c(0, seq(from=0, to=fround(self$limit, 10),
by=self$limit_chunk)[-1])
private$offset_args <- as.list(stats::setNames(private$offset_iters,
private$offset_args <- as.list(stats::setNames(private$offset_iters,
rep(self$offset_param, length(private$offset_iters))))
private$limit_chunks <- rep(self$limit_chunk, length(private$offset_iters))
diffy <- self$limit - private$offset_iters[length(private$offset_iters)]
Expand Down Expand Up @@ -257,26 +273,32 @@ Paginator <- R6::R6Class(
resps = NULL,
page = function(method, path, query, body, encode, ...) {
tmp <- list()
if (self$progress) {
pb <- utils::txtProgressBar(min = 0, max = length(private$offset_iters),
initial = 0, style = 3)
on.exit(close(pb), add = TRUE)
}
for (i in seq_along(private$offset_iters)) {
if (self$progress) utils::setTxtProgressBar(pb, i)
off <- private$offset_args[i]
off[self$limit_param] <- private$limit_chunks[i]
tmp[[i]] <- switch(
method,
get = self$http_req$get(path, query = ccp(c(query, off)), ...),
post = self$http_req$post(path, query = ccp(c(query, off)),
post = self$http_req$post(path, query = ccp(c(query, off)),
body = body, encode = encode, ...),
put = self$http_req$put(path, query = ccp(c(query, off)),
put = self$http_req$put(path, query = ccp(c(query, off)),
body = body, encode = encode, ...),
patch = self$http_req$patch(path, query = ccp(c(query, off)),
patch = self$http_req$patch(path, query = ccp(c(query, off)),
body = body, encode = encode, ...),
delete = self$http_req$delete(path, query = ccp(c(query, off)),
delete = self$http_req$delete(path, query = ccp(c(query, off)),
body = body, encode = encode, ...),
head = self$http_req$head(path, ...)
)
cat("\n")
# cat("\n")
}
private$resps <- tmp
message("OK\n")
# message("OK\n")
}
)
)
Expand Down
11 changes: 11 additions & 0 deletions man/Paginator.Rd

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

10 changes: 10 additions & 0 deletions tests/testthat/test-paginator.R
Original file line number Diff line number Diff line change
Expand Up @@ -128,3 +128,13 @@ test_that("Paginator fails well", {
"offset_param must be of class character"
)
})

test_that("Paginator progress option", {
skip_on_cran()

cli <- HttpClient$new(url = "https://api.crossref.org")
cc <- Paginator$new(client = cli, limit_param = "rows",
offset_param = "offset", limit = 20, limit_chunk = 10,
progress = TRUE)
expect_output(cc$get('works'), "====")
})

0 comments on commit 1ebd24f

Please sign in to comment.