Skip to content

Commit 2872d5e

Browse files
use type checkers in fit.R (#1182)
--------- Co-authored-by: Emil Hvitfeldt <emil.hvitfeldt@posit.co>
1 parent 227ab92 commit 2872d5e

File tree

4 files changed

+55
-55
lines changed

4 files changed

+55
-55
lines changed

R/convert_data.R

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -388,7 +388,7 @@ check_dup_names <- function(x, y, call = rlang::caller_env()) {
388388
#' @return A data frame, matrix, or sparse matrix.
389389
#' @export
390390
maybe_matrix <- function(x) {
391-
inher(x, c("data.frame", "matrix", "dgCMatrix"), cl = match.call())
391+
check_inherits(x, c("data.frame", "matrix", "dgCMatrix"))
392392
if (is.data.frame(x)) {
393393
non_num_cols <- vapply(x, function(x) !is.numeric(x), logical(1))
394394
if (any(non_num_cols)) {

R/fit.R

Lines changed: 37 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -55,11 +55,11 @@
5555
#' a "reverse Kaplan-Meier" curve that models the probability of censoring. This
5656
#' may be used later to compute inverse probability censoring weights for
5757
#' performance measures.
58-
#'
58+
#'
5959
#' Sparse data is supported, with the use of the `x` argument in `fit_xy()`. See
60-
#' `allow_sparse_x` column of [parsnip::get_encoding()] for sparse input
60+
#' `allow_sparse_x` column of [parsnip::get_encoding()] for sparse input
6161
#' compatibility.
62-
#'
62+
#'
6363
#' @examplesIf !parsnip:::is_cran_check()
6464
#' # Although `glm()` only has a formula interface, different
6565
#' # methods for specifying the model can be used
@@ -121,21 +121,17 @@ fit.model_spec <-
121121
control <- condense_control(control, control_parsnip())
122122
check_case_weights(case_weights, object)
123123

124-
if (!inherits(formula, "formula")) {
125-
msg <- "The {.arg formula} argument must be a formula, but it is a \\
126-
{.cls {class(formula)[1]}}."
127-
128-
if (inherits(formula, "recipe")) {
129-
msg <-
130-
c(
131-
msg,
132-
"i" = "To fit a model with a recipe preprocessor, please use a \\
124+
if (inherits(formula, "recipe")) {
125+
cli::cli_abort(
126+
c(
127+
"The {.arg formula} argument must be a formula.",
128+
"i" = "To fit a model with a recipe preprocessor, please use a \\
133129
{.help [workflow](workflows::workflow)}."
134-
)
135-
}
136-
137-
cli::cli_abort(msg)
130+
)
131+
)
138132
}
133+
check_formula(formula)
134+
139135

140136
if (is_sparse_matrix(data)) {
141137
data <- sparsevctrs::coerce_to_sparse_tibble(data)
@@ -179,7 +175,7 @@ fit.model_spec <-
179175
eval_env$weights <- wts
180176

181177
data <- materialize_sparse_tibble(data, object, "data")
182-
178+
183179
fit_interface <-
184180
check_interface(eval_env$formula, eval_env$data, cl, object)
185181

@@ -297,10 +293,11 @@ fit_xy.model_spec <-
297293
# TODO case weights: pass in eval_env not individual elements
298294
fit_interface <- check_xy_interface(eval_env$x, eval_env$y, cl, object)
299295

300-
if (object$engine == "spark")
296+
if (object$engine == "spark") {
301297
cli::cli_abort(
302-
"spark objects can only be used with the formula interface to {.fn fit} with a spark data object."
298+
"spark objects can only be used with the formula interface to {.fn fit} with a spark data object."
303299
)
300+
}
304301

305302
# populate `method` with the details for this model type
306303
object <- add_methods(object, engine = object$engine)
@@ -373,59 +370,47 @@ eval_mod <- function(e, capture = FALSE, catch = FALSE, envir = NULL, ...) {
373370

374371
# ------------------------------------------------------------------------------
375372

376-
inher <- function(x, cls, cl) {
377-
if (!is.null(x) && !inherits(x, cls)) {
378-
379-
call <- match.call()
380-
obj <- deparse(call[["x"]])
381-
382-
if (length(cls) > 1)
383-
cli::cli_abort(
384-
"{.arg {obj}} should be one of the following classes: {.cls {cls}}.")
385-
386-
else
387-
cli::cli_abort("{.arg {obj}} should be a {.cls {cls}} object")
388-
}
389-
invisible(x)
390-
}
391-
392-
# ------------------------------------------------------------------------------
393-
394-
check_interface <- function(formula, data, cl, model) {
395-
inher(formula, "formula", cl)
396-
inher(data, c("data.frame", "dgCMatrix", "tbl_spark"), cl)
373+
check_interface <- function(formula, data, cl, model, call = caller_env()) {
374+
check_formula(formula, call = call)
375+
check_inherits(data, c("data.frame", "dgCMatrix", "tbl_spark"), call = call)
397376

398377
# Determine the `fit()` interface
399378
form_interface <- !is.null(formula) & !is.null(data)
400379

401380
if (form_interface)
402381
return("formula")
403-
cli::cli_abort("Error when checking the interface.")
382+
cli::cli_abort("Error when checking the interface.", call = call)
404383
}
405384

406-
check_xy_interface <- function(x, y, cl, model) {
385+
check_xy_interface <- function(x, y, cl, model, call = caller_env()) {
407386

408387
sparse_ok <- allow_sparse(model)
409388
sparse_x <- inherits(x, "dgCMatrix")
410389
if (!sparse_ok & sparse_x) {
411-
cli::cli_abort("Sparse matrices not supported by this model/engine combination.")
390+
cli::cli_abort(
391+
"Sparse matrices not supported by this model/engine combination.",
392+
call = call
393+
)
412394
}
413395

414396
if (sparse_ok) {
415-
inher(x, c("data.frame", "matrix", "dgCMatrix"), cl)
397+
check_inherits(x, c("data.frame", "matrix", "dgCMatrix"), call = call)
416398
} else {
417-
inher(x, c("data.frame", "matrix"), cl)
399+
check_inherits(x, c("data.frame", "matrix"), call = call)
418400
}
419401

420-
if (!is.null(y) && !is.atomic(y))
421-
inher(y, c("data.frame", "matrix"), cl)
402+
if (!is.null(y) && !is.atomic(y)) {
403+
check_inherits(y, c("data.frame", "matrix"), call = call)
404+
}
422405

423406
# rule out spark data sets that don't use the formula interface
424-
if (inherits(x, "tbl_spark") | inherits(y, "tbl_spark"))
407+
if (inherits(x, "tbl_spark") | inherits(y, "tbl_spark")) {
425408
cli::cli_abort(
426-
"spark objects can only be used with the formula interface via {.fn fit} with a spark data object."
427-
)
428-
409+
"spark objects can only be used with the formula interface via
410+
{.fn fit} with a spark data object.",
411+
call = call
412+
)
413+
}
429414

430415
if (sparse_ok) {
431416
matrix_interface <- !is.null(x) && !is.null(y) && (is.matrix(x) | sparse_x)
@@ -444,7 +429,7 @@ check_xy_interface <- function(x, y, cl, model) {
444429

445430
check_outcome(y, model)
446431

447-
cli::cli_abort("Error when checking the interface")
432+
cli::cli_abort("Error when checking the interface.", call = call)
448433
}
449434

450435
allow_sparse <- function(x) {

R/misc.R

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -533,6 +533,21 @@ check_case_weights <- function(x, spec, call = rlang::caller_env()) {
533533
invisible(NULL)
534534
}
535535

536+
# ------------------------------------------------------------------------------
537+
538+
check_inherits <- function(x, cls, arg = caller_arg(x), call = caller_env()) {
539+
if (is.null(x)) {
540+
return(invisible(x))
541+
}
542+
543+
if (!inherits(x, cls)) {
544+
cli::cli_abort(
545+
"{.arg {arg}} should be a {.cls {cls}}, not {.obj_type_friendly {x}}.",
546+
call = call
547+
)
548+
}
549+
}
550+
536551
# -----------------------------------------------------------------------------
537552
check_for_newdata <- function(..., call = rlang::caller_env()) {
538553
if (any(names(list(...)) == "newdata")) {

tests/testthat/_snaps/fit_interfaces.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
fit(linear_reg(), rec, mtcars)
55
Condition
66
Error in `fit()`:
7-
! The `formula` argument must be a formula, but it is a <recipe>.
7+
! The `formula` argument must be a formula.
88
i To fit a model with a recipe preprocessor, please use a workflow (`?workflows::workflow()`).
99

1010
---
@@ -13,7 +13,7 @@
1313
fit(linear_reg(), "boop", mtcars)
1414
Condition
1515
Error in `fit()`:
16-
! The `formula` argument must be a formula, but it is a <character>.
16+
! `formula` must be a formula, not the string "boop".
1717

1818
# No loaded engines
1919

0 commit comments

Comments
 (0)