Skip to content

Commit cb0ea97

Browse files
committed
reorganize function and check in as_yaml directly
1 parent 20e7d56 commit cb0ea97

File tree

7 files changed

+244
-143
lines changed

7 files changed

+244
-143
lines changed

R/na-validation.R

Lines changed: 0 additions & 29 deletions
This file was deleted.

R/render.R

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -164,11 +164,6 @@ quarto_render <- function(
164164
args <- c(args, ifelse(isTRUE(execute), "--execute", "--no-execute"))
165165
}
166166
if (!missing(execute_params)) {
167-
# Check for NA values in execute_params and error with helpful guidance
168-
# This is because R's NA is not valid in YAML, and it would not be loaded
169-
# correctly by quarto (using YAML 1.2).
170-
check_params_for_na(execute_params)
171-
172167
params_file <- tempfile(pattern = "quarto-params", fileext = ".yml")
173168
write_yaml(execute_params, params_file)
174169
args <- c(args, "--execute-params", params_file)

R/utils.R

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,13 @@ yaml_handlers <- list(
1616

1717
#' @importFrom yaml as.yaml
1818
as_yaml <- function(x) {
19+
check_params_for_na(x)
1920
yaml::as.yaml(x, handlers = yaml_handlers)
2021
}
2122

2223
#' @importFrom yaml write_yaml
2324
write_yaml <- function(x, file) {
25+
check_params_for_na(x)
2426
yaml::write_yaml(x, file, handlers = yaml_handlers)
2527
}
2628

@@ -30,6 +32,36 @@ as_yaml_block <- function(x) {
3032
paste0("---\n", yaml_content, "---\n")
3133
}
3234

35+
check_params_for_na <- function(x) {
36+
# Recursively check for NA values
37+
check_na_recursive <- function(data, path = "") {
38+
if (is.list(data)) {
39+
for (i in seq_along(data)) {
40+
name <- names(data)[i] %||% as.character(i)
41+
new_path <- if (path == "") name else paste0(path, "$", name)
42+
check_na_recursive(data[[i]], new_path)
43+
}
44+
} else if (any(is.na(data) & !is.nan(data))) {
45+
# Found NA values (excluding NaN which is mathematically valid)
46+
na_positions <- which(is.na(data) & !is.nan(data))
47+
n_na <- length(na_positions)
48+
49+
cli::cli_abort(c(
50+
"{.code NA} values detected in parameter {.field {path}}",
51+
"x" = "Found NA at position{if (n_na > 1) 's' else ''}: {.val {na_positions}}",
52+
"i" = "Quarto CLI uses YAML 1.2 spec which cannot process R's {.code NA} values",
53+
"i" = "R's {.code NA} gets converted to YAML strings (like {.code .na.real}) that Quarto doesn't recognize as missing values",
54+
" " = "Consider these alternatives:",
55+
"*" = "Remove NA values from your data before passing to Quarto",
56+
"*" = "Use {.code NULL} instead of {.code NA} for missing optional parameters",
57+
"*" = "Handle missing values within your document code using conditional logic"
58+
))
59+
}
60+
}
61+
62+
check_na_recursive(x)
63+
}
64+
3365

3466
# inline knitr:::merge_list()
3567
merge_list <- function(x, y) {

tests/testthat/_snaps/na-validation.md

Lines changed: 0 additions & 45 deletions
This file was deleted.

tests/testthat/_snaps/utils.md

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
# check_params_for_na detects NA in simple vectors
2+
3+
Code
4+
check_params_for_na(bad_params)
5+
Condition
6+
Error in `check_na_recursive()`:
7+
! `NA` values detected in parameter values
8+
x Found NA at position: 2
9+
i Quarto CLI uses YAML 1.2 spec which cannot process R's `NA` values
10+
i R's `NA` gets converted to YAML strings (like `.na.real`) that Quarto doesn't recognize as missing values
11+
Consider these alternatives:
12+
* Remove NA values from your data before passing to Quarto
13+
* Use `NULL` instead of `NA` for missing optional parameters
14+
* Handle missing values within your document code using conditional logic
15+
16+
# check_params_for_na detects NA in nested structures
17+
18+
Code
19+
check_params_for_na(nested_params)
20+
Condition
21+
Error in `check_na_recursive()`:
22+
! `NA` values detected in parameter data$subset
23+
x Found NA at position: 2
24+
i Quarto CLI uses YAML 1.2 spec which cannot process R's `NA` values
25+
i R's `NA` gets converted to YAML strings (like `.na.real`) that Quarto doesn't recognize as missing values
26+
Consider these alternatives:
27+
* Remove NA values from your data before passing to Quarto
28+
* Use `NULL` instead of `NA` for missing optional parameters
29+
* Handle missing values within your document code using conditional logic
30+
31+
# check_params_for_na shows correct NA positions
32+
33+
Code
34+
check_params_for_na(multi_na_params)
35+
Condition
36+
Error in `check_na_recursive()`:
37+
! `NA` values detected in parameter x
38+
x Found NA at positions: 2 and 4
39+
i Quarto CLI uses YAML 1.2 spec which cannot process R's `NA` values
40+
i R's `NA` gets converted to YAML strings (like `.na.real`) that Quarto doesn't recognize as missing values
41+
Consider these alternatives:
42+
* Remove NA values from your data before passing to Quarto
43+
* Use `NULL` instead of `NA` for missing optional parameters
44+
* Handle missing values within your document code using conditional logic
45+
46+
# as_yaml detects NA in simple vectors
47+
48+
Code
49+
as_yaml(list(values = c(1, NA, 3)))
50+
Condition
51+
Error in `check_na_recursive()`:
52+
! `NA` values detected in parameter values
53+
x Found NA at position: 2
54+
i Quarto CLI uses YAML 1.2 spec which cannot process R's `NA` values
55+
i R's `NA` gets converted to YAML strings (like `.na.real`) that Quarto doesn't recognize as missing values
56+
Consider these alternatives:
57+
* Remove NA values from your data before passing to Quarto
58+
* Use `NULL` instead of `NA` for missing optional parameters
59+
* Handle missing values within your document code using conditional logic
60+
61+
# write_yaml detects NA in nested structures
62+
63+
Code
64+
write_yaml(list(data = list(subset = c(1, NA, 3))), tempfile())
65+
Condition
66+
Error in `check_na_recursive()`:
67+
! `NA` values detected in parameter data$subset
68+
x Found NA at position: 2
69+
i Quarto CLI uses YAML 1.2 spec which cannot process R's `NA` values
70+
i R's `NA` gets converted to YAML strings (like `.na.real`) that Quarto doesn't recognize as missing values
71+
Consider these alternatives:
72+
* Remove NA values from your data before passing to Quarto
73+
* Use `NULL` instead of `NA` for missing optional parameters
74+
* Handle missing values within your document code using conditional logic
75+
76+
# as_yaml shows correct NA positions
77+
78+
Code
79+
as_yaml(list(x = c(1, NA, 3, NA)))
80+
Condition
81+
Error in `check_na_recursive()`:
82+
! `NA` values detected in parameter x
83+
x Found NA at positions: 2 and 4
84+
i Quarto CLI uses YAML 1.2 spec which cannot process R's `NA` values
85+
i R's `NA` gets converted to YAML strings (like `.na.real`) that Quarto doesn't recognize as missing values
86+
Consider these alternatives:
87+
* Remove NA values from your data before passing to Quarto
88+
* Use `NULL` instead of `NA` for missing optional parameters
89+
* Handle missing values within your document code using conditional logic
90+
91+
# quarto_render uses write_yaml validation
92+
93+
Code
94+
quarto_render("test.qmd", execute_params = list(bad_param = c(1, NA)))
95+
Condition
96+
Error in `check_na_recursive()`:
97+
! `NA` values detected in parameter bad_param
98+
x Found NA at position: 2
99+
i Quarto CLI uses YAML 1.2 spec which cannot process R's `NA` values
100+
i R's `NA` gets converted to YAML strings (like `.na.real`) that Quarto doesn't recognize as missing values
101+
Consider these alternatives:
102+
* Remove NA values from your data before passing to Quarto
103+
* Use `NULL` instead of `NA` for missing optional parameters
104+
* Handle missing values within your document code using conditional logic
105+

tests/testthat/test-na-validation.R

Lines changed: 0 additions & 64 deletions
This file was deleted.

0 commit comments

Comments
 (0)