Use uninstalled packages - r

I'm working in a package (and I'll include more later), and I'm doing a lot of changes and using it, and I'm looking for a method to can load the library without compile it, the lib is written in R.
I think the next structure:
Code
libs/
test_pkg1/
test_pkg2/
more code.R
Where the test_pkg are the dirs with the packages, they are already in the pkg format for R, the wd is set inside "Code", and then add "libs" to the library path in R, but R does not detect it.
I'm trying to use the libs in this both ways:
test_pkg1::func()
test_pkg2::func()
library(test_pkg1)
library(test_pkg2)
for the library, I can use devtools::load_all(path), and works great, but I don't want to mix the env with other funcs, so I need the other way too.
I'm not trying to use both at the same time, but I need both, the most important for this is the :: method.
I tested the libPath from here:
Change R default library path using .libPaths in Rprofile.site fails to work
But I can't do it works...., using that I get the next result:
.libPaths( c( .libPaths(), "./libs") )
test_pkg1::func()
Error in namespaceExport(ns, exports) : undefined exports: func()
Although: Warning message:
In loadNamespace(name) : package ‘test_pkg1’ has no 'package.rds' in Meta/
Note, If I install the package, all works fine, the NAMESPACE file, contains the export functions, in any case, any error there and I should not be able to install and use the libs.
Thx.
Tests from comments:
Try library(pkg, lib.loc)
library("test_pkg1", lib.loc="./libs", verbose=TRUE)
Error in library("test_pkg1", lib.loc = "./libs", verbose = TRUE) :
‘test_pkg1’ is not a valid installed package
Notice, the message is not, there is no package called, the package is detected, but seems, how is not built, I can't load it from library. I try build the package, but don't works either.
Try devtools::dev_mode(on = NULL, path = "libs")
Sadly, this method seems to have the same behavior as the .libsPath method.

Related

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.

How do I edit an R package from GitHub that has already been cloned?

I have an R package, created by someone else that I have been made a collaborator on, that I want to work on and develop. I've already cloned the repository to my local computer through the Create Project > Clone from GitHub route in RStudio, and since then I've been editing the scripts, but not working with it as a package. As in, I had been adding functions and working on a Shiny interface, but not following any R package development rules (loading packages directly into the .R files, not updating the NAMESPACE, using roxygen2 conventions, etc.).
Everything I've read mentions devtools::install_github, but I don't want to install and use it, I want to edit it like I've been doing. I also want it to still be connected to Git (so I can continue to commit and pull from the remote server, once my collaborators make edits). I've tried devtools::load_all() and devtools::document(), but it gives me this warning:
Error in FUN(X[[i]], ...) :
bad restore file magic number (file may be corrupted) -- no data loaded
In addition: Warning messages:
1: In readChar(con, 5L, useBytes = TRUE) :
truncating string with embedded nuls
2: file ‘file_example.rda’ has magic number 'X'
Use of save versions prior to 2 is deprecated
Do I need to delete my local copy and do something different to work with it as a package so that the functionality of roxygen2 and the NAMESPACE documentation will work correctly? Or is there an obvious reason for this error/something I'm missing about how to work with it as a package, how it is currently?
Thanks!
It looks like file_example.rda is corrupt
Can you just load it in R and check what it contains?
You could try:
tools::resaveRdaFiles( 'file_example.rda', compress='xz' )
And see if that saves it in a way that is acceptable?

How to build API documentation for an R package in RStudio?

