1
votes

I have a package that generates some functions when you call an initialize function. I create these functions in the parent.frame of initialize(), which I guess is the global environment. I want to emulate the normal package behavior that allows you to directly call a function from a package after loading it, but without having to see those functions when you list your workspace contents using ls(). For example, doing

library(ggplot2)
ls()

doesn't return geom_line, geom_point, etc., but you don't have to use :: to call those functions. They are exposed to the user but do not live in the global environment.

Is there a clever way for me to do the same thing for functions generated by the call to initialize, e.g. by defining environments or namespaces in zzz.r and the onLoad or onAttach hooks? I thought of trying to set the function environments to the package namespace, but it seems that you cannot modify the package namespace after it is loaded.

EDIT the package I'm working on is here: https://github.com/mkoohafkan/arcpyr. The arcpy.initialize function connects to Python using PythonInR, imports the arcpy package, and then creates interfaces for a list of functions. I'll try to create a simplified dummy package later today.

1
Sure @Hack-R, I edited my question with a link. I'll try to create a simpler version later today. - mikeck
Function names that start with a . will not show up with ls(). Not exactly "clever" and not very safe if other packages use the same trick. - Eric
Why do you need to create these functions dynamically? Why not have them exist in your package's namespace, but have them throw an error if Python isn't initialized yet? - shadowtalker
@mikeck another solution would be to create and export an environment, or perhaps even an R6 class, which you can modify dynamically to your heart's content. E.g. instead of just calling an initializing function, you have your users create an instance of this environment, arcpy <- arcpy::ArcPy() which then holds all the functions you create, e.g. arcpy$some_python_function(). - shadowtalker

1 Answers

0
votes

So I eventually found a solution that uses both environments (thanks @ssdecontrol!) and attach.

f = new.env()                   # create the environment f
assign("foo", "bar", pos = f)   # create the variable foo inside f
ls()                            # lists f
ls(f)                           # lists foo
attach(f)                       # attach f to the current environment
foo                             # foo can now be accessed directly
## bar
ls()                            # but still only shows f
rm(f)                           # can even remove f
foo                             # and foo is still accessible
## bar

Of course, there are some risks to using attach.

I redid the arcpyr package to use environments instead, but you can get the old behavior back by doing

arcpy = arcpy_env()
attach(arcpy)