Get namespace of function - r

I'm developing a package where I wish to add an edit history to an object. The package allows other packages to register functions for editing the object. I'm looking for a way to record the version of the package that registered the function that was used for the edit.
The question is: Given a function how do you get the package from where it was exported? My idea is to investigate its search path, but search() only reports the search path for the current environment and thus not for a function, which is what I need.
Any pointers to other approaches is greatly appreciated.
The context for getting the package is this:
registerFunction <- function(fun) {
package <- getPackage(fun) ## This is what I need
version <- getPackageVersion(package)
register(fun, package, version)
}

You can use getAnywhere For example, if you're looking for the namespace for the stringr function str_locate you can do
getAnywhere("str_locate")$where
# [1] "package:stringr" "namespace:stringr"
This will work as long as stringr is "visible on the search path, registered as an S3 method or in a namespace but not exported."
The result is a named list, and you can see what's available from getAnywhere with names
names(getAnywhere("str_locate"))
# [1] "name" "objs" "where" "visible" "dups"

You can use:
environment(fun=someFunctionName)
It will return the environment of the function passed as parameter, specifying also the namespace, i.e. the package name.

Related

Why/how some packages define their functions in nameless environment?

In my code, I needed to check which package the function is defined from (in my case it was exprs(): I needed it from Biobase but it turned out to be overriden by rlang).
From this SO question, I thought I could use simply environmentName(environment(functionname)). But for exprs from Biobase that expression returned empty string:
environmentName(environment(exprs))
# [1] ""
After checking the structure of environment(exprs) I noticed that it has .Generic member which contains package name as an attribute:
environment(exprs)$.Generic
# [1] "exprs"
# attr(,"package")
# [1] "Biobase"
So, for now I made this helper function:
pkgparent <- function(functionObj) {
functionEnv <- environment(functionObj)
envName <- environmentName(functionEnv)
if (envName!="")
return(envName) else
return(attr(functionEnv$.Generic,'package'))
}
It does the job and correctly returns package name for the function if it is loaded, for example:
pkgparent(exprs)
# Error in environment(functionObj) : object 'exprs' not found
library(Biobase)
pkgparent(exprs)
# [1] "Biobase"
library(rlang)
# The following object is masked from ‘package:Biobase’:
# exprs
pkgparent(exprs)
# [1] "rlang"
But I still would like to learn how does it happen that for some packages their functions are defined in "unnamed" environment while others will look like <environment: namespace:packagename>.
What you’re seeing here is part of how S4 method dispatch works. In fact, .Generic is part of the R method dispatch mechanism.
The rlang package is a red herring, by the way: the issue presents itself purely due to Biobase’s use of S4.
But more generally your resolution strategy might fail in other situations, because there are other reasons (albeit rarely) why packages might define functions inside a separate environment. The reason for this is generally to define a closure over some variable.
For example, it’s generally impossible to modify variables defined inside a package at the namespace level, because the namespace gets locked when loaded. There are multiple ways to work around this. A simple way, if a package needs a stateful function, is to define this function inside an environment. For example, you could define a counter function that increases its count on each invocation as follows:
counter = local({
current = 0L
function () {
current <<- current + 1L
current
}
})
local defines an environment in which the function is wrapped.
To cope with this kind of situation, what you should do instead is to iterate over parent environments until you find a namespace environment. But there’s a simpler solution, because R already provides a function to find a namespace environment for a given environment (by performing said iteration):
pkgparent = function (fun) {
nsenv = topenv(environment(fun))
environmentName(nsenv)
}

getting lazy data without attaching package

Background:
I have a CRAN R package which has a dependency on lazy-loaded data in another CRAN package of a specific version. I need to avoid using :: to refer to the data, because it causes CRAN check to fail.
I've read:
Evaluate function within package environment without attaching package
and
See if a variable/function exists in a package?
I've tried (using nycflights13 for this example):
# this works, but I can't use ::
nycflights13::airlines
find("airlines")
# character(0)
get("airlines", envir = asNamespace("nycflights13"), mode = "list")
#Error in get("airlines", envir = asNamespace("nycflights13"), mode = "list") : object 'airlines' of mode 'list' was not found
# attach
library(nycflights13)
get("airlines", envir = asNamespace("nycflights13"), mode = "list")
# works
find("airlines")
# [1] "package:nycflights13"
This may make it even more complicated, but I actually want to refer to an active binding, which returns data which may or may not be available.
What I would like:
A CRAN compatible way of referring to lazy-loaded data in another package without using :: or Imports in DESCRIPTION.
My workaround was to export a getter function for the external package, for which I am also the author. This works because functions are visible, but lazy data and active bindings (which are set, in my case, in .onLoad()) are not.
Another possibility is to use the fact that :: is a command, so something like this is valid R, and with variable naming on the RHS, it would enable flexibility to query presence or absence of data in namespaces (not just environments on the search() path)
`::`(nycflights13, airlines)
:: just substitutes the given symbols for strings, and calls getExportedValue in base.
So, better still, and I think this is my final answer:
base::getExportedValue(asNamespace("nycflights13"), "airlines")
This works without any requireNamespace() or library().

