Skip to content

Commit d4df9a0

Browse files
authored
Merge pull request #308 from cmu-delphi/dev
1.2.1 release
2 parents b998e1d + c7b094d commit d4df9a0

19 files changed

+279
-218
lines changed

.github/workflows/R-CMD-check-full.yaml

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,21 +19,26 @@ jobs:
1919
fail-fast: false
2020
matrix:
2121
config:
22+
# Mac latest release
2223
- { os: macos-latest, r: "release" }
24+
# Oldest R version we claim to support
25+
- { os: macos-latest, r: "3.5" }
2326

27+
# Windows latest release
2428
- { os: windows-latest, r: "release" }
25-
# Use 3.6 to trigger usage of RTools35
26-
- { os: windows-latest, r: "3.6" }
29+
# Use 3.5 to trigger usage of RTools35
30+
- { os: windows-latest, r: "3.5" }
2731
# use 4.1 to check with rtools40's older compiler
2832
- { os: windows-latest, r: "4.1" }
2933

34+
# Ubuntu latest release
3035
- { os: ubuntu-latest, r: "devel", http-user-agent: "release" }
3136
- { os: ubuntu-latest, r: "release" }
3237
- { os: ubuntu-latest, r: "oldrel-1" }
3338
- { os: ubuntu-latest, r: "oldrel-2" }
3439
- { os: ubuntu-latest, r: "oldrel-3" }
3540
- { os: ubuntu-latest, r: "oldrel-4" }
36-
# The oldest version of R we claim to support
41+
# Oldest R version we claim to support
3742
- { os: ubuntu-latest, r: "3.5" }
3843

3944
env:

.github/workflows/test-coverage.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,10 @@ jobs:
4747

4848
- name: Upload test results
4949
if: failure()
50-
uses: actions/upload-artifact@v3
50+
uses: actions/upload-artifact@v4
5151
with:
5252
name: coverage-test-failures
5353
path: ${{ runner.temp }}/package
5454

5555
- name: Upload coverage reports to Codecov
56-
uses: codecov/codecov-action@v3
56+
uses: codecov/codecov-action@v5

