rscopecallr

How to refer to the .GlobalEnv of the session using callr::r


My understanding of callr::r is that the function I am providing is evaluated in a new session of R. If (for whatever reason) I want to keep the .GlobalEnv of this session, I thought I could do it like this:

i_am_defined_on_global_level <- "here"
res <- callr::r(function() .GlobalEnv)
names(res)
# [1] "res"                          ".Random.seed"                
# [3] "i_am_defined_on_global_level"

But apparently .GlobalEnv within the anonymous function refers to the global environment of the calling environment (otherwise I would not see i_am_defined_on_global_level).

So how would I return the .GlobalEnv of the session in which the function is called?

Background

I have a large Rmarkdown document and because of current bugs in Rstudio I cannot run run all chunks as I have non R chunks in my document. Thus, I have to run each chunk "by hand" which is rather cumbersome.

Thus, I wanted to call render not via the knit button, but from the command line, where I have control over the environment in which the document is rendered and thus could keep all intermediate results. I thought it would be a good idea to do so in a new session to avoid name conflicts, thus I wanted to rely on callr::r:

render_report <- function(report = "myreport.Rmd",
                          report_dir = here::here("report")) {
   report_env <- callr::r(function(report, report_dir) {
      rmarkdown::render(file.path(report_dir, report), 
                        output_dir = report_dir,
                        envir = globalenv())
      globalenv()
   }, list(report = report, 
           report_dir = report_dir),
   show = TRUE,
   spinner = FALSE)
   report_env
}

results <- render_report()

But results refers then only to the original GlobalEnv.


Solution

  • [Edited to correct the first sentence.] The problem is that .GlobalEnv is saved in a weird way. It just refers to the current global environment, whatever that is. So anything you create in your function will disappear, and res will point to your current global environment.

    To see the globals in the callr::r environment, I think you'll have to copy them to a new environment and return that. E.g.

    i_am_defined_on_global_level <- "here"
    res <- callr::r(function() {
      i_am_in_the_callr_global_env <<- "there"
      returnenv <- as.list(globalenv())
      list2env(returnenv)
      })
    names(res)
    #> [1] "i_am_in_the_callr_global_env"
    

    Created on 2023-01-12 with reprex v2.0.2