Export all hidden functions from a package
Asked Answered
T

2

10

Is there a way to automatically import all hidden functions from a package, ie functions accessible only with package:::fun ?

Indeed I have brought some modifications to a given function which uses quite a lot of internal functions and I want to avoid retyping package::: everywhere.

I looked at loadNamespace base function but it does not attach the non exported ones.

Twinscrew answered 15/6, 2016 at 10:30 Comment(1)
Can you give some more background? Is, e.g., creating a branch of the package and building it with your modifications an option?Yowl
T
10

Ok I finally found sort of a hack using this related post and eval:

# get all the function names of the given package "mypack"
r <- unclass(lsf.str(envir = asNamespace("mypack"), all = T))

# filter weird names
r <- r[-grep("\\[", r)]
r <- r[-grep("<-", r)]

# create functions in the Global Env. with the same name
for(name in r) eval(parse(text=paste0(name, '<-mypack:::', name)))

I would have thought there were some prebuilt function to do this anyway.

Twinscrew answered 15/6, 2016 at 11:12 Comment(4)
thanks for pointing this out. this is because of some wired names (don't know what these functions are), you should add some filtering, see my edited answerTwinscrew
Thank you very much, it works, it's very useful for some occasion for external packages used. Little addendum: to not launch one or both of r <- r[-grep(, r)] if they found nothing (integer(0)) else r return character(empty), or replace by r<-if (any(grep("\\[", r) )) r[-grep("\\[", r)] else r and r<-if (any(grep("<-", r) )) r[-grep("<-", r)] else rRhu
Sorry to be harsh, but this is an insanely convoluted, poorly working hack for something that can be done in a single line of code: list2env(as.list(asNamespace(pkgname), all.names = TRUE), envir = environment()). However, there is virtually no use-case where indiscriminately dumping all package names into the current environment is a good idea.Anni
You are right in theory for the use case, but I have one. I had installed a project with many calls directly to hidden functions because a package, from the same author of the project, was to be compiled with their hidden functions made public. But it was very difficult to recompile by hand. So I preferred to use their CRAN package...with their hidden functions. During my first installation, I copied the Theirpackage::: prefix everywhere with many risk of forgetting. With the solution of exporting everything, I don't forget anything. But yes your list2env() seems more powerful and simple.Rhu
A
3

I don’t think dumping non-exported names from a package into the current environment is ever a good idea:1 there’s a reason why these functions are not exported, and at the point where you find yourself accessing them in bulk you should stop and rethink your approach.

Given your specific use-case (edit a function from a package that needs to use non-exported names internally), a better solution would be to assign the package namespace as the function’s environment:

the_edited_function = function (…) { … }
environment(the_edited_function) = asNamespace('the_package')

… of course it goes without saying that this is also a horrible hack and should rarely be necessary.


1 It can be done with a single expression:

list2env(as.list(asNamespace('the_package'), all.names = TRUE), envir = environment())

… but, really, don’t do this.

Anni answered 11/7, 2023 at 9:50 Comment(2)
Used now, but with only the functions list2env(lapply(as.list(asNamespace("the_package"), all.names = TRUE), function(x) { if (is.function(x)) x }), envir = environment())Rhu
@Rhu You can shorten this a bit by using Filter(is.function, …) instead of lapply(…, function (x) { if (is.function(x)) x }).Anni

© 2022 - 2024 — McMap. All rights reserved.