How do I save a image in my current environment (not Global)?

There are several bugs that I have noticed with 4.2.1 related to prophet and purr related to vctrs rules.
One particularly nasty one, seems to hard crash the Windows 2019 Server OS.

In order to find the root cause, I need to be able to save the internal environment of any rlang or v
Creating repro examples is a bit hard as by default save.image() now properly saves only the Global Environment. If I am in debug mode like browser() how can I save the current local environment I am in so I can reload an inspect it later for bugs?

x = 1
testfunction <- function(input){ 
  print("hello world")
  a <- 2
  output <- a + input
  save.image("localEnv.Rdata")
  return(ouput) 
}

So in the example above, I would want to see load("localEnv.Rdata") load in a, output, input, and not x.

Let's look at ?save.image:

save.image() is just a short-cut for ‘save my current workspace’, i.e., save(list = ls(all.names = TRUE), file = ".RData", envir = .GlobalEnv).

So, since you want finer control, you'll want to use save().

save(..., list = character(), file = stop("'file' must be specified"), ascii = FALSE, version = NULL, envir = parent.frame(), compress = isTRUE(!ascii), compression_level, eval.promises = TRUE, precheck = TRUE)

For save(), you need to provide the list of objects to save, either in ... or in list. We can use ls() to find all the objects in the environment.

So now, you get full control of the environment. By default, ls() looks in the current environment, the one where it's called, which is the function execution environment (local):

x = 1
testfunction <- function(input){ 
  a <- 2
  output <- a + input
  list_objects <- ls()
  cat("In the current env, there are ",length(list_objects)," objects: ")
  print(list_objects)
  invisible(output) 
}


testfunction(4)
#> In the current env, there are  3  objects: [1] "a"      "input"  "output"

Created on 2022-11-28 by the reprex package (v2.0.1)

So now we just want to save these objects with save(list = ls()). But save() by default looks in the parent.frame(), i.e. the parent environment (here, the global environment), so we need to be explicit that we want to look in the current environment().

x = 1
testfunction <- function(input){ 
  a <- 2
  output <- a + input
  list_objects <- ls()
  save(list = list_objects, file = "test.rda", envir = environment())
  invisible(output) 
}



if(file.exists('test.rda')) file.remove('test.rda')

testfunction(4)

rm(list = ls())

ls()
#> character(0)
load('test.rda',
     verbose = TRUE)
#> Loading objects:
#>   a
#>   input
#>   output
ls()
#> [1] "a"      "input"  "output"

Created on 2022-11-28 by the reprex package (v2.0.1)

Note: for details on how environments work, see chapter 7 of Advanced R, particularly Section 7.4.4

1 Like

@AlexisW thank for the reply.

This answer my question, but raises a bigger question about how R loads in a variable distinguishes between variables in global vs. local. I wish to know how the code for the environment package works, but when I tried to load it up using standard methods trying to access the code for both environment() and parent.frame() crashed R and Rstudio.

Do you know where the source code of these packages are found?

I no longer trust them to be where they say they are sourcing from. I am thinking about submitting a BugZilla report about access as it is related to something I brought up to @technocrat before. At my work we have found that certain packages (rlang, vctrs) are having weird behavior on a few windows 10 machines and windows server 2016 machine so neither Rstudio or R can be upgraded. To find the cause we might have to dive into the source code of environment() itself.

By "package", you mean "function", right?

Not sure what the standard method for you is, on my computer it works putting the cursor in the function name and pressing F2 (or control+click on function name). Unfortunately, the source code of these functions is deeply uninteresting:

base::parent.frame
function (n = 1) 
.Internal(parent.frame(n))

and

base::environment
function (fun = NULL) 
.Internal(environment(fun))

So these functions are written in C, to find their source code you need to dive into the sources. parent.frame() is defined here and the actual code is there; environment() seems to be here.

But if, like me, you're not familiar with C code, reading the source of these functions might be hard and pretty much useless.

