futureverse / progressr

三 R package: An Inclusive, Unifying API for Progress Updates
https://progressr.futureverse.org
281 stars 12 forks source link

How can I run handlers(global = TRUE) from an R Markdown (Rmd) file? #166

Closed tripartio closed 8 months ago

tripartio commented 8 months ago

In trying to demonstrate the functionality of my package to users, I want to make progress bars as invisible as possible. Yet, using the fantastic progressr implementation, I need to show users how to activate global handling of progress bars. But how can I do this in an R Markdown (Rmd) file for a vignette? Even this very minimal example crashes:

---
title: "progressr global test"
output: html_document
---

```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE)
```

```{r}
progressr::handlers(global = TRUE)
```
Error in globalCallingHandlers(condition = global_progression_handler) : 
    should not be called with handlers on the stack
    3. globalCallingHandlers(condition = global_progression_handler)
    2. register_global_progression_handler(action = action)
    1. progressr::handlers(global = TRUE)

In the [progressr] package documentation, we are told "In such cases, the global progress handler has to be enabled prior to processing the document, e.g."

> progressr::handlers(global = TRUE)
> rmarkdown::render("input.Rmd")

But how is that possible in standard package documentation? As far as I can tell, progressr::handlers(global = TRUE) is for interactive use. I do not see how a package developer can easily communicate this information to their package users. I would appreciate any help with this.

HenrikBengtsson commented 8 months ago

This is a limitation in R that progressr cannot work around. It's possible that knitr can provide a workaround. I've posted "WISH: Make it possible to call globalCallingHandlers() in a chunk" (https://github.com/yihui/knitr/issues/2324) to propose this.

HenrikBengtsson commented 8 months ago

Forgot to say:

As far as I can tell, progressr::handlers(global = TRUE) is for interactive use.

No, it's not only for interactive use. It also works in batch mode, e.g. Rscript script.R. The problem is that it does not work when called within things such as withCallingHandlers(), tryCatch(), ..., and that's the problem in several case, including knitr, rmarkdown, etc.

tripartio commented 8 months ago

@HenrikBengtsson Thanks for the response. Oh well.

So, I'll do the next best thing: in every vignette and website article, before loading my package, I briefly explain to users how to activate the package. But I place these in Rmd with the eval = FALSE chunk option, like so:

```{r enable progressr, eval = FALSE}
progressr::handlers(global = TRUE)
progressr::handlers('cli')
```

It's not quite ideal, but the trade-off for getting to use your great package is worth it. Thanks again!