How to find out if I am using a package

My R script has evolved over many months with many additions and subtractions. It is long and rambling and I would like to find out which packages I am actually using in the code so I can start deleting library() references. Is there a way of finding redundant dependencies in my R script?
I saw this question so I tried:
library(mvbutils)
library(MyPackage)
library(dplyr)
foodweb( funs=find.funs( asNamespace( 'EndoMineR')), where=
asNamespace( 'EndoMineR'), prune='filter')
But that really tells me where I am using a function from a package whereas I don't necessarily remember which functions I have used from which package.
I tried packrat but this is looking for projects whereas mine is a directory of scripts I am trying to build into a package.
To do this you first parse your file and then use getAnywhere to check for each terminal token in which namespace it is defined. Compare the result with the searchpath and you will have the answer. I compiled a function that takes a filename as argument and returns the packages which are used in the file. Note that it can only find packages that are loaded when the function is executed, so be sure to load all "candidates" first.
findUsedPackages <- function(sourcefile) {
## get parse tree
parse_data <- getParseData(parse(sourcefile))
## extract terminal tokens
terminal_tokens <- parse_data[parse_data$terminal == TRUE, "text"]
## get loaded packages/namespaces
search_path <- search()
## helper function to find the package a token belongs to
findPackage <- function(token) {
## get info where the token is defined
token_info <- getAnywhere(token)
##return the package the comes first in the search path
token_info$where[which.min(match(token_info$where, search_path))]
}
packages <- lapply(unique(terminal_tokens), findPackage)
##remove elements that do not belong to a loaded namespace
packages <- packages[sapply(packages, length) > 0]
packages <- do.call(c, packages)
packages <- unique(packages)
##do not return base and .GlobalEnv
packages[-which(packages %in% c("package:base", ".GlobalEnv"))]
}

Code in R package: find out *which* package/namespace it is in

Is there a way code in an R package can find out which package or namespace it belongs to?
Background: I find I have common code between packages that just differs in the package name. One common example is tests/testthat.R:
library(testthat)
library(ShiftedExcitation)
test_check("ShiftedExcitation")
If the code could find out to which package or namespace it belongs, I could avoid a number of places where the package name is now given.
Right now I define a hidden variable that contains the package name, say
.PKG <- "ShiftedExcitation"
and then use something along the lines of *
library(testthat)
library(.PKG, character.only = TRUE)
test_check(.PKG)
but I'm curious whether a more elegant solution exists.
* I did not get this working so far as testthat.R is evaluated outside the package namespace. It does work for defining a unittest function inside the package code, though.
Approaching an answer:
#MartinMorgan's hint to use topenv () is quite close. But it turns out that while running unit tests with testthat, testthat is before the package namespace in the search path.
So this is the current state:
.findmyname <- function() {
pkgs <- .packages ()
if (pkgs [1] == "testthat")
pkgs [2]
else
pkgs [1]
}
This function finds the name of the package in question both from within the package and in tests/testthat.R. (Of course, any .findmyname () defined within the package is not known in tests/testthat.R before the library call...)

How to debug unexported functions from required packages?

A function, in a package I am using is giving me not so informative errors. I don't know what is going on. This function is called internally by the function I call. Something like this:
myres <- the.func(x)
the.func <-function(x){
unexported.func(x)
}
How do I debug unexported.func ?
Using debug doesn't work:
>debug(unexported.func)
Error in debug(undexported.func) : object 'unexported.func' not found
Update:
Currently I do nested debug like the following. But I find it inconvenient:
>debug(the.func) # Initiate debugging for the outer function, so I get unexported.func loaded.
>myres <- the.func(x)
Browse[2]>debug(unexported.func) # Now I can call debug with this.
You can access an unexported function via the ::: (triple-colon) operator, prefacing it with the package namespace name (i.e. the package name).
Assuming the pkgA contains the unexported function unexported.func(), we would set the debugging flag on unexported.func() using:
debug(pkgA:::unexported.func)
If you don't know which package (hence namespace) to use for a given unexported function, you can always determine this using getAnywhere().

Resources