Find Library Location of Loaded Namespace - r

I'm looking to fetch what would be the lib.loc argument to library or loadNamespace, from a currently loaded namespace.
For attached packages this is relatively straightforward:
path.package("stats") # get library location of loaded stats package
However, for a non-attached loaded namespace, the best I can come up with is:
getNamespace(x)[[".__NAMESPACE__"]][["path"]]
which happens to work on my R version, but has absolutely no guarantee of working in the future. I could also temporarily attach the package to use path.package, but that would potentially trigger attach hooks and I'd prefer to avoid that.
Anyone know of an equivalent to path.package for loaded but not attached namespaces?

You can use find.package :
it returns path to the locations where the given packages are found. If lib.loc is NULL, then loaded namespaces are searched before the libraries.

Related

R devtools: use local dependencies

This bounty has ended. Answers to this question are eligible for a +100 reputation bounty. Bounty grace period ends in 4 hours.
antonio wants to draw more attention to this question:
Explain what is the proper workflow when you are building two packages, where one depends on the other. What is the correct way to run devtools::check() on the depending-on package?
I want to add a local package dependency using R devtools.
The suggested way to add packages to the package DESCRIPTION file is one of the two functions use_package() and use_dev_package(), from the usethis package. The latter adds a dependency on an in-development package. The function help shows the following prototype:
use_dev_package(package, type = "Imports", remote = NULL)
where remote is
a character string to specify the remote, e.g. ‘"gitlab::jimhester/covr"’, using any syntax supported by the remotes package.
The remotes vignette shows the following
# Local
Remotes: local::/pkgs/testthat
So the command should be along these lines:
use_dev_package(foopack, type = "Imports", remote = "local::<foopack>")
However, what should be the path to the foopack. An absolute one or relative to project dir? The root package directory or the R directory with the code, or perhaps the foopack.tar.gz build?
All attempts failed for me.
Needless to say that, beyond having the local dependency properly listed in the DESCRIPTION file, I need it to be seen by the devtools build & check functions.
Edit
As regards use_dev_package(), I found a solution:
if I use devtools::check(), then the dependency appears in the search path, and use_dev_package() does not complain any more (see answer below).
However, it is still unclear to me what arguments should I use to make a development check() for the main package, in particular when the package has a vignette.
Ideally, I should be able to pass the check with local dependencies by passing cran = FALSE, but this still gives
"Package required but not available".
It seems that I have to check the local dependencies before adding them to the description file.
devtools::check("path/to/foopack")
usethis::use_dev_package("foopack", remote ="local::path/to/foopack")
The paths can be relative or absolute, and even a single colon works.
It might be worth noting that, when I build the main package, I can use the ordinary:
devtools::build()
but, for a successful check, I need to use the remote argument:
devtools::check(remote = TRUE)
I can't see a rationale for restating what is in the DESCRIPTION file, but I do not have enough expertise to say it's a bug.
Let's see what the others say in this regard.
Edit
Unfortunately, it seems that the remote argument above does not apply to vignettes. So, if I add a vignette to the package, checks fail with local packages
Until an actual solution is found, all I can do is (sadly) to ignore vignette checks:
devtools::check(remote = TRUE, vignettes = FALSE)

devtools::load_all() side effects: C++-class constructor calling base::system.file fails/ returns empty string

