2012-06-27 8 views
6

Ho bisogno di ripulire un'istanza R per restituirlo allo stato di virginal all'avvio. Finora, quello che sto facendo è:Come determinare l'ordine di importazione dello spazio dei nomi in [R]

Su lancio, registrare i pacchetti e gli spazi dei nomi caricati

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

Quando ho bisogno di svuotare l'istanza, staccare ogni pacchetto caricato che non c'era al momento del lancio:

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

Il problema è che se ho caricato un pacchetto con un mazzo di spazi dei nomi importati, come ggplot2, quegli spazi restano caricati, e devo scaricarli in ordine di importazione, da alto livello verso il basso. Semplicemente scaricandoli ciecamente non funziona, dato che "namespace" x "è importato da errori" y "," z "quindi non può essere scaricato".

Ecco esempio riproducibile:

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) 
    } 
} 

C'è qualche modo per capire la gerarchia dello spazio dei nomi di importazione? Se è così, allora dovrei essere in grado di ordinare l'ultimo ciclo correttamente ...

+4

ho rinunciato a questo metodo molto tempo fa. AFAIK, la documentazione per 'detach' dice che non è garantito il funzionamento. L'unico modo garantito è iniziare una nuova sessione. – Andrie

+0

Sì, sfortunatamente non riesco ad avviare una nuova sessione con rpy2 AFAICT - questo è per un'app Web che ha una sessione R persistente nel suo design attuale. – Tarek

+1

In seguito al commento di @ Andrie, gli ultimi commenti sulla risposta a [questa domanda SO] (http://stackoverflow.com/questions/11004018/how-can-a-non-imported-method-in-a- not-attached-package-be-found-by-calls-to-fun) ottenere uno dei motivi per cui semplicemente 'detach'ing non ripristinerà in modo affidabile la tua sessione al suo stato originale. –

risposta

0

Come @Josh O'Brien ha menzionato, non è possibile ottenere un ambiente pulito scollegando o scaricando spazi dei nomi.

Ma per rispondere alla tua domanda qui è un approccio semplice per scaricare tutti gli spazi dei nomi in ordine corretto utilizzando 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

Ok, ho gettato insieme una soluzione hacky per un fabbisogno certamente hacky. Qualche consiglio su come farlo meglio sarebbe apprezzato. In particolare, non sono molto contento dell'assegnazione di <<- dell'oggetto globale namespace_depths.

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

FWIW, nell'esempio che ho collegato sopra, questo * still * non elimina i metodi dai pacchetti precedentemente collegati (in questo caso 'reorder.factor()' da 'gmodels') che sono stati registrati in' .__ S3MethodsTable__ .'s di pacchetti ancora attaccati (in questo caso 'stats'). –

+0

Grazie per questo chiarimento, Josh. Fortunatamente, questo è abbastanza buono per quello che sto facendo, e la risposta di sgibb è molto più semplice della mia. – Tarek

Problemi correlati