Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to attach a package including the non-exported functions?

When debugging functions from an external package, I often find myself copying the function to a new script to add my corrections, but I have to add a bunch of foo=extpack:::foo at the beginning of the script for the function to access the internal function of the package.

Cloning and building the package would be a total overkill in those situations when often a single line is changed.

Is there a way to attach the package with all its internal functions?

Something like library(extpack, attach_nonexported=TRUE)

like image 940
Dan Chaltiel Avatar asked Dec 07 '22 10:12

Dan Chaltiel


2 Answers

You can get all functions from a package namespace as an environment by doing e.g.:

getNamespace("ggplot2")

So you can attach them to your search path (similar to calling library with unexported functions) by doing:

attach(getNamespace("ggplot2"))

If you prefer them in a list you can do

as.list(getNamespace("ggplot2"))

Or if you wish them to appear in the global workspace, you can do:

list2env(as.list(getNamespace("ggplot2")), globalenv())

Needless to say, you should only do this kind of thing with interactive sessions rather than when writing a package.

like image 130
Allan Cameron Avatar answered Dec 21 '22 23:12

Allan Cameron


if you really want to simulate a library call we can create a "package:yourpkg" on the searchpath containing all functions :

magrittr::as_pipe_fn
#> Error: 'as_pipe_fn' n'est pas un objet exporté depuis 'namespace:magrittr'
magrittr:::as_pipe_fn
#> function (expr, env) 
#> {
#>     eval(call("function", lambda_fmls, expr), env)
#> }
#> <bytecode: 0x0000000013917228>
#> <environment: namespace:magrittr>

attach_all <- function(pkg) {
  pkg <- as.character(substitute(pkg))
  pkg_long <- paste0("package:", pkg)
  eval(bquote(with(
    setNames(list(getNamespace(pkg)), pkg_long), 
    attach(.(as.symbol(pkg_long)))
  )))
}

attach_all(magrittr)

search()
#>  [1] ".GlobalEnv"        "package:magrittr"  "package:stats"    
#>  [4] "package:graphics"  "package:grDevices" "package:utils"    
#>  [7] "package:datasets"  "package:methods"   "Autoloads"        
#> [10] "tools:callr"       "package:base"
as_pipe_fn
#> function (expr, env) 
#> {
#>     eval(call("function", lambda_fmls, expr), env)
#> }
#> <bytecode: 0x0000000013917228>
#> <environment: namespace:magrittr>

Created on 2020-10-09 by the reprex package (v0.3.0)


It might make you nervous to use package:mypkg, feel free to change this part if so, the result will be the same.

Another way would be to attach the unexported functions to a different environment so you can detach it independently if needed :

attach_unexported <- function(pkg) {
  pkg <- as.character(substitute(pkg))
  all_funs <- lsf.str(asNamespace(pkg))
  exported <- getNamespaceExports(pkg)
  unexported_funs <- setdiff(all_funs, exported)
  pkg_long <- paste0(pkg, "_unexported")
  eval(bquote(with(
    setNames(list(mget(unexported_funs, asNamespace(pkg))), pkg_long), 
    attach(.(as.symbol(pkg_long)))
  )))
}

attach_unexported(magrittr)

search()
#>  [1] ".GlobalEnv"          "magrittr_unexported" "package:stats"      
#>  [4] "package:graphics"    "package:grDevices"   "package:utils"      
#>  [7] "package:datasets"    "package:methods"     "Autoloads"          
#> [10] "tools:callr"         "package:base"
as_pipe_fn
#> function (expr, env) 
#> {
#>     eval(call("function", lambda_fmls, expr), env)
#> }
#> <bytecode: 0x0000000013a05bd0>
#> <environment: namespace:magrittr>

`%>%`
#> Error in eval(expr, envir, enclos): objet '%>%' introuvable

Created on 2020-10-09 by the reprex package (v0.3.0)

like image 43
Moody_Mudskipper Avatar answered Dec 21 '22 23:12

Moody_Mudskipper