Context
I'm developing (for the first time) an R package using Rcpp which implements an interface to another program (maxima). This package defines a C++ class, whose constructor needs to retrieve the path to an initialization script that gets installed with the package (the in-package path is inst/extdata/maxima-init.mac. The path to this script is then used as a parameter to spawn a child process that runs the program.
In order to retrieve the path to the installed initialization script I'm calling the R function base::system.file from within the C++ class constructor definition:
...
Environment env("package:base");
Function f = env["system.file"];
fs::path p(Rcpp::as<std::string>(f("extdata", "maxima-init.mac", Named("package") = "rmaxima")));
std::string utilsDir = p.parent_path().string();
...
# spawn child process using path in utilsDir
My R/zzz.R creates an object of that class when the packages gets attached:
loadModule("Maxima", TRUE)
.onAttach <- function(libname, pkgname) {
"package:base" %in% search()
maxima <<- new(RMaxima)
}
The Problem
I can install.packages(rmaxima) and library(rmaxima) just fine and the package works as expected.
I now want to increase my development efficiency by using devtools::load_all() to avoid having to R CMD build rmaxima, install.packages(rmaxima) and library(rmaxima) each time I want to test changes. However, when calling devtools::load_all() (or similarily devtools::test() (working directory set to package root) my implementation freezes, because the variable utilsDir is empty and therefore the process launching does not return (I guess it keeps waiting for a valid path). I eventually need to manually kill the process. The same thing happens without setting .onAttach()
Apparently devtools::load_all() does not resemble R's default search path on restart. What can I do? Is this the problem or am I missing something else?
Update
I just came across the following notion of in the devtools::load_all() R documentation file which could be a tip in the right direction
Shim files:
‘load_all’ also inserts shim functions into the imports environment of
the loaded package. It presently adds a replacement version of
‘system.file’ which returns different paths from ‘base::system.file’.
This is needed because installed and uninstalled package sources have
different directory structures. Note that this is not a perfect
replacement for base::system.file.
Also I realized, that devtools::load_all() only temporarily installs my package into, but somehow doesn't the files from my inst/
rcst#Velveeta:~$ ls -1R /tmp/RtmpdnvOQg/devtools_install_ee1e82c780/rmaxima/
/tmp/RtmpdnvOQg/devtools_install_ee1e82c780/rmaxima/:
DESCRIPTION
libs
Meta
NAMESPACE
/tmp/RtmpdnvOQg/devtools_install_ee1e82c780/rmaxima/libs:
rmaxima.so
/tmp/RtmpdnvOQg/devtools_install_ee1e82c780/rmaxima/Meta:
features.rds
package.rds
As it turns out devtools provides a solution to exactly this problem.
In short: calling system.file (i.e. from the global environitment and having the devtools package attached) solves the issue. Specifically the modification:
// Environment env("package:base");
// Function f = env["system.file"];
Function f("system.file");
fs::path p(Rcpp::as<std::string>(f("extdata", "maxima-init.mac", Named("package") = "rmaxima")));
std::string utilsDir = p.parent_path().string();
Explanation
base::system.file(..., mustWork = FALSE) returns an empty string if no match is found. devtools::load_all() temporarily installs the packages inside /tmp/ (on my linux machine). The directory structure of the temporary installation differs from the one of the regular installation, i.e. the one created by install.packages(). In my case, most notably, devtools::load_all() does not copy the inst/ directory, which contains the initialization file.
Now, calling base::system.file("maxima-init.mac", package="rmaxima", mustWork=FALSE) naturally fails, since it searches inside the temporary installation. Having devtools attached masks system.file() with devtools::system.file(), which as mentioned above is "... meant to intercept calls to base::sysem.file() " and behaves differently from base::system.file(). Practically, I think this means, that it will search for the package's source directory instead of the temporary installation.
This way, simply calling system.file() from the global environment calls the right function, either from devtools or base, for either the development or user version of the package automatically.
Nonetheless, using ccache additionally (thanks #dirk) substantially speeds up my development workflow.

Weird issue while testing R package: package `[package name]` found more than once, using the first from [file path]

I'm working on a somewhat complex package (that I unfortunately can't share) that involves a Shiny app, and it an issue has surfaced where I'm getting these warnings when testing:
package [package name] found more than once, using the first from [file path]
In library(testthat) : package ‘testthat’ already present in search()
The first one occurs because I'm using system.file to pull a file in inst that I use for testing.
I've tried to do some debugging with .libPaths and by forcing system.file to go to the .libPaths default with the lib.loc argument, but that doesn't do anything.
I've tried uninstalling the package, which works because then there are not multiple results for find.package.
It seems like testthat adds the current directory to the library paths while it's running, and this creates the issue with system.file and consequently, find.package.
I'm really confused as to what's causing this. I'm combing through the changes I've made and I can't seem to find anything. Any ideas are helpful. I've tried googling this error messages and all that comes up is the source.
The issue here was with changing the option setting for verbose. That caused more output to result from the code, which broke a lot of tests. I hope this helps someone in the future.

Difference between loading and attaching in [R]

In RStudio, when I check and uncheck a package, I see the following commands.
library("ggplot2", lib.loc="~/R/win-library/3.4")
detach("package:ggplot2", unload=TRUE)
Can someone explain what is unload=TRUE does?
Conceptually is there a difference between loading/unloading vs attaching/detaching?
From R's official help pages (see also R Packages - Namespaces):
Anything needed for the functioning of the namespace should be handled at load/unload times by the .onLoad and .onUnload hooks.
For example, DLLs can be loaded (unless done by a useDynLib directive in the ‘NAMESPACE’ file) and initialized in .onLoad and unloaded in .onUnload.
Use .onAttach only for actions that are needed only when the package becomes visible to the user (for example a start-up message) or need to be run after the package environment has been created.
 
attaching and .onAttach
thus means that a package is attached to the user space
aka the global environment
usually this is done via library(pkg)
and you can use normal fun() syntax
 
loading and .onLoad
thus means that package is (in any way) made available to the current R-session
(e.g. by loading/attaching another package that depends on it or by using pkg::fun() syntax the first time)
though you will not find functions in the global environment
you can use pkg::fun()
detach related to package environment(which more related to user)
unload = TRUE related to namespace environment(which more related to other package)
after detach, you can not use any function inside that package directly
but unloadnamespace won't prevent you from calling that function,but the other packages can't use its function directly

Run `devtools::document()` before installing

I've just pushed a package on Github, which I regularly document, test and install on my machine with the following R commands:
library(devtools)
library(testthat)
setwd("bimark")
document() # cheers to roxygen2!
use_testthat() # cheers to testthat!
setwd("..")
install("bimark", build_vignettes=TRUE) # cheers to R-markdown!
library(bimark)
test_package("bimark")
run_examples("bimark")
However, installing it from github with:
install_github("iago-lito/bimark")
does not work since
ERROR: a 'NAMESPACE' file is required
The reason why I do not version my NAMESPACE file is that it is automatically generated by devtools::document().
How can I make the full doc-test-installation easy for my users without versionning non-source files such as NAMESPACE?
NAMESPACE is autogenerated only if devtools::document() and roxygen2 is used. Otherwise, you create it by hand. Therefore, I think they consider it as a source file which needs to be versioned.

Resources