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

WISH: Make it possible to call globalCallingHandlers() in a chunk #2324

Open
HenrikBengtsson opened this issue Feb 5, 2024 · 1 comment
Open

Comments

@HenrikBengtsson
Copy link
Contributor

HenrikBengtsson commented Feb 5, 2024

(I'm not sure if this one is for the evaluate or the knitr package, but I start here)

Background

In R (>= 4.0.0), we have globalCallingHandlers() for registering global calling handlers, which are functions that handle conditions that haven't been handled previously by local calling handlers, e.g. withCallingHandlers(), tryCatch(), suppressWarnings(), etc. For example,

> globalCallingHandlers(foo = function(c) message("Woo hoo"))

will generate a message if a condition of class foo "bubbles" all the way to the global handlers.

R does not allow you to register global calling handlers in a context with active, local handlers. For instance, if we would try:

tryCatch({
  globalCallingHandlers(foo = function(c) message("Woo hoo"))
}, error = function(e) NULL)         

we get an error (that cannot be caught/handled):

Error in globalCallingHandlers(foo = function(c) message("Woo hoo")):
should not be called with handlers on the stack

Issue

Because of the above, and how code chunks are wrapped in condition handlers when evaluated, if we add a code chunk:

```{r}
globalCallingHandlers(foo = function(c) message("Woo hoo"))
```

we get:

```r
globalCallingHandlers(foo = function(c) message("Woo hoo"))
```

```
## Error in globalCallingHandlers(foo = function(c) message("Woo hoo")): should not be called with handlers on the stack
```

Wish

Make it possible to configure a code chunk such that it is evaluated without calling handlers. I understand that this limits what can be relayed, e.g. message and warning conditions. It also prevents handling of errors, unless something can be hacked around options(error = function(...) ...).

See also

This is related to feature requests for being able to register a global calling handler for progress updates by the progressr package, e.g. futureverse/progressr#166

yihui added a commit to yihui/xfun that referenced this issue Apr 29, 2024
clrpackages pushed a commit to clearlinux-pkgs/R-xfun that referenced this issue May 15, 2024
Yihui Xie (63):
      start the next version
      simply let the handler() function use location info (`loc`) directly without adding `at lines`
      add 'at lines' to the error messages only in csv_options() and yaml_load()
      inline output values
      a line that starts with 3 or more backticks followed by spaces and backticks is not a code block fence
      re-wrap roxygen comments
      let write_utf8() return the output path (the previous returned value `NULL` is rarely useful)
      ignore rhub before R 4.0.0
      prose_index() should also take raw HTML <pre></pre> into consideration
      don't include the `yaml` component in the returned value of yaml_body() if YAML metadata is not found in the input
      55575cd248536e76fc2c26bd939bb4385d18c98b was buggy; shouldn't add fences to <pre>, because <pre> might be inside fences already
      deal with an edge case when no plots were generated in the code but the device (e.g., pdf()) will generate a non-empty plot file on dev.off(); in this case, we should just delete the plot file
      prism-xcode.css has been moved to yihui/misc.js
      move find_globals()'s tests from knitr to xfun
      rename md5_obj() to md5() and export it
      always add a space after the fence if the attributes are not empty (this might be a "breaking" change if anyone is testing the Markdown output precisely, although the space is meaningless to Markdown)
      no need to record plots if no device was opened
      don't change the original cache_rds() function, although it will be less useful than the new cache_run()
      add a function cache_exec(), which can be seen as a generalized version of cache_rds()
      support caching in record()
      use a fixed path by default for the dev.path argument in record() to avoid littering the working directory with random plot files
      handle errors via options(error) instead of withCallingHandlers() to make it possible to call globalCallingHandlers(): yihui/knitr#2324
      factor out the code to merge neighbor elements in record()
      add arguments `message` and `warning` to record(), and change the `error `argument
      add a custom printing function record_print() for record() to print visible values
      declare dependency on the methods package
      provide the environment to find_globals()
      make sure `function` can be found (in baseenv())
      provide a helper function record_class() for record_print() methods to return types of output recognized by record() (e.g., source, asis, plot, message, etc)
      add an S3 method for knitr::kable()
      rename record_class() to record_new()
      forgot to document the argument `class`
      allow record_print() methods to return lists of records
      rename record_new() to new_record()
      define %||% only for R < 4.4.0
      add line numbers of YAML to the result of yaml_body()
      rename api.R to app.R
      add a function new_app() based R's internal httpd server (for hackers only), i.e., no dependency on third-party packages
      maintain the working directory for the handler
      add a function to open any path
      make sure to close sink() before closing the text connection
      add a shorthand function fenced_div()
      add a function md_table() as a bare minimal Markdown table generator
      add arguments `print` and `print.args` to record()
      escape pipes in the input
      document the global option xfun.md_table.digits
      add an argument `limit` to limit the number of rows/columns in the table
      let record_print() methods handle table caption instead
      forgot options()
      move the S3 method to litedown instead
      should get the class of out$value instead of out
      the caption argument has been removed
      use vertical ellipsis to denote omitted rows
      default values of all md_table() arguments can be set via options()
      use lazy-loading for local variables in code, i.e., load them from cache only when they are used in the future
      don't rely on the error option because users may change it; instead, just use a simple boolean variable to check if the expr can run successfully
      no need to assign to a new variable
      include the cache method name in the cache file paths, so we can switch between different methods without invalidating other methods' cache (e.g., for comparison purpose)
      don't touch the cache from other methods during cleaning up
      remove the `skip` argument of split_source(), which was originally for servr::httr() to skip code (for speed purpose), but I'll provide a better implementation in litedown later without having to skip code
      a temporary workaround to avoid breaking one of knitr's tests
      don't use \Sexpr
      CRAN release v0.44
@yihui
Copy link
Owner

yihui commented Jun 18, 2024

Just for the record, I looked into this issue in February and found it was not straightforward to solve in knitr, but I had this issue in mind when designing litedown. With litedown, when you have chunk options message=NA and warning=NA, the code chunk won't be evaluated inside withCallingHandlers(), so globalCallingHandlers() will work, e.g.,

---
title: "Test globalCallingHandlers()"
knit: litedown:::knit
---

```{r, message=NA, warning=NA}
globalCallingHandlers(foo = function(c) message("Woo hoo"))
```

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

2 participants