Skip to content

Commit 84d2d16

Browse files
authored
Merge pull request #19 from Boehringer-Ingelheim/update_CM_TC_snippets
Update shared CM and TC snippets and relax default arm checks.
2 parents 66c40a2 + ecae5a2 commit 84d2d16

4 files changed

Lines changed: 58 additions & 17 deletions

File tree

R/CM.R

Lines changed: 47 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1-
# YT#VHb3a67af97b323ee47762788154a489fd#VHa53bd254d6ac8e6a19dfa057febb06b5#
1+
# YT#VH20fe8acb2e57832933eb60226847381a#VHe9395a780f86f7653c9f11cadba1e3f0#
22
CM <- local({ # _C_hecked _M_odule
3+
# 2025-07-11: [feature] New `manual_check` flag to tell `CM$generate_check_functions()` to ignore particular elements
4+
# 2025-04-09: [fix] Make `generate_map_afmm_function` maps multi-variable parameters (e.g. `visit_vars`)
35
# 2025-03-21: [feature] report errors for all loaded datasets and [fix] dehardcode "PARAM" string and use `par` argument
46

57
message_well <- function(title, contents, color = "f5f5f5") {
@@ -281,6 +283,13 @@ CM <- local({ # _C_hecked _M_odule
281283
elem <- spec$elements[[elem_name]]
282284
attrs_ids <- setdiff(names(attributes(elem)), c("names", "docs"))
283285
attrs <- attributes(elem)[attrs_ids]
286+
287+
if (isTRUE(attrs[["manual_check"]])) {
288+
push(sprintf("'NOTE: %s (%s) tagged as \"manual_check\"'\n", elem_name, elem$kind))
289+
push(sprintf("' The expectation is that it either does not require automated checks or that'\n"))
290+
push(sprintf("' the caller of this function has written manual checks near the call site.'\n"))
291+
next
292+
}
284293

285294
if (isTRUE(attrs[["subjid_var"]])) {
286295
subjid_vars <- c(subjid_vars, elem_name)
@@ -320,6 +329,11 @@ CM <- local({ # _C_hecked _M_odule
320329
"OK[['%s']] <- CM$check_function('%s', %s, %d, flags, warn, err)\n",
321330
elem_name, elem_name, elem_name, elem$arg_count
322331
))
332+
} else if (elem$kind == "group") {
333+
push(sprintf("'NOTE: %s (%s) unsupported as the check generator cannot handle nested elements yet'\n",
334+
elem_name, elem$kind))
335+
push(sprintf("' The expectation is that it either does not require automated checks or that'\n"))
336+
push(sprintf("' the caller of this function has written manual checks near the call site.'\n"))
323337
} else {
324338
push(sprintf("'NOTE: %s (%s) has no associated automated checks'\n", elem_name, elem$kind))
325339
push(sprintf("' The expectation is that it either does not require them or that'\n"))
@@ -422,11 +436,24 @@ CM <- local({ # _C_hecked _M_odule
422436
elem <- spec$elements[[elem_name]]
423437
stopifnot(elem$kind == "col")
424438
dataset_name <- elem[["dataset_name"]]
425-
push(sprintf("if(is.character(ds[[%s]][[%s]])){\n", dataset_name, elem_name))
426-
push("mapping_summary <- c(mapping_summary,")
427-
push(sprintf("paste0('(', ds_name, ') ', %s, '[[\"', %s, '\"]]')", dataset_name, elem_name))
428-
push(")\n")
429-
push("}\n")
439+
440+
multiple <- (isTRUE(attr(elem, "zero_or_more")) || isTRUE(attr(elem, "one_or_more")))
441+
if (multiple) {
442+
push(sprintf("for (.elem in %s) {\n", elem_name))
443+
push(sprintf("if(is.character(ds[[%s]][[.elem]])){\n", dataset_name))
444+
push("mapping_summary <- c(mapping_summary,")
445+
push(sprintf("paste0('(', ds_name, ') ', %s, '[[\"', .elem, '\"]]')", dataset_name))
446+
push(")\n")
447+
push("}\n")
448+
push("}\n")
449+
} else {
450+
push(sprintf("if(is.character(ds[[%s]][[%s]])){\n", dataset_name, elem_name))
451+
push("mapping_summary <- c(mapping_summary,")
452+
push(sprintf("paste0('(', ds_name, ') ', %s, '[[\"', %s, '\"]]')", dataset_name, elem_name))
453+
push(")\n")
454+
push("}\n")
455+
}
456+
430457
}
431458
push("}\n")
432459

@@ -449,10 +476,20 @@ CM <- local({ # _C_hecked _M_odule
449476
elem <- spec$elements[[elem_name]]
450477
dataset_name <- elem[["dataset_name"]]
451478

452-
push(sprintf("if (is.character(res[[%s]][[%s]])) {\n", dataset_name, elem_name))
453-
push(sprintf(" res[[%s]][[%s]] <- ", dataset_name, elem_name))
454-
push(sprintf(" as.factor(res[[%s]][[%s]])\n", dataset_name, elem_name))
455-
push("}\n")
479+
multiple <- (isTRUE(attr(elem, "zero_or_more")) || isTRUE(attr(elem, "one_or_more")))
480+
if (multiple) {
481+
push(sprintf("for (.elem in %s) {\n", elem_name))
482+
push(sprintf("if (is.character(res[[%s]][[.elem]])) {\n", dataset_name))
483+
push(sprintf(" res[[%s]][[.elem]] <- ", dataset_name))
484+
push(sprintf(" as.factor(res[[%s]][[.elem]])\n", dataset_name))
485+
push("}\n")
486+
push("}\n")
487+
} else {
488+
push(sprintf("if (is.character(res[[%s]][[%s]])) {\n", dataset_name, elem_name))
489+
push(sprintf(" res[[%s]][[%s]] <- ", dataset_name, elem_name))
490+
push(sprintf(" as.factor(res[[%s]][[%s]])\n", dataset_name, elem_name))
491+
push("}\n")
492+
}
456493
}
457494

458495
push(" return(res)\n")

R/TC.R

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# YT#VH1202cc468f3cbf448dd25ff917fc4762#VH00000000000000000000000000000000#
1+
# YT#VHf29a3f572c107632b46daf31f56ecd34#VH1202cc468f3cbf448dd25ff917fc4762#
22
TC <- local({ # _T_ype C_hecks
33
# basic types
44
T_logical <- function() list(kind = "logical")
@@ -78,6 +78,7 @@ TC <- local({ # _T_ype C_hecks
7878
"named", # elements of targetted argument must be named
7979
"map_character_to_factor", # the target TC$col() will be transformed to factor prior to reaching the module
8080
"ignore", # argument should be ignored by Dressing Room, for now
81+
"manual_check", # CM$generate_check_functions will not generate an automated check for this element
8182
# domain-specific flags
8283
"subject_level_dataset_name", # indicates dataset with one row per subject
8384
"subjid_var" # indicates unique subject identifier column on dataset pointed at by subject_level_dataset_name

R/check_call_auto.R

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55
# dv.edish::mod_edish
66
check_mod_edish_auto <- function(afmm, datasets, module_id, subject_level_dataset_name, lab_dataset_name,
77
subjectid_var, arm_var, arm_default_vals, visit_var, baseline_visit_val, lb_test_var, lb_test_choices,
8-
lb_test_default_x_val, lb_test_default_y_val, lb_result_var, ref_range_upper_lim_var, receiver_id, warn, err) {
8+
lb_test_default_x_val, lb_test_default_y_val, lb_result_var, ref_range_upper_lim_var, receiver_id,
9+
warn, err) {
910
OK <- logical(0)
1011
used_dataset_names <- new.env(parent = emptyenv())
1112
OK[["module_id"]] <- CM$check_module_id("module_id", module_id, warn, err)
@@ -24,10 +25,9 @@ check_mod_edish_auto <- function(afmm, datasets, module_id, subject_level_datase
2425
flags <- structure(list(), names = character(0))
2526
OK[["arm_var"]] <- OK[["subject_level_dataset_name"]] && CM$check_dataset_colum_name("arm_var", arm_var,
2627
subkind, flags, subject_level_dataset_name, datasets[[subject_level_dataset_name]], warn, err)
27-
flags <- list(one_or_more = TRUE, optional = TRUE)
28-
OK[["arm_default_vals"]] <- OK[["arm_var"]] && CM$check_choice_from_col_contents("arm_default_vals",
29-
arm_default_vals, flags, "subject_level_dataset_name", datasets[[subject_level_dataset_name]],
30-
arm_var, warn, err)
28+
"NOTE: arm_default_vals (choice_from_col_contents) tagged as \"manual_check\""
29+
" The expectation is that it either does not require automated checks or that"
30+
" the caller of this function has written manual checks near the call site."
3131
subkind <- list(kind = "or", options = list(list(kind = "character"), list(kind = "factor")))
3232
flags <- structure(list(), names = character(0))
3333
OK[["visit_var"]] <- OK[["lab_dataset_name"]] && CM$check_dataset_colum_name("visit_var", visit_var,
@@ -61,6 +61,9 @@ check_mod_edish_auto <- function(afmm, datasets, module_id, subject_level_datase
6161
OK[["ref_range_upper_lim_var"]] <- OK[["lab_dataset_name"]] && CM$check_dataset_colum_name("ref_range_upper_lim_var",
6262
ref_range_upper_lim_var, subkind, flags, lab_dataset_name, datasets[[lab_dataset_name]], warn,
6363
err)
64+
"NOTE: receiver_id (character) has no associated automated checks"
65+
" The expectation is that it either does not require them or that"
66+
" the caller of this function has written manual checks near the call site."
6467
for (ds_name in names(used_dataset_names)) {
6568
OK[["subjectid_var"]] <- OK[["subjectid_var"]] && CM$check_subjid_col(datasets, ds_name, get(ds_name),
6669
"subjectid_var", subjectid_var, warn, err)

R/mod_edish.R

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -465,7 +465,7 @@ mod_edish_API_spec <- TC$group(
465465
lab_dataset_name = TC$dataset_name(),
466466
subjectid_var = TC$col("subject_level_dataset_name", TC$or(TC$character(), TC$factor())) |> TC$flag("subjid_var"),
467467
arm_var = TC$col("subject_level_dataset_name", TC$or(TC$character(), TC$factor())),
468-
arm_default_vals = TC$choice_from_col_contents("arm_var") |> TC$flag("one_or_more", "optional"),
468+
arm_default_vals = TC$choice_from_col_contents("arm_var") |> TC$flag("one_or_more", "optional", "manual_check"),
469469
visit_var = TC$col("lab_dataset_name", TC$or(TC$character(), TC$factor())),
470470
baseline_visit_val = TC$choice_from_col_contents("visit_var"),
471471
lb_test_var = TC$col("lab_dataset_name", TC$or(TC$character(), TC$factor())),

0 commit comments

Comments
 (0)