.lintr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
linters: linters_with_defaults(
22
line_length_linter(120),
3-
cyclocomp_linter = NULL,
4-
object_length_linter(length = 40L)
3+
object_length_linter(length = 40L),
4+
return_linter = NULL
55
)
66
exclusions: list(
77
"renv",

DESCRIPTION

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
Type: Package
22
Package: epidatr
33
Title: Client for Delphi's 'Epidata' API
4-
Version: 1.2.0
4+
Version: 1.2.1
55
Authors@R: c(
66
person("Logan", "Brooks", , "[email protected]", role = "aut"),
77
person("Dmitry", "Shemetov", , "[email protected]", role = "aut"),
@@ -30,7 +30,7 @@ URL: https://cmu-delphi.github.io/epidatr/,
3030
https://cmu-delphi.github.io/delphi-epidata/,
3131
https://github.com/cmu-delphi/epidatr
3232
BugReports: https://github.com/cmu-delphi/epidatr/issues
33-
Depends:
33+
Depends:
3434
R (>= 3.5.0)
3535
Imports:
3636
cachem,
@@ -45,6 +45,7 @@ Imports:
4545
purrr,
4646
rappdirs,
4747
readr,
48+
rlang,
4849
tibble,
4950
usethis,
5051
xml2
@@ -54,13 +55,12 @@ Suggests:
5455
knitr,
5556
mapproj,
5657
maps,
57-
rlang,
5858
rmarkdown,
5959
testthat (>= 3.1.5),
6060
withr
61-
VignetteBuilder:
61+
VignetteBuilder:
6262
knitr
63-
Remotes:
63+
Remotes:
6464
cmu-delphi/delphidocs
6565
Config/Needs/website: cmu-delphi/delphidocs
6666
Config/testthat/edition: 3

NAMESPACE

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ import(cachem)
5353
import(glue)
5454
importFrom(MMWRweek,MMWRweek)
5555
importFrom(MMWRweek,MMWRweek2Date)
56+
importFrom(cachem,is.key_missing)
5657
importFrom(checkmate,assert)
5758
importFrom(checkmate,assert_character)
5859
importFrom(checkmate,assert_integerish)
@@ -80,7 +81,8 @@ importFrom(magrittr,"%>%")
8081
importFrom(openssl,md5)
8182
importFrom(purrr,map_chr)
8283
importFrom(purrr,map_lgl)
83-
importFrom(readr,read_csv)
84+
importFrom(rlang,dots_list)
85+
importFrom(rlang,inject)
8486
importFrom(stats,na.omit)
8587
importFrom(tibble,as_tibble)
8688
importFrom(tibble,tibble)

NEWS.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
# epidatr 1.2.1
2+
## Patches
3+
- Fix so that `covidcast_epidata()` will still print if fields are missing.
4+
15
# epidatr 1.2.0
26

37
## Changes
@@ -8,6 +12,7 @@
812
- Support more date formats in function to convert dates to epiweeks. Use `parse_api_date` since it already supports both common formats. #276
913
- `EPIDATR_USE_CACHE` only supported exactly "TRUE" before. Now it supports all logical values and includes a warning when any value that can't be converted to logical is provided. #273
1014
- `missing` doesn't count default values as non-missing. If a user doesn't pass `geo_values` or `time_values` (both of which default to `"*"` in `pub_covidcast`), or `dates` (in `pub_covid_hosp_state_timeseries`), the missing check fails. To avoid this, just don't check missingness of those two arguments.
15+
- `fetch_args_list` now has an `refresh_cache` argument, which is `FALSE` by default.
1116

1217
# epidatr 1.1.1
1318

R/cache.R

Lines changed: 90 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
cache_environ <- new.env(parent = emptyenv())
44
cache_environ$use_cache <- NULL
55
cache_environ$epidatr_cache <- NULL
6+
cache_environ$cache_args <- NULL
67

78
#' Create or renew a cache for this session
89
#' @aliases set_cache
@@ -169,6 +170,12 @@ set_cache <- function(cache_dir = NULL,
169170
max_age = days * 24 * 60 * 60,
170171
logfile = file.path(cache_dir, logfile)
171172
)
173+
cache_environ$cache_args <- list(
174+
cache_dir = cache_dir,
175+
days = days,
176+
max_size = max_size,
177+
logfile = logfile
178+
)
172179
}
173180

174181
cli::cli_inform(c(
@@ -183,9 +190,9 @@ set_cache <- function(cache_dir = NULL,
183190
#' Manually reset the cache, deleting all currently saved data and starting afresh
184191
#' @description
185192
#' Deletes the current cache and resets a new cache. Deletes local data! If you
186-
#' are using a session unique cache, you will have to pass the arguments you
187-
#' used for `set_cache` earlier, otherwise the system-wide `.Renviron`-based
188-
#' defaults will be used.
193+
#' are using a session unique cache, the previous settings will be reused. If
194+
#' you pass in new `set_cache` arguments, they will take precedence over the
195+
#' previous settings.
189196
#' @param disable instead of setting a new cache, disable caching entirely;
190197
#' defaults to `FALSE`
191198
#' @inheritDotParams set_cache
@@ -195,14 +202,26 @@ set_cache <- function(cache_dir = NULL,
195202
#' [`disable_cache`] to only disable without deleting, and [`cache_info`]
196203
#' @export
197204
#' @import cachem
205+
#' @importFrom rlang dots_list inject
198206
clear_cache <- function(..., disable = FALSE) {
199207
if (any(!is.na(cache_environ$epidatr_cache))) {
200208
cache_environ$epidatr_cache$destroy()
209+
recovered_args <- cache_environ$cache_args
210+
cache_environ$cache_args <- NULL
211+
} else {
212+
recovered_args <- list()
201213
}
214+
args <- dots_list(
215+
...,
216+
confirm = FALSE,
217+
!!!recovered_args,
218+
.homonyms = "first",
219+
.ignore_empty = "all"
220+
)
202221
if (disable) {
203222
cache_environ$epidatr_cache <- NULL
204223
} else {
205-
set_cache(...)
224+
inject(set_cache(!!!args))
206225
}
207226
}
208227

@@ -234,68 +253,85 @@ disable_cache <- function() {
234253
#' disable without deleting
235254
#' @export
236255
cache_info <- function() {
237-
if (is.null(cache_environ$epidatr_cache)) {
238-
return("there is no cache")
239-
} else {
256+
if (is_cache_enabled()) {
240257
return(cache_environ$epidatr_cache$info())
258+
} else {
259+
return("there is no cache")
241260
}
242261
}
243262

244-
#' Dispatch caching
263+
#' Check if the cache is enabled
264+
#' @keywords internal
265+
is_cache_enabled <- function() {
266+
!is.null(cache_environ$epidatr_cache)
267+
}
268+
269+
#' Helper that checks whether a call is actually cachable
270+
#'
271+
#' The cacheable endpoints are those with `as_of` or `issues` parameters:
272+
#' - pub_covidcast
273+
#' - pub_covid_hosp_state_timeseries
274+
#' - pub_ecdc_ili
275+
#' - pub_flusurv
276+
#' - pub_fluview_clinical
277+
#' - pub_fluview
278+
#' - pub_kcdc_ili
279+
#' - pub_nidss_flu
280+
#' - pub_paho_dengue
281+
#'
282+
#' @keywords internal
283+
check_is_cachable <- function(epidata_call, fetch_args) {
284+
as_of_cachable <- !is.null(epidata_call$params$as_of) && !identical(epidata_call$params$as_of, "*")
285+
issues_cachable <- !is.null(epidata_call$params$issues) && !identical(epidata_call$params$issues, "*")
286+
is_cachable <- (
287+
# Cache should be enabled
288+
is_cache_enabled() &&
289+
# Call should be cachable
290+
(as_of_cachable || issues_cachable) &&
291+
# This should not be a dry run
292+
!fetch_args$dry_run &&
293+
# Base url should be null
294+
is.null(fetch_args$base_url) &&
295+
# Don't cache debug calls
296+
!fetch_args$debug &&
297+
# Format type should be json
298+
fetch_args$format_type == "json" &&
299+
# Fields should be null
300+
is.null(fetch_args$fields) &&
301+
# Disable date parsing should be false
302+
!fetch_args$disable_date_parsing &&
303+
# Disable data frame parsing should be false
304+
!fetch_args$disable_data_frame_parsing &&
305+
# Refresh cache should be false
306+
fetch_args$refresh_cache == FALSE
307+
)
308+
return(is_cachable)
309+
}
310+
311+
#' Check for warnings for the cache
245312
#'
246313
#' @description
247-
#' The guts of caching, its interposed between fetch and the specific fetch
248-
#' methods. Internal method only.
314+
#' Adds warnings when arguments are potentially too recent to use with the cache.
249315
#'
250316
#' @param epidata_call the `epidata_call` object
251317
#' @param fetch_args the args list for fetch as generated by [`fetch_args_list()`]
252318
#' @keywords internal
253-
#' @importFrom openssl md5
254-
cache_epidata_call <- function(epidata_call, fetch_args = fetch_args_list()) {
255-
is_cachable <- check_is_cachable(epidata_call, fetch_args)
256-
if (is_cachable) {
257-
target <- request_url(epidata_call)
258-
hashed <- md5(target)
259-
cached <- cache_environ$epidatr_cache$get(hashed)
260-
as_of_recent <- check_is_recent(epidata_call$params$as_of, 7)
261-
issues_recent <- check_is_recent(epidata_call$params$issues, 7)
262-
if (as_of_recent || issues_recent) {
263-
cli::cli_warn(
264-
c(
265-
"Using cached results with `as_of` within the past week (or the future!).
319+
check_for_cache_warnings <- function(epidata_call, fetch_args) {
320+
as_of_recent <- check_is_recent(epidata_call$params$as_of, 7)
321+
issues_recent <- check_is_recent(epidata_call$params$issues, 7)
322+
if (as_of_recent || issues_recent) {
323+
cli::cli_warn(
324+
c(
325+
"Using cached results with `as_of` within the past week (or the future!).
266326
This will likely result in an invalid cache. Consider",
267-
"i" = "disabling the cache for this session with `disable_cache` or
327+
"i" = "disabling the cache for this session with `disable_cache` or
268328
permanently with environmental variable `EPIDATR_USE_CACHE=FALSE`",
269-
"i" = "setting `EPIDATR_CACHE_MAX_AGE_DAYS={Sys.getenv('EPIDATR_CACHE_MAX_AGE_DAYS
329+
"i" = "setting `EPIDATR_CACHE_MAX_AGE_DAYS={Sys.getenv('EPIDATR_CACHE_MAX_AGE_DAYS
270330
', unset = 1)}` to e.g. `3/24` (3 hours)."
271-
),
272-
.frequency = "regularly",
273-
.frequency_id = "cache timing issues",
274-
class = "cache_recent_data"
275-
)
276-
}
277-
if (!is.key_missing(cached)) {
278-
cli::cli_warn(
279-
c(
280-
"Loading from the cache at {cache_environ$epidatr_cache$info()$dir};
281-
see {cache_environ$epidatr_cache$info()$logfile} for more details."
282-
),
283-
.frequency = "regularly",
284-
.frequency_id = "using the cache",
285-
class = "cache_access"
286-
)
287-
return(cached[[1]])
288-
}
289-
}
290-
# need to actually get the data, since its either not in the cache or we're not caching
291-
runtime <- system.time(if (epidata_call$only_supports_classic) {
292-
fetched <- fetch_classic(epidata_call, fetch_args)
293-
} else {
294-
fetched <- fetch_tbl(epidata_call, fetch_args)
295-
})
296-
# add it to the cache if appropriate
297-
if (is_cachable) {
298-
cache_environ$epidatr_cache$set(hashed, list(fetched, Sys.time(), runtime))
331+
),
332+
.frequency = "regularly",
333+
.frequency_id = "cache timing issues",
334+
class = "cache_recent_data"
335+
)
299336
}
300-
return(fetched)
301337
}

R/covidcast.R

Lines changed: 16 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -69,18 +69,18 @@ parse_source <- function(source, base_url) {
6969
#' @export
7070
as_tibble.covidcast_data_signal_list <- function(x, ...) {
7171
tib <- list()
72-
tib$source <- unname(map_chr(x, "source"))
73-
tib$signal <- unname(map_chr(x, "signal"))
74-
tib$name <- unname(map_chr(x, "name"))
75-
tib$active <- unname(map_lgl(x, "active"))
76-
tib$short_description <- unname(map_chr(x, "short_description"))
77-
tib$description <- unname(map_chr(x, "description"))
78-
tib$time_type <- unname(map_chr(x, "time_type"))
79-
tib$time_label <- unname(map_chr(x, "time_label"))
80-
tib$value_label <- unname(map_chr(x, "value_label"))
81-
tib$format <- unname(map_chr(x, "format"))
82-
tib$category <- unname(map_chr(x, "category"))
83-
tib$high_values_are <- unname(map_chr(x, "high_values_are"))
72+
chr_fields <- c(
73+
"source", "signal", "name", "short_description",
74+
"description", "time_type", "time_label", "value_label",
75+
"format", "category", "high_values_are"
76+
)
77+
for (field in chr_fields) {
78+
tib[[field]] <- unname(map_chr(x, field, .default = ""))
79+
}
80+
lgl_fields <- c("active")
81+
for (field in lgl_fields) {
82+
tib[[field]] <- unname(map_lgl(x, field, .default = ""))
83+
}
8484
as_tibble(tib)
8585
}
8686

@@ -184,11 +184,10 @@ covidcast_epidata <- function(base_url = global_base_url, timeout_seconds = 30)
184184
#' @export
185185
as_tibble.covidcast_data_source_list <- function(x, ...) {
186186
tib <- list()
187-
tib$source <- unname(map_chr(x, "source"))
188-
tib$name <- unname(map_chr(x, "name"))
189-
tib$description <- unname(map_chr(x, "description"))
190-
tib$reference_signal <- unname(map_chr(x, "reference_signal"))
191-
tib$license <- unname(map_chr(x, "license"))
187+
fields <- c("source", "name", "description", "reference_signal", "license")
188+
for (field in fields) {
189+
tib[[field]] <- unname(map_chr(x, field, .default = ""))
190+
}
192191
as_tibble(tib)
193192
}
194193

0 commit comments

Comments
 (0)