Skip to content

Commit

Permalink
Merge pull request #1527 from rstudio/knitr-format-exceptions
Browse files Browse the repository at this point in the history
knitr eng: format captured exceptions
  • Loading branch information
t-kalinowski authored Jan 29, 2024
2 parents 0e5676e + afee13b commit ca86913
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 9 deletions.
7 changes: 6 additions & 1 deletion NEWS.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
# reticulate (development version)

- The knitr python engine now formats captured python exceptions to include the
exception type and any exception notes when chunk options
`error = TRUE` is set (reported in #1520, fixed in #1527).

- R external pointers (EXTPTRSXP objects) now round-trip through
`py_to_r(r_to_py(x))` successfully.
(reported in #1511, fixed in #1519, contributed by @llaniewski).

- Fixed issue where `virtualenv_create()` would error on Ubuntu 22.04 when
using the system python as a base. (#1495, fixed in #1496).

- Fixed issue where `csc_matrix` objects with unsorted indices could not be converted to a dgCMatrix. (related to #727, fixed in #1524, contributed by @rcannood).
- Fixed issue where `csc_matrix` objects with unsorted indices could not be
converted to a dgCMatrix. (related to #727, fixed in #1524, contributed by @rcannood).

# reticulate 1.34.0

Expand Down
26 changes: 21 additions & 5 deletions R/knitr-engine.R
Original file line number Diff line number Diff line change
Expand Up @@ -252,8 +252,25 @@ eng_python <- function(options) {
compile_mode <- if (suppress) "exec" else "single"

# run code and capture output
captured_stdout <- if (capture_errors)
tryCatch(py_compile_eval(snippet, compile_mode), error = identity)
captured_stdout <- if (capture_errors) {
tryCatch(
py_compile_eval(snippet, compile_mode),
error = function(e) {

# if the chunk option is error = FALSE (the default).
# we'll need to bail and not evaluate to the next python expression.
if (identical(options$error, FALSE))
had_error <- TRUE

# format the exception object
etype <- py_get_attr(e, "__class__")
traceback <- import("traceback")
paste0(traceback$format_exception_only(etype, e),
collapse = "")
}
)

}
else
py_compile_eval(snippet, compile_mode)

Expand Down Expand Up @@ -304,10 +321,9 @@ eng_python <- function(options) {
pending_source_index <- range[2] + 1

# bail if we had an error with 'error=FALSE'
if (identical(options$error, FALSE) && inherits(captured, "error")) {
had_error <- TRUE
if (had_error && identical(options$error, FALSE))
break
}


}
}
Expand Down
30 changes: 27 additions & 3 deletions tests/testthat/resources/eng-reticulate-example.Rmd
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,20 @@ library(reticulate)
knitr::knit_engines$set(python = eng_python)
# use specific environment if available
python <- "~/.virtualenvs/python-3.7.7-venv/bin/python"
if (file.exists(python))
reticulate::use_python(python, required = TRUE)
# python <- "~/.virtualenvs/python-3.7.7-venv/bin/python"
# if (file.exists(python))
# reticulate::use_python(python, required = TRUE)
# use rlang error handler
if (requireNamespace("rlang", quietly = TRUE))
options(error = rlang::entrace)
```

```{r}
reticulate::py_config()
```


Python variables live across chunk boundaries.

```{python}
Expand Down Expand Up @@ -129,6 +134,25 @@ raise RuntimeError("oops!")
print("This line is still reached.")
```

Ensure that Exceptions are formatted w/ the type and notes.
```{python, error=TRUE}
class CustomException(Exception):
pass
e = CustomException("oops!")
# BaseException.add_note() added in Python 3.11
import sys
if sys.version_info >= (3, 11):
e.add_note("note 1: extra oopsy oops")
e.add_note("note 2: in the future avoid oopsies")
else:
print(sys.version_info)
raise e
print("This line is still reached.")
```

Ensure that lines with multiple statements are only run once.

```{python}
Expand Down

0 comments on commit ca86913

Please sign in to comment.