How to determine the import namespace order in [R]

I need to clear an instance of R in order to return it to its virgin state. So far I am doing:

At startup, record downloaded packages and namespaces

original_packages <- grep('^package:', search(), value = TRUE) original_namespaces <- loadedNamespaces() 

When I need to clear an instance, disconnect every downloaded package that was not there at startup:

 for (pkg in grep('^package:', search(), value = TRUE)) { if (! pkg %in% original_packages){ detach(pkg, unload=TRUE, force=TRUE, character.only=TRUE) } } 

The problem is that if I downloaded a package with a bunch of imported namespaces like ggplot2, these namespaces remain loaded, and I have to unload them in import order, starting from the top level. Just unloading them blindly does not work, since I get a "namespace" x imported by the errors "y, z, so it cannot be unloaded."

Here is an example of reproducibility:

 original_packages <- grep('^package:', search(), value = TRUE) original_namespaces <- loadedNamespaces() library(ggplot2) library(plyr) loadedNamespaces() for (pkg in grep('^package:', search(), value = TRUE)) { if (! pkg %in% original_packages){ detach(pkg, unload=TRUE, force=TRUE, character.only=TRUE) } } for (ns in loadedNamespaces()) { if (! ns %in% original_namespaces){ unloadNamespace(ns) } } 

Is there a way to define a namespace import hierarchy? If so, then I should just be able to arrange the last loop correctly ...

+6
source share
2 answers

As @Josh O'Brien said, it's impossible to get a clean environment by disconnecting or unloading namespaces.

But to answer your question, here is a simple approach to unload all namespaces in the correct order using tools:::dependsOnPkgs :

 ## params: originalNamespaces is a list of namespaces you want to keep cleanNamespaces <- function(originalNamespaces) { ## which namespaces should be removed? ns <- setdiff(loadedNamespaces(), originalNamespaces) ## get dependency list dep <- unlist(lapply(ns, tools:::dependsOnPkgs)) ## append namespaces to guarantee to fetch namespaces with ## no reverse dependencies ns <- c(dep, ns) ## get namespace names in correct order to unload without errors ns <- names(sort(table(ns), decreasing=TRUE)) ## only unload namespaces which are attached ns <- ns[ns %in% loadedNamespaces()] ## unload namespaces invisible(sapply(ns, unloadNamespace)) } 
0
source

Well, I chose a hacking solution of a truly hacker need. Any advice on how to do this better would be appreciated. In particular, I am not very pleased with the purpose of <<- global namespace_depths object.

 original_packages <- grep('^package:', search(), value = TRUE) original_namespaces <- loadedNamespaces() library(ggplot2) library(plyr) loadedNamespaces() new_packages <- Filter(function(pkg) { ! pkg %in% original_packages }, grep('^package:', search(), value = TRUE)) new_namespaces <- Filter(function(ns) { ! ns %in% original_namespaces }, loadedNamespaces()) get_imports <- function(ns, depth) { imports <- Filter(function(ns) { ! ns %in% original_namespaces }, names(getNamespaceInfo(ns, 'imports'))) if (length(imports) == 0 ) { if ( is.null(namespace_depths[[ns]]) || namespace_depths[[ns]] < depth){ namespace_depths[[ns]] <<- depth } return() } for (imported_ns in imports){ get_imports(imported_ns, depth + 1) } if ( is.null(namespace_depths[[ns]]) || namespace_depths[[ns]] < depth){ namespace_depths[[ns]] <<- depth } } namespace_depths <- list() sapply(new_namespaces, get_imports, 0) for (ns in names(namespace_depths)[order(unlist(namespace_depths))]) { if (! ns %in% original_namespaces){ unloadNamespace(ns) } } for (pkg in new_packages){ detach(pkg, unload=TRUE, force=TRUE, character.only=TRUE) } 
0
source

Source: https://habr.com/ru/post/919170/


All Articles