Unload a package and all dependencies
Asked Answered
A

1

8

I am trying to unload a package with all of its dependencies. The problem that I am running into is the order in which to unload dependencies. Because dependencies are recursive, they can only be unloaded from bottom-up in the dependency tree.

Is there an easy or native way in R to accomplish this? Below a first go in what I would like to accomplish:

eval_current <- function(expr, envir=parent.frame(), timeout=60){  
  #set the timeout
  setTimeLimit(elapsed=timeout, transient=TRUE);

  #currently loaded packages
  currentlyattached <- search();
  currentlyloaded <- loadedNamespaces();

  on.exit({
    #reset time limit
    setTimeLimit(cpu=Inf, elapsed=Inf, transient=FALSE);

    #try to detach packages that were attached during eval
    nowattached <- search();
    todetach <- nowattached[!(nowattached %in% currentlyattached)];
    for(i in seq_along(todetach)){
      try(detach(todetach[i], unload=TRUE, character.only=TRUE, force=TRUE));
    }

    #try to unload packages that are still loaded
    nowloaded <- loadedNamespaces(); 
    tounload <- nowloaded[!(nowloaded %in% currentlyloaded)];
    for(i in seq_along(tounload)){
      try(unloadNamespace(tounload[i]));
    }    

  });

  eval(expr, envir) 
}

But it results in:

> eval_current({library(ggplot2); qplot(rnorm(100));})
Error in unloadNamespace(tounload[i]) : 
  namespace ‘colorspace’ is imported by ‘munsell’ so cannot be unloaded
Error in unloadNamespace(tounload[i]) : 
  namespace ‘dichromat’ is imported by ‘scales’ so cannot be unloaded
Error in unloadNamespace(tounload[i]) : 
  namespace ‘grid’ is imported by ‘gtable’ so cannot be unloaded
Error in unloadNamespace(tounload[i]) : 
  namespace ‘labeling’ is imported by ‘scales’ so cannot be unloaded
Error in unloadNamespace(tounload[i]) : 
  namespace ‘munsell’ is imported by ‘scales’ so cannot be unloaded
Astrogation answered 21/7, 2013 at 13:21 Comment(8)
I'd killall R; R instead. Processes are cheap.Bigot
Haha yes, this is already a windows specific solution. On unix we can just use a temporary fork indeed.Astrogation
For every minute you spend engineering around a Windows wart, $Deity kills a kitten. Just don't do it.Bigot
I'm sure Rcpp didn't compile on Windows without a little tweak here and there :-)Astrogation
We don't claim you can cleanly unload its DLL. Some other people have other opinions (cf package devtools) but are of course free to do so. The Rcpp code really has only minimal tweaks for Windoze. Doing more would mean that my cat got really mad at me.Bigot
See devtools::unload for our best attempt at this. But as @DirkEddelbuettel says, if there's any way to use a new process instead, you're better off doing that. R is not designed to cleanly unload packages.Nuno
@Nuno devtools::unload does not attempt to do any recursive unloading of dependencies right? Or am I missing something?Astrogation
@Jeroen no, you'd have to implement that yourself - it's something we've talked about but haven't done.Nuno
K
2

This works for me -- a bit crude but gets the job done.

on.exit({
  #reset time limit
  setTimeLimit(cpu=Inf, elapsed=Inf, transient=FALSE);

  #try to detach packages that were attached during eval
  nowattached <- search();
  todetach <- nowattached[!(nowattached %in% currentlyattached)];
  while( ! length(todetach) == 0 ){
    for(i in seq_along(todetach)){
      suppressWarnings(tryCatch(detach(todetach[i], unload=TRUE, character.only=TRUE, force=TRUE),error = function(x) return(NA)))
    }
    nowattached <- search();
    todetach <- sample(nowattached[!(nowattached %in% currentlyattached)]);
  }

  #try to unload packages that are still loaded
  nowloaded <- loadedNamespaces(); 
  tounload <- nowloaded[!(nowloaded %in% currentlyloaded)];
  while( ! length(tounload) == 0 ){
    for(i in seq_along(todetach)){
      suppressWarnings(tryCatch(unloadNamespace(tounload[i]),error = function(x) return(NA)))
    }
    nowloaded <- loadedNamespaces(); 
    tounload <- sample(nowloaded[!(nowloaded %in% currentlyloaded)]);
  }
});
Kennakennan answered 13/1, 2015 at 16:5 Comment(1)
I think that the for loop in the second while should be for(i in seq_along(tounload))Zabrine

© 2022 - 2024 — McMap. All rights reserved.