I'm working on a very recent Windows 10 build, RStudio 1.3.959 and I've just installed the latest MikTex.
I'm trying to put together an R package using RStudio. I can build the package and the Function documentation comments are being converted into /man/*.Rd files. These are then successfully displayed when one executes ?function_name in the RStudio console window.
Unfortunately, I'm having very little luck building the PDF package API documentation (not to be mistaken as the vignette; which I can build). I've looked over a good few tutorials but they all stop short of instructing how one builds the final PDF API document that one expects with every R package.
I've tried:
Build[Windows]->More->Document ... which execute devtools::document(roclets = c('rd', 'collate', 'namespace', 'vignette'))
Build[Windows]->More->Build Source Package ... which executes devtools::document(roclets = c('rd', 'collate', 'namespace', 'vignette')) followed by devtools::build(binary = TRUE, args = c('--preclean'))
Build[Windows]->More->Build Binary Package ... which executes devtools::document(roclets = c('rd', 'collate', 'namespace', 'vignette')) followed by devtools::build(binary = TRUE, args = c('--preclean'))
All three function as expected but still no final package manual pdf file.
Doing some digging on Stack I noticed someone used the command:
devtools::build_manual()
I'm convinced this is what I need. However, when I execute that line of code I get the error:
Converting Rd files to LaTeX ...
Warning in sys2(makeindex, shQuote(idxfile)) : '"makeindex"' not found
Error in texi2dvi(file = file, pdf = TRUE, clean = clean, quiet = quiet, :
unable to run 'makeindex' on 'Rd2.idx'
Warning in sys2(makeindex, shQuote(idxfile)) : '"makeindex"' not found
Error in texi2dvi(file = file, pdf = TRUE, clean = clean, quiet = quiet, :
unable to run 'makeindex' on 'Rd2.idx'
Error in running tools::texi2pdf()
Error: Failed to build manual
Which has left me none the wiser, although it's quite clear that something's a bit upset by the absence of makeindex. Help is much appreciated.
If I understand correctly, you mean the standard reference manual. For example ggplot2 reference manual. In my experience, this is thrown together by CRAN when you submit. All the manual is (as far as I can tell) a collection of things that a well documented package should have, such as a DESCRIPTION file, a NAMESPACE file, and the various .RD files for actual documentation.
Even when looking at the public github for ggplot2 we see that they do not have the manual in their repository. Additionally, there isn't any evidence in their .git*ignore files to suggest they made the manual themselves.
However, if you want to make this yourself devtools::build_manual() is the correct function call.
I was able to make the manual with a preexisting package on github. I would suggest trying to reinstall your devtools package and make sure there are no warnings or errors. It may be helpful to run a session as administrator to insure things get installed correctly.
Good luck!
I am using R version 3.4 with RStudio 1.1.453 on MacOS High Serra.

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.

How to use the parallel package inside another package, using devtools?

When running the following code in an R terminal:
library(parallel)
func <- function(a,b,c) a+b+c
testfun <- function() {
cl <- makeCluster(detectCores(), outfile="parlog.txt")
res <- clusterMap(cl, func, 1:10, 11:20, MoreArgs = list(c=1))
print(res)
stopCluster(cl)
}
testfun()
... it works just fine. However, when I copy the two function definitions into my own package, add a line #' #import parallel, do dev_tools::load_all("mypackage") on the R terminal and then call testfun(), I get an
Error in unserialize(node$con) (from myfile.r#7) :
error reading from connection
where #7 is the line containing the call to clusterMap.
So the exact same code works on the terminal but not inside a package.
If I take a look into parlog.txt, I see the following:
starting worker pid=7204 on localhost:11725 at 13:17:50.784
starting worker pid=4416 on localhost:11725 at 13:17:51.820
starting worker pid=10540 on localhost:11725 at 13:17:52.836
starting worker pid=9028 on localhost:11725 at 13:17:53.849
Error: (converted from warning) namespace 'mypackage' is not available and has been replaced
by .GlobalEnv when processing object ''
Error: (converted from warning) namespace 'mypackage' is not available and has been replaced
by .GlobalEnv when processing object ''
Error: (converted from warning) namespace 'mypackage' is not available and has been replaced
by .GlobalEnv when processing object ''
Error: (converted from warning) namespace 'mypackage' is not available and has been replaced
by .GlobalEnv when processing object ''
What's the root of this problem and how do I resolve it?
Note that I'm doing this with a completely fresh, naked package. (Created by devtools::create.) So no interactions with existing, possibly destructive code.
While writing the question, I actually found the answer and am going to share it here.
The problem here is the combination of the packages devtools and parallel.
Apparently, for some reason, parallel requires the package mypackage to be installed into some local library, even if you do not need to load it in the workers explicitly (e.g. using clusterEvalQ(cl, library(mypackage)) or something similar)!
I was employing the usual devtools workflow, meaning that I was working in dev_mode() all of the time. However, this led to my package being installed just in some special dev mode folders (I do not know exactly how this works internally). These are not searched by the worker processes invoked parallel, since they are not in dev_mode.
So here is my 'workaround':
## turn off dev mode
dev_mode()
## install the package into a 'real' library
install("mypackage")
library(mypackage)
## ... and now the following works:
mypackage:::testfun()
As Hadley just pointed out correctly, another workaround would be to add a line
clusterEvalQ(cl, dev_mode())
right after cluster creation. That way, one can use the dev_mode.

Resources