Have you fully read the above-linked chapter of Advanced R? I think it gives a pretty good view of how R deals with package environments and the call stack. A more advanced document is the R Internals manual. Chances are, you would get a better idea of what's happening by reading these documents rather than the actual source code.

You can download the source code here. Before burning too much time, recall that R is a very mature language, dating from the end of the 20th century. R for Data Science has an introduction to environments. 7 Environments | Advanced R takes it further. Chapter 3 of Functional Programming in R is more advanced yet. (For the avoidance of doubt, I don't have any compensation arrangement with any of the publishers. Or anyone else for that matter.)

2 Likes

@AlexisW so for the next part to talk about I talk about a few things....

First, parallel to this thread there was an error happening with parent.frame, but I am now confident that the environment call code was not the cause. This fatal error on a Window 10 laptop can be seen in the picture below. From checking the logs from the recording, I discovered that the R froze on purr::map_dfr then to rename() then to vctrs() then to an environment call, which I now know had to be parent.frame. The user tried to close the computer and restart the computer. The logs from the computer revealed that many of the c files and .dll files associated with vctrs, the mouse pointer, and the audio/video camera had been removed by Onedrive/Sharepoint Migration.
I suspect now that R was having an issue with Rprofile, .Rproj, internet.dll, or something else stored in the Documents folder--which had been locked by Onedrive/Sharepoint. This is because of how the code for not just parent.frame but much of utilizes pointers in C that are connected to profile/project and what packages/functions are loaded in. These pointers only search once and don't loop search. At least if I am understanding the documents correctly that you linked above (?).

Correct?

We are having an ongoing issue with computers with tidyverse and vctrs installed losing access to R and all other program files since this error occurred

Still for this first bullet point, I think more ease of access is needed to underlying rlang, vctrs, tidyverse packages in terms of both the S3 methods and C functions it uses, so that an end user can trace and report bugs. So I will try to issue github to everything in rlang and vctrs that calls to a parent.frame() or uses rename().

Second, independent of the windows configuration there is an error for parent frame that I will put in a bug report to R about. If you use debugonce() on parent.frame(), it crashes your R instance.

Is bugzilla still the best method to submit bug reports? If so I will edit the recording and upload to R shortly.

P.S. Also C code is not 100% useless, but more like very time consuming to confirm the location of C files. As to see the real problems (in a lack of documentation with source code), you have git blame base R between minor versions to figure out the real reason for Errors. I had to do, I did something similar to internet.C on my github. Would you like me to share?

Interesting, it doesn't do that on my R 4.2.2 (nor 4.2.1, 4.2.0, 4.1.2, 4.1.0 that I had on my computer). What version are you using? Make sure you can reproduce in the R terminal (not Rstudio), with the --vanilla flag.

I do believe so.

I don't understand enough, I just feel that's similar to other problems we've seen on this forum (e.g. this one where you helpfully participated), where R gets installed in OneDrive and that causes problems. If that's the case, it won't be so much a bug in R's code for parent.frame(), but rather a problem that requires Windows configuration.

I did mention "if, like me, you're not familiar with C code, [...] useless". For me, it's useless, but that's because I'm not familiar with C nor the R internals; on a function like parent.frame() I could spend hours staring at the code having no idea what's happening. Obviously, for other people (e.g. the R Core team), it would be perfectly clear and meaningful.

I honestly wouldn't understand nor care enough. But if you think it might be useful to other people finding this thread because of a similar problem, sure, it would be nice for them!

I agree which is why I think packages should test over both available versions of Windows on github rather than just one. Ideally, it would be nice if people who test there code against Windows 11 but a stable build for package developers past the May 2022 update has not be released to the general public. However, two version OS testing allows you to at least better anticipate bugs.
Also Thanks for confirming the link.

Ok, I will make a recording this weekend. Would you be willing to review it to make sure it is non-technical? If so, I will share it with you this weekend. :slight_smile:

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.

If you have a query related to it or one of the replies, start a new topic and refer back with a link.