I have kind of a strange case where I'm trying to look for a specific warning and return one thing if I see it and a different thing if I don't. I feel like I must be missing something, but I can't figure out how to do it, at least not without calling the originating function twice. Thanks in advance for any pointers.
The specific case is: I'm reading in files with data.table::fread() and, if I see a specific parsing warning, I want to return NULL instead of the (incorrectly) parsed data.
Below are my first three attempts, and some tests to prove the issue with them. Note that my_func3 actually passes all the tests, but requires reading in all the data twice. Obviously, in my real application, the data is much larger and hence this is definitely not ideal.
# this one fails test 3
# because it doesn't return anything if _any_ warning is caught
my_func1 <- function(.string) {
res <- tryCatch(
{
data.table::fread(text = .string)
},
warning = function(.w) {
if (grepl("Stopped early.+TABLE NO", .w$message)) {
warning("my custom warning")
return(NULL)
} else {
warning(.w)
}
}
)
}
# this one fails test 2
# because it returns the parsed df even if we catch the custom warning
my_func2 <- function(.string) {
res <- withCallingHandlers(
{
data.table::fread(text = .string)
},
warning = function(.w) {
if (grepl("Stopped early.+TABLE NO", .w$message)) {
warning("my custom warning")
return(NULL)
} else {
warning(.w)
}
}
)
}
# this one passes all three
# but it requires reading the data twice
my_func3 <- function(.string) {
res <- tryCatch(
{
data.table::fread(text = .string)
},
warning = function(.w) {
if (grepl("Stopped early.+TABLE NO", .w$message)) {
warning("my custom warning")
return(NULL)
} else {
data.table::fread(text = .string)
}
}
)
}
##################
# TESTS
##################
# uncomment the one you want to test
#my_func <- my_func1
#my_func <- my_func2
#my_func <- my_func3
library(testthat)
test_that("test 1: my_func returns df when no warning", {
df <- my_func("a,b\n1,2\n3,4")
expect_equal(nrow(df), 2)
expect_equal(ncol(df), 2)
})
test_that("test 2: my_func warns and returns NULL on custom warning", {
expect_warning(
df <- my_func("a,b\n1,2\nTABLE NO\n3,4"),
regexp = "my custom warning"
)
expect_null(df)
})
test_that("test 3: my_func warns and returns df on other warning ", {
expect_warning(
df <- my_func("a,b\n1,2,3\n")
)
expect_equal(nrow(df), 1)
expect_equal(ncol(df), 3)
})
Any thoughts on how to accomplish this without having to read the data twice are very much appreciated.