-
Notifications
You must be signed in to change notification settings - Fork 36
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Refactor error handling of the repository (#233)
Co-authored-by: sorhawell <sorhawell@gmail.com> Co-authored-by: eitsupi <50911393+eitsupi@users.noreply.github.com>
- Loading branch information
1 parent
0b7b8d3
commit 71f3d05
Showing
40 changed files
with
1,596 additions
and
920 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
# THIS FILE IMPLEMENTS ERROR CONVERSION, FOR R TO Result-list & FOR Result-list TO R | ||
|
||
# TODO unwrap should be eventually renamed to unwrap_with_context (or similar) | ||
# a simpler unwrap without where_in and when_calling should be defined in rust_result.R | ||
|
||
#' rust-like unwrapping of result. Useful to keep error handling on the R side. | ||
#' | ||
#' @param result a list here either element ok or err is NULL, or both if ok is litteral NULL | ||
#' @param call context of error or string | ||
#' @param context a msg to prefix a raised error with | ||
#' | ||
#' @return the ok-element of list , or a error will be thrown | ||
#' @keywords internal | ||
#' @examples | ||
#' | ||
#' # get unwrap without using ::: | ||
#' unwrap = environment(polars::pl$all)$unwrap | ||
#' | ||
#' structure(list(ok = "foo", err = NULL), class = "extendr_result") | ||
#' | ||
#' tryCatch( | ||
#' unwrap( | ||
#' structure( | ||
#' list(ok = NULL, err = "something happen on the rust side"), | ||
#' class = "extendr_result" | ||
#' ) | ||
#' ), | ||
#' error = function(err) as.character(err) | ||
#' ) | ||
unwrap = function(result, context = NULL, call = sys.call(1L)) { | ||
if (is_ok(result)) { | ||
result$ok | ||
} else { | ||
result$err |> | ||
where_in(context) |> | ||
when_calling(call) |> | ||
to_condition() |> | ||
stop() | ||
} | ||
} | ||
|
||
#' rust-like unwrap_err, internal use only | ||
#' @details | ||
#' throwed error info is sparse because only for internal errors | ||
#' @keywords internal | ||
#' @param result a Result, see rust_result.R#' | ||
#' @return some error type | ||
unwrap_err = function(result) { | ||
if (is_ok(result)) { | ||
stop("internal error: Cannot unwrap_err an Ok-value") | ||
} else { | ||
result$err | ||
} | ||
} | ||
|
||
|
||
#' Capture any R error and return a rust-like Result | ||
#' @param expr code to capture any error from and wrap as Result | ||
#' @param msg handy way to add a context msg | ||
#' @keywords internal | ||
#' @return Result | ||
#' @examples | ||
#' | ||
#' # user internal functions without using ::: | ||
#' result = environment(polars::pl$all)$result | ||
#' unwrap_err = environment(polars::pl$all)$unwrap_err | ||
#' unwrap = environment(polars::pl$all)$unwrap | ||
#' Err = environment(polars::pl$all)$Err | ||
#' | ||
#' # capture regular R errors or RPolarsErr | ||
#' throw_simpleError = \() stop("Imma simple error") | ||
#' result(throw_simpleError()) | ||
#' | ||
#' throw_RPolarsErr = \() unwrap( | ||
#' Err(.pr$RPolarsErr$new()$bad_robj(42)$mistyped("String")$when("doing something")) | ||
#' ) | ||
#' res_RPolarsErr = result(throw_RPolarsErr()) | ||
#' str(res_RPolarsErr) | ||
#' RPolarsErr = unwrap_err(res_RPolarsErr) | ||
#' RPolarsErr$contexts() | ||
result = function(expr, msg = NULL) { | ||
tryCatch( | ||
Ok(expr), | ||
error = \(cond) cond$value %||% cond$message |> | ||
plain(msg) |> | ||
Err() | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
# ANY NEW ERROR MUST IMPLEMENT THESE S3 METHODS, these are the "trait" of a polars error | ||
# ALSO MUST IMPLEMENT BASE THESE METHODS: print | ||
|
||
#' Internal generic method to add call to error | ||
#' @param err any type which impl as.character | ||
#' @param call calling context | ||
#' @details | ||
#' Additional details... | ||
#' | ||
#' @keywords internal | ||
#' @return err as string | ||
#' @examples | ||
#' # | ||
when_calling = function(err, call) { | ||
if (polars_optenv$do_not_repeat_call || is.null(call)) { | ||
err | ||
} else { | ||
UseMethod("when_calling", err) | ||
} | ||
} | ||
when_calling.default = function(err, call) { | ||
stop("internal error: an error-type was not fully implemented") | ||
} | ||
# support function to convert a call to a string | ||
call_to_string = function(call) { | ||
paste( | ||
"\n", | ||
paste(capture.output(print(call)), collapse = "\n") | ||
) | ||
} | ||
|
||
|
||
#' Internal generic method to point to which public method the user got wrong | ||
#' @param err any type which impl as.character | ||
#' @param call calling context | ||
#' @keywords internal | ||
#' @return err as string | ||
#' @examples | ||
#' # | ||
where_in = function(err, context) { | ||
if (is.null(context)) { | ||
return(err) | ||
} | ||
if (!is_string(context)) { | ||
stop( | ||
paste( | ||
"internal error: where_in context must be a string or NULL it was: ", | ||
str_string(context) | ||
) | ||
) | ||
} | ||
UseMethod("where_in", err) | ||
} | ||
where_in.default = function(err, context) { | ||
stop("internal error: an error-type was not fully implemented") | ||
} | ||
|
||
#' Internal generic method to convert an error_type to condition. | ||
#' @param err any type which impl as.character | ||
#' @param call calling context | ||
#' @keywords internal | ||
#' @details | ||
#' this method is needed to preserve state of err without upcasting to a string message | ||
#' an implementation will describe how to store the error in the condition | ||
#' @return condition | ||
to_condition = function(err) { | ||
UseMethod("to_condition", err) | ||
} | ||
to_condition.default = function(err) { | ||
errorCondition( | ||
paste(capture.output(print(err)), collapse = "\n"), | ||
class = c("default_error"), | ||
value = err, | ||
call = NULL | ||
) | ||
} | ||
|
||
|
||
|
||
#' Internal generic method to add plain text to error message | ||
#' @param err some error type object | ||
#' @param msg string to add | ||
#' @keywords internal | ||
#' @return condition | ||
plain = function(err, msg) { | ||
if (is.null(msg)) { | ||
return(err) | ||
} | ||
UseMethod("plain", err) | ||
} | ||
plain.default = function(err, msg) { | ||
paste0(msg, ": ", err) | ||
} |
Oops, something went wrong.