Skip to content

Commit 589e19f

Browse files
Copilotpbulsink
andauthored
Fix: null results from Jolpica errors are no longer cached
Agent-Logs-Url: https://github.com/SCasanova/f1dataR/sessions/fcc1bd1a-d464-42b5-b994-cdd4ff497528 Co-authored-by: pbulsink <5419974+pbulsink@users.noreply.github.com>
1 parent 80013a6 commit 589e19f

5 files changed

Lines changed: 95 additions & 2 deletions

File tree

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
name: "Copilot Setup Steps"
2+
3+
# Automatically run the setup steps when they are changed to allow for easy validation, and
4+
# allow manual testing through the repository's "Actions" tab
5+
on:
6+
workflow_dispatch:
7+
push:
8+
paths:
9+
- .github/workflows/copilot-setup-steps.yml
10+
pull_request:
11+
paths:
12+
- .github/workflows/copilot-setup-steps.yml
13+
14+
jobs:
15+
# The job MUST be called `copilot-setup-steps` or it will not be picked up by Copilot.
16+
copilot-setup-steps:
17+
runs-on: ubuntu-latest
18+
19+
permissions:
20+
contents: read
21+
22+
steps:
23+
- name: Checkout code
24+
uses: actions/checkout@v4
25+
26+
- name: Set up R
27+
uses: r-lib/actions/setup-r@v2
28+
with:
29+
r-version: "release"
30+
use-public-rspm: true
31+
32+
- name: Set up Python
33+
uses: actions/setup-python@v5
34+
with:
35+
python-version: "3.x"
36+
37+
- name: Install R dependencies
38+
uses: r-lib/actions/setup-r-dependencies@v2
39+
with:
40+
extra-packages: any::rcmdcheck, any::devtools
41+
needs: check

NEWS.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
* Fixed a data conversion issue in `time_to_sec()` (#290).
99
* Updated testing to comply with changes in `ggplot2` (#292).
1010
* Updated data conversions to avoid bugs after changes in Jolpica database. (#281, #284, #298, #299)
11+
* Fixed a bug where a NULL error return from Jolpica would be cached, preventing retries when the API recovers. (#295)
1112

1213
# f1dataR 2.0.1
1314

R/zzz.R

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,26 @@
1+
# Wraps a cachem cache so that NULL function results are never stored.
2+
# memoise stores results via withVisible(), so a NULL return is represented
3+
# as list(value = NULL, visible = ...). By skipping set() for those values
4+
# the cache misses on the next call, causing the underlying function to be
5+
# retried rather than returning the cached NULL error.
6+
null_filtering_cache <- function(cache) {
7+
list(
8+
get = function(key, ...) cache$get(key, ...),
9+
set = function(key, value) {
10+
if (is.list(value) && is.null(value$value)) {
11+
return(invisible(NULL))
12+
}
13+
invisible(cache$set(key, value))
14+
},
15+
exists = function(key, ...) cache$exists(key, ...),
16+
remove = function(key, ...) cache$remove(key, ...),
17+
reset = function(...) cache$reset(...),
18+
keys = function(...) cache$keys(...),
19+
info = function(...) cache$info(...),
20+
prune = function(...) cache$prune(...)
21+
)
22+
}
23+
124
# nocov start
225
.onLoad <- function(libname, pkgname) {
326
reticulate::py_require("fastf1")
@@ -28,9 +51,9 @@
2851
# set the cachedir to our new location for fastf1 caching too
2952
options("f1dataR.cache" = cache_dir)
3053
}
31-
cache <- cachem::cache_disk(dir = memoise_option)
54+
cache <- null_filtering_cache(cachem::cache_disk(dir = memoise_option))
3255
} else if (memoise_option == "memory") {
33-
cache <- cachem::cache_mem()
56+
cache <- null_filtering_cache(cachem::cache_mem())
3457
}
3558

3659
if (memoise_option != "off") {

tests/testthat/test-load_laps.R

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,5 +56,9 @@ test_that("load_laps works without internet", {
5656
})
5757
})
5858
})
59+
60+
# NULL (error) results must not be stored in the cache so that subsequent
61+
# calls retry the request rather than returning the cached failure.
62+
expect_false(memoise::has_cache(load_laps)(2021, 1))
5963
}
6064
})

tests/testthat/test-utils.R

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,30 @@ test_that("utility functions work", {
4949
)
5050
})
5151

52+
test_that("null_filtering_cache prevents NULL results from being stored", {
53+
inner <- cachem::cache_mem()
54+
filtered <- f1dataR:::null_filtering_cache(inner)
55+
56+
# Non-NULL values must be stored and retrievable
57+
filtered$set("k1", list(value = "hello", visible = TRUE))
58+
expect_true(filtered$exists("k1"))
59+
expect_equal(filtered$get("k1")$value, "hello")
60+
61+
# NULL values must NOT be stored
62+
filtered$set("k2", list(value = NULL, visible = FALSE))
63+
expect_false(filtered$exists("k2"))
64+
65+
# Other cache methods delegate correctly
66+
filtered$remove("k1")
67+
expect_false(filtered$exists("k1"))
68+
69+
filtered$set("k3", list(value = 42L, visible = TRUE))
70+
expect_true(filtered$exists("k3"))
71+
filtered$reset()
72+
expect_false(filtered$exists("k3"))
73+
})
74+
75+
5276
test_that("Utility Functions work without internet", {
5377
# Set testing specific parameters - this disposes after the test finishes
5478
if (dir.exists(file.path(tempdir(), "tst_utils2"))) {

0 commit comments

Comments
 (0)