Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature request: classed errors for specific tidyselect errors #351

Open
yjunechoe opened this issue Apr 30, 2024 · 1 comment
Open

Feature request: classed errors for specific tidyselect errors #351

yjunechoe opened this issue Apr 30, 2024 · 1 comment

Comments

@yjunechoe
Copy link

A user's attempt at selecting a column can fail for various reasons - currently, there are some (extremely brittle) ways to infer what went wrong.

Briefly, if we wanted to distinguish between these three types of tidyselect errors (mismatch, other evaluation error, empty):

library(rlang)
library(tidyselect)
df <- data.frame(x = 1)

selectors <- exprs(
  mismatch = z,
  error = stop(),
  empty = 
)

We know that a mismatch error is classed with a vctrs subscript oob error (as of the most recent update) and also stores the problematic selection in $i:

err_mismatch <- catch_cnd(
  eval_select(selectors$mismatch, df)
)
class(err_mismatch)
#> [1] "vctrs_error_subscript_oob" "vctrs_error_subscript"    
#> [3] "rlang_error"               "error"                    
#> [5] "condition"
err_mismatch$parent
#> NULL
err_mismatch$i
#> [1] "z"

An error from evaluating the user-supplied expression gets chained, so these errors are distinguished by having a $parent:

err_error <- catch_cnd(
  eval_select(selectors$error, df)
)
class(err_error)
#> [1] "rlang_error" "error"       "condition"
err_error$parent
#> <simpleError in eval_tidy(as_quosure(expr, env), context_mask): >
err_error$i
#> NULL

Lastly, an empty selection that's promoted to an error with allow_empty = FALSE has neither $i nor a $parent:

err_empty <- catch_cnd(
  eval_select(selectors$empty, df, allow_empty = FALSE)
)
class(err_empty)
#> [1] "rlang_error" "error"       "condition"
err_empty$parent
#> NULL
err_empty$i
#> NULL

I fully acknowledge that these are not part of the official API, so I do not mean to build on top of this pattern. Instead, I was hoping that tidyselect could throw more specific, classed errors, where possible. For example, it'd be nice for an empty selection error with allow_empty = FALSE to look something like this:

err_empty2 <- catch_cnd(
  eval_select(selectors$empty, df, allow_empty = FALSE)
)
class(err_empty2)
#> [1] "tidyselect_error_disallow_empty" "rlang_error"                    
#> [3] "error"                           "condition"

... by adding the "tidyselect_error_*" class where the error gets thrown:

tidyselect/R/eval-walk.R

Lines 128 to 132 in fd22cc1

check_empty <- function(x, allow_empty = TRUE, call = caller_env()) {
if (!allow_empty && length(x) == 0) {
cli::cli_abort("Must select at least one item.", call = call)
}
}

I realize that this is a non-trivial ask that probably requires a lot of deliberation, but I was curious whether this is within scope / planned to be worked on. Thanks in advance for considering!

@yjunechoe
Copy link
Author

Geez I'm just seeing that #350 partially addresses this -- sorry for the noise. My issue is not a complete duplicate but pretty close, so please feel free to close this issue if you decide to merge that other PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant