Skip to content

Commit 03d63a4

Browse files
authored
time_to_second fix (#291)
* Fix time_to_sec() and test * Updated News * Style & Document code * Test needs the correct NA type
1 parent 0282790 commit 03d63a4

3 files changed

Lines changed: 91 additions & 30 deletions

File tree

NEWS.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# f1dataR (development version)
22

3+
* Fixed a data conversion issue in `time_to_sec()` (#290)
4+
35
# f1dataR 2.0.1
46

57
* Forced fail-over from Ergast to Jolpica (still deprecated at 'warn' level).

R/utils.R

Lines changed: 78 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@
1717
#' Further processing is performed by specific functions
1818
get_ergast_content <- function(url) {
1919
# Function Deprecation Warning
20-
lifecycle::deprecate_warn("at the end of 2024", "get_ergast_content()",
20+
lifecycle::deprecate_warn(
21+
"at the end of 2024",
22+
"get_ergast_content()",
2123
details = c(
2224
"i" = "At the end of 2024 season the Ergast Motor Racing Database API was shut down.",
2325
" " = "Update f1dataR to use the new jolpica-f1 API data source"
@@ -52,11 +54,15 @@ get_jolpica_content <- function(url) {
5254
# Automatically retries request up to 5 times. Back-off provided in httr2 documentation
5355
# Automatically retries at http if https fails after retries.
5456

55-
5657
jolpica_raw <- httr2::request("https://api.jolpi.ca/ergast/f1/") %>%
5758
httr2::req_url_path_append(url) %>%
58-
httr2::req_retry(max_tries = 10, backoff = function(x) stats::runif(1, 1, 2^x)) %>%
59-
httr2::req_user_agent(glue::glue("f1dataR/{ver}", ver = utils::installed.packages()["f1dataR", "Version"])) %>%
59+
httr2::req_retry(max_tries = 10, backoff = function(x) {
60+
stats::runif(1, 1, 2^x)
61+
}) %>%
62+
httr2::req_user_agent(glue::glue(
63+
"f1dataR/{ver}",
64+
ver = utils::installed.packages()["f1dataR", "Version"]
65+
)) %>%
6066
httr2::req_throttle(4 / 1) %>%
6167
httr2::req_error(is_error = ~FALSE)
6268

@@ -68,15 +74,24 @@ get_jolpica_content <- function(url) {
6874
httr2::req_perform()
6975
},
7076
error = function(e) {
71-
cli::cli_alert_danger(glue::glue("f1dataR: Error getting data from Jolpica:\n{e}", e = e))
77+
cli::cli_alert_danger(glue::glue(
78+
"f1dataR: Error getting data from Jolpica:\n{e}",
79+
e = e
80+
))
7281
}
7382
)
7483

7584
# Restart retries to Jolpica with http (instead of https)
7685
# No testing penalty for Jolpica functioning correct
7786
# nocov start
78-
if (is.null(jolpica_res) || httr2::resp_is_error(jolpica_res) || httr2::resp_body_string(jolpica_res) == "Unable to select database") {
79-
cli::cli_alert_warning("Failure at Jolpica with https:// connection. Retrying as http://.")
87+
if (
88+
is.null(jolpica_res) ||
89+
httr2::resp_is_error(jolpica_res) ||
90+
httr2::resp_body_string(jolpica_res) == "Unable to select database"
91+
) {
92+
cli::cli_alert_warning(
93+
"Failure at Jolpica with https:// connection. Retrying as http://."
94+
)
8095
tryCatch(
8196
{
8297
jolpica_res <- jolpica_raw %>%
@@ -85,7 +100,10 @@ get_jolpica_content <- function(url) {
85100
httr2::req_perform()
86101
},
87102
error = function(e) {
88-
cli::cli_alert_danger(glue::glue("f1dataR: Error getting data from Jolpica:\n{e}", e = e))
103+
cli::cli_alert_danger(glue::glue(
104+
"f1dataR: Error getting data from Jolpica:\n{e}",
105+
e = e
106+
))
89107
}
90108
)
91109
}
@@ -96,15 +114,18 @@ get_jolpica_content <- function(url) {
96114
}
97115

98116
if (httr2::resp_is_error(jolpica_res)) {
99-
cli::cli_alert_danger(glue::glue("Error getting Jolpica data, http status code {code}.\n{msg}",
117+
cli::cli_alert_danger(glue::glue(
118+
"Error getting Jolpica data, http status code {code}.\n{msg}",
100119
code = httr2::resp_status(jolpica_res),
101120
msg = httr2::resp_status_desc(jolpica_res)
102121
))
103122
return(NULL)
104123
}
105124

106125
if (httr2::resp_body_string(jolpica_res) == "Unable to select database") {
107-
cli::cli_alert_danger("Jolpica is having database trouble. Please try again at a later time.")
126+
cli::cli_alert_danger(
127+
"Jolpica is having database trouble. Please try again at a later time."
128+
)
108129
return(NULL)
109130
}
110131
# nocov end
@@ -121,7 +142,8 @@ get_jolpica_content <- function(url) {
121142
#' @export
122143
#' @return Year (four digit number) representation of current season, as numeric.
123144
get_current_season <- function() {
124-
return(ifelse(as.numeric(strftime(Sys.Date(), "%m")) < 3,
145+
return(ifelse(
146+
as.numeric(strftime(Sys.Date(), "%m")) < 3,
125147
as.numeric(strftime(Sys.Date(), "%Y")) - 1,
126148
as.numeric(strftime(Sys.Date(), "%Y"))
127149
))
@@ -138,9 +160,11 @@ get_current_season <- function() {
138160
time_to_sec <- function(time) {
139161
subfun <- function(x) {
140162
if (is.na(x)) {
141-
NA
163+
return(NA_real_)
142164
} else if (is.numeric(x)) {
143-
x
165+
return(x)
166+
} else if (x == "") {
167+
return(NA_real_)
144168
} else {
145169
split <- as.numeric(strsplit(x, ":", fixed = TRUE)[[1]])
146170
if (length(split) == 3) {
@@ -174,10 +198,16 @@ check_ff1_session_loaded <- function(session_name = "session") {
174198
{
175199
# Only returns a value if session.load() has been successful
176200
# If it hasn't, retry
177-
reticulate::py_run_string(glue::glue("{session_name}.t0_date", session_name = session_name))
201+
reticulate::py_run_string(glue::glue(
202+
"{session_name}.t0_date",
203+
session_name = session_name
204+
))
178205
},
179206
error = function(e) {
180-
reticulate::py_run_string(glue::glue("{session_name}.load()", session_name = session_name))
207+
reticulate::py_run_string(glue::glue(
208+
"{session_name}.load()",
209+
session_name = session_name
210+
))
181211
}
182212
)
183213
invisible(TRUE)
@@ -208,14 +238,20 @@ check_ff1_network_connection <- function(path = NA_character_) {
208238
httr2::req_url_path_append(path) %>%
209239
httr2::req_url_path_append("Index.json") %>%
210240
httr2::req_retry(max_tries = 5) %>%
211-
httr2::req_user_agent(glue::glue("f1dataR/{ver}", ver = utils::installed.packages()["f1dataR", "Version"])) %>%
241+
httr2::req_user_agent(glue::glue(
242+
"f1dataR/{ver}",
243+
ver = utils::installed.packages()["f1dataR", "Version"]
244+
)) %>%
212245
httr2::req_throttle(4 / 1) %>%
213246
httr2::req_error(is_error = ~FALSE)
214247
status <- ff1raw %>%
215248
httr2::req_perform()
216249
},
217250
error = function(e) {
218-
cli::cli_alert_danger(glue::glue("f1dataR: Error getting data from F1 Live Timing:\n{e}", e = e))
251+
cli::cli_alert_danger(glue::glue(
252+
"f1dataR: Error getting data from F1 Live Timing:\n{e}",
253+
e = e
254+
))
219255
}
220256
)
221257
if (is.null(status)) {
@@ -240,13 +276,15 @@ check_ff1_network_connection <- function(path = NA_character_) {
240276
check_ff1_version <- function() {
241277
version <- get_fastf1_version()
242278
if (version < "3.1") {
243-
cli::cli_abort(c("An old version of {.pkg FastF1} is in use. {.pkg f1dataR} requires {.pkg FastF1} version 3.1.0 or newer.",
279+
cli::cli_abort(c(
280+
"An old version of {.pkg FastF1} is in use. {.pkg f1dataR} requires {.pkg FastF1} version 3.1.0 or newer.",
244281
x = "Support for older {.pkg FastF1} versions was removed in {.pkg f1dataR} v1.6.0",
245282
i = "You can update your {.pkg FastF1} installation manually, or by running:",
246283
" " = "{.code setup_fastf1()}"
247284
))
248285
} else if (version < "3.4") {
249-
cli::cli_warn(c("An old version of {.pkg FastF1} is in use. {.pkg f1dataR} requires {.pkg FastF1} version 3.4.0 or newer for some functions.",
286+
cli::cli_warn(c(
287+
"An old version of {.pkg FastF1} is in use. {.pkg f1dataR} requires {.pkg FastF1} version 3.4.0 or newer for some functions.",
250288
x = "Support for older {.pkg FastF1} versions may be removed soon.",
251289
i = "You can update your {.pkg FastF1} installation manually, or by running:",
252290
" " = "{.code setup_fastf1()}"
@@ -269,7 +307,8 @@ get_fastf1_version <- function() {
269307
dplyr::filter(.data$package == "fastf1") %>%
270308
dplyr::pull("version")
271309
if (length(ver) == 0) {
272-
cli::cli_warn("Ensure {.pkg fastf1} Python package is installed.",
310+
cli::cli_warn(
311+
"Ensure {.pkg fastf1} Python package is installed.",
273312
i = "Please run this to install the most recent version:",
274313
" " = "{.code setup_fastf1()}"
275314
)
@@ -294,13 +333,19 @@ get_fastf1_version <- function() {
294333
#' @keywords internal
295334
add_col_if_absent <- function(data, column_name, na_type = NA) {
296335
if (!is.na(na_type)) {
297-
cli::cli_abort(x = "{.arg na_type} must be provided as an actual {.code NA_type_} (for example, {.val NA_character_}).")
336+
cli::cli_abort(
337+
x = "{.arg na_type} must be provided as an actual {.code NA_type_} (for example, {.val NA_character_})."
338+
)
298339
}
299340
if (!(inherits(data, "data.frame"))) {
300-
cli::cli_abort(x = "{.arg data} must be provided as a {.code data.frame} or {.code tibble}.")
341+
cli::cli_abort(
342+
x = "{.arg data} must be provided as a {.code data.frame} or {.code tibble}."
343+
)
301344
}
302345
if (!(length(column_name) == 1) | !(inherits(column_name, "character"))) {
303-
cli::cli_abort(x = "{.arg column_name} must be provided as a single {.code character} value.")
346+
cli::cli_abort(
347+
x = "{.arg column_name} must be provided as a single {.code character} value."
348+
)
304349
}
305350
if (!(column_name %in% colnames(data))) {
306351
data[, column_name] <- na_type
@@ -332,13 +377,20 @@ add_col_if_absent <- function(data, column_name, na_type = NA) {
332377
#' # Reinstall fastf1 and recreate the environment.
333378
#' setup_fastf1(envname = "f1dataR_env", new_env = TRUE)
334379
#' }
335-
setup_fastf1 <- function(..., envname = "f1dataR_env", new_env = identical(envname, "f1dataR_env")) {
380+
setup_fastf1 <- function(
381+
...,
382+
envname = "f1dataR_env",
383+
new_env = identical(envname, "f1dataR_env")) {
336384
if (new_env && virtualenv_exists(envname)) {
337-
cli::cli_alert_warning("The Python environment {.var {envname}} is being removed and rebuilt for {.pkg FastF1}f")
385+
cli::cli_alert_warning(
386+
"The Python environment {.var {envname}} is being removed and rebuilt for {.pkg FastF1}f"
387+
)
338388
virtualenv_remove(envname)
339389
}
340390

341-
cli::cli_alert_info("Installing {.pkg FastF1} in current Python environment: {.var {envname}}.")
391+
cli::cli_alert_info(
392+
"Installing {.pkg FastF1} in current Python environment: {.var {envname}}."
393+
)
342394
reticulate::py_install("fastf1", envname = envname, ...)
343395
}
344396

tests/testthat/test-utils.R

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,13 +35,18 @@ test_that("utility functions work", {
3535
expect_equal(time_to_sec("12:34:56.789"), 45296.789)
3636
expect_equal(time_to_sec("12.3456"), 12.3456)
3737
expect_equal(time_to_sec(12.345), 12.345)
38+
expect_equal(time_to_sec(""), NA_real_)
39+
expect_equal(time_to_sec(NA), NA_real_)
3840

3941
expect_equal(
4042
time_to_sec(c("12.345", "1:23.456", "12:34:56.789", "12.3456")),
4143
c(12.345, 83.456, 45296.789, 12.3456)
4244
)
4345

44-
expect_error(check_ff1_network_connection(), "f1dataR: Specific race path must be provided")
46+
expect_error(
47+
check_ff1_network_connection(),
48+
"f1dataR: Specific race path must be provided"
49+
)
4550
})
4651

4752
test_that("Utility Functions work without internet", {
@@ -60,9 +65,11 @@ test_that("Utility Functions work without internet", {
6065
# a byproduct of the without_internet call
6166
suppressWarnings({
6267
suppressMessages({
63-
httptest2::without_internet((
64-
expect_false(check_ff1_network_connection("/static/2024/2024-03-02_Bahrain_Grand_Prix/2024-03-02_Race/"))
65-
))
68+
httptest2::without_internet(
69+
(expect_false(check_ff1_network_connection(
70+
"/static/2024/2024-03-02_Bahrain_Grand_Prix/2024-03-02_Race/"
71+
)))
72+
)
6673
})
6774
})
6875
}

0 commit comments

Comments
 (0)