I'd like to push a function inside a package namespace so it can access internal objects of that package (let's use stats package as an example). I've tried using
myfun <- function(x) print(x)
env = loadNamespace("stats")
assign("myfun", myfun , env)
But it is locked. So I've tried to unlock my object
unlockBinding("myfun", env)
Since myfun doesn't exist yet, I can't unlock it.
Any help ?
Along the line of #Hadley's solution, but using the environment of the namespace, how about:
environment(myfun) <- asNamespace('stats')
Why not just set the environment of your new function to the right place?
myfun <- function(x) print(x)
environment(myfun) <- as.environment("package:stats")
You can access internal objects of a package using the triple colon operator :::. Take a look at, for example, as.roman and utils:::.roman2numeric. (Compare this to utils::.roman2numeric.) This could help you avoid having to put your function inside the namespace.
You might also want to look at dont.lockBindings in the mvbutils package, which stops namespaces being locked.
Related
I like using function reshape from the matlab package, but I need then to specify base::sum(m) each time I want to sum the elements of my matrix or else matlab::sum is called, which only sums by columns..
I need loading package gtools to use the rdirichlet function, but then the function gtools::logit masks the function pracma::logit that I like better..
I gess there are no such things like:
library(loadOnly = "rdirichlet", from = "gtools")
or
library(loadEverythingFrom = "matlab", except = "sum")
.. because functions from the package matlab may internaly work on the matlab::sum function. So the latter must be loaded. But is there no way to get this behavior from the point of view of the user? Something that would feel like:
library(pracma)
library(matlab)
library(gtools)
sum <- base::sum
logit <- pracma::logit
.. but that would not spoil your ls() with all these small utilitary functions?
Maybe I need defining my own default namespace?
To avoid spoiling your ls, you can do something like this:
.ns <- new.env()
.ns$sum <- base::sum
.ns$logit <- pracma::logit
attach(.ns)
To my knowledge there is no easy answer to what you want to achieve. The only dirty hack I can think of is to download the source of the packages "matlab", "gtools", "pracma" and delete the offending functions from their NAMESPACE file prior to installation from source (with R CMD INSTALL package).
However, I would recommend using the explicit notation pracma::logit, because it improves readability of your code for other people and yourself in the future.
This site gives a good overview about package namespaces:
http://r-pkgs.had.co.nz/namespace.html
I am writing some data manipulation scripts in R, and I finally decided to create an external .r file and call my functions from there. But it started giving me some problems when I try calling some functions. Simple example:
This one works with no problem:
change_column_names <- function(file,new_columns,seperation){
new_data <- read.table(file, header=TRUE, sep=seperation)
colnames(new_data) <- new_columns
write.table(new_data, file=file, sep=seperation, quote=FALSE, row.names = FALSE)
}
change_column_names("myfile.txt",c("Column1", "Column2", "Cost"),"|")
When I crate a file "data_manipulation.r", and put the above change_column_names function in there, and do this
sys.source("data_manipulation.r")
change_column_names("myfile.txt",c("Column1", "Column2", "Cost"),"|")
it does not work. It gives me could not find function "read.table" error. I fixed it by changing the function calls to util:::read.table and util:::write.table .
But this kinda getting frustrating. Now I have the same issue with the aggregate function, and I do not even know what package it belongs to.
My questions: Which package aggregate belongs to? How can I easily know what packages functions come from? Any cleaner way to handle this issue?
The sys.source() by default evaluates inside the base environment (which is empty) rather than the global environment (where you usually evaluate code). You probably should just be using source() instead.
You can also see where functions come from by looking at their environment.
environment(aggregate)
# <environment: namespace:stats>
For the first part of your question: If you want to find what package a function belongs to, and that function is working properly you can do one of two (probably more) things:
1.) Access the help files
?aggregate and you will see the package it belongs to in the top of the help file.
Another way, is to simply type aggregate without any arguments into the R console:
> aggregate
function (x, ...)
UseMethod("aggregate")
<bytecode: 0x7fa7a2328b40>
<environment: namespace:stats>
The namespace is the package it belongs to.
2.) Both of those functions that you are having trouble with are base R functions and should always be loaded. I was not able to recreate the issue. Try using source instead of sys.source and let me know if it alleviates your error.
I use some user-defined small functions as helpers. These functions are all stored in a R_HOME_USER/helperdirectory. Until now, these functions were sourced at R start up. The overall method is something like `lapply(my.helper.list,source). I want now these functions to be sourced but not to appear in my environment, as they pollute it.
A first and clean approach would be to build a package with all my helper.R. For now, I do not want to follow this method. A second approach would be to name these helpers with a leading dot. This annoys me to have to run R > .helper1().
Best way would be to define these helpers in a specific and accessible environment, but I am messing with the code. My idea is to create first a new environment:
.helperEnv <- new.env(parent = baseenv())
attach(.helperEnv, name = '.helperEnv')
Fine, R > search() returns 'helperEnv' in the list. Then I run :
assign('helper1', helper1, envir = .helperEnv)
rm(helper1)
Fine, ls(.helperEnv)returns 'helper1' and this function does not appear anymore in my environment.
The issue is I can't run helper1 (object not found). I guess I am not on the right track and would appreciate some hints.
I think you should assign the pos argument in your call to attach as a negative number:
.helperEnv <- new.env()
.helperEnv$myfunc<-function(x) x^3+1
attach(.helperEnv,name="helper",pos=-1)
ls()
#character(0)
myfunc
#function(x) x^3+1
Instead of doing
a <- loadBigObject("a")
b <- loadBigObject("b")
I'd like to call a function like
loadBigObjects(list("a","b"))
And be able to access the a and b objects.
It is not clear what loadBigObjects() does or where it will look for a and b. How does it load the objects from file or sourcing code?
There are lots of options in general:
sys.source() allows an R file to be sourced to a given environment
load() which will load an .Rdata file to a given environment
assign() in combination with any object created by loadBigObjects() or a call to readRDS() can also load an object to a given environment.
From within your function, you'll want to specify the environment in which to load objects as the Global Environment by using globalenv(). If you don't do that then the object will only exist in the evaluation frame of the running loadBigObjects(). E.g.
loadBigObjects <- function(list) {
lapply(list, function(x) assign(x, readRDS(x), envir = globalenv()))
}
(as per your comment to #GSee's Answer, and assuming the list("a","b") is sufficient information for readRDS() to locate and open the object.
Without knowing anything about what loadBigObject is or does, you can use lapply to apply a function to a list of objects
lapply(list("a", "b"), loadBigObject)
If you provided the code for loadBigObject or at least describe what it is supposed to do, a better loadBigObjects function could probably be written.
The assign function can be used to define a variable in an environment other than the current one.
loadBigObjects <- function(lst) {
lapply(lst, function(l) {
assign(l, loadBigObject(l), envir=globalenv())
}
lst
}
(Not that this is necessarily a good idea.)
I would like to create a function within a package with a NAMESPACE that will save some variables. The problem is that when load is called on the .Rdata file it
tries to load the namespace of the package that contained the function that created the .Rdata file, but this package need not be loaded.
This example function is in a package in a namespace :
create.global.function <- function(x, FUN, ...) {
environment(FUN) <- .GlobalEnv
assign(".GLOBAL.FUN", function(x) { FUN(x, ...) }, env=.GlobalEnv)
environment(.GLOBAL.FUN) <- .GlobalEnv
save(list = ls(envir = .GlobalEnv, all.names = TRUE),
file = "/tmp/.Rdata",
envir = .GlobalEnv)
}
The environment(.GLOBAL.FUN) <- .GlobalEnv calls are not sufficient and attaching gdb to the R process confirms it is serializing a NAMESPACESXP here with the name of the package namespace and the load fails because it is unable to load this.
Is it possible to fully strip the namespace out of the .GLOBAL.FUN before I save it such that it can be loaded into other R instances without trying to load the namespace?
#JorisMeys snowfall and the others do not offer exactly this functionality.
snowfall uses sfExport ( from clusterFunctions.R in snowfall) to export local and global objects to the slave nodes, and this in turn uses sfClusterCall which is a wrapper around the clusterCall function from snow.
res <- sfClusterCall( assign, name, val, env = globalenv(),
stopOnError = FALSE )
And the snow library is loaded on the clients getting around any namespace issues as I mentioned in the last sentence of my question I would like to not load the namespace there.
Furthermore, it seems to make simplified assumptions such as that the nodes will share an NFS mount point for shared data (e.g. sfSource function in clusterFunctions.R).
I am more interested in something like a case where a node saves an .Rdata file then scp's it to another node that need not have the package namespace loaded.
It seems I can for now solve my original problem by using eval.parent and substitute:
assign(".GLOBAL.FUN",
eval.parent(substitute(function(y) { FUN(y, ...) })),
env=.GlobalEnv)
I apologize for the posting snafu, but I do not have an edit link although I posted this question, nor is there any place for me to leave a "comment" in the same way that I have this big text field for an answer. I've flagged this for moderation so I can get some help with that and have referenced the FAQ which talks about buttons that do not appear for me for leaving comments. there is some problem with this new account.