Using data.table in package - fail on check - r

I want to use data.tables as a backbone in a package that I wrote.
As I don't want to used :: all the time (and avoid the complications with [ and := operators), I include data.table as a Depends and not as an Import in DESCRIPTION to be able to use all dt functions directly.
If I build the package everything works fine but running a "check" results in the error (from DTTest.Rcheck/00install.out):
* installing *source* package ‘DTTest’ ...
** R
** preparing package for lazy loading
** help
*** installing help indices
** building package indices
** testing if installed package can be loaded
Error : package ‘data.table’ required by ‘DTTest’ could not be found
Error: loading failed
Execution halted
ERROR: loading failed
The only function in this package is this
#' Creates a data.table
#'
#' #return a data.table
#' #export
#'
#' #examples
#' create_dt()
create_dt <- function() {
dt <- data.table(x = 1:10)
dt[, x_2 := x^2]
return(dt[])
}
And DESCRIPTION contains Depends: data.table, otherwise the files are the standard RStudio new package-files.
You can find the whole package here: https://github.com/DavZim/DTTest
Any ideas how to fix this?

After some helpful comments from Roland, I found the solution to my problem. It was indeed related to my .libPaths() and not with the code.
When checking the package R tried to search for the packages inside the first library in .libPaths(). As it happens, I have four paths (/usr/local/..., /usr/lib/R/site-library, /usr/lib/R/library, and /home/user/R/x86_64-pc-linux-gnu-library/3.4) and data.table is installed inside the last one.
The solution (more like a workaround at this stage) was to install data.table in the first one.
To do this, I executed R with admin privileges (sudo R in my case) and installed data.table with install.packages("data.table", lib = .libPaths()[1]).
Now the check pass as expected!

Related

R Package Check(): "All declared Imports should be used"

Starting Situation:
I'm writing a small package of functions for myself only (not CRAN; on GitHub, but not public), and developing locally on the computer. Mostly this is me being a newbie at R and learning to write first package.
I'm using devtools and after load_all() and check(), I have been getting this "NOTE":
-- R CMD check results -------------------------------------------------------------------------------------------- MondelezR 0.1.0 ----
Duration: 21.1s
> checking dependencies in R code ... NOTE
Namespace in Imports field not imported from: 'tibble'
All declared Imports should be used.
0 errors v | 0 warnings v | 1 note x
Question:
Am I doing something wrong or is this a known/ expected problem that I can ignore?
Little more background:
I am using tibble()
In my package, "Find in Files" shows that I have used tibble in four files in different ways:
DESCRIPTION file:
[First Section of File Omitted]
Encoding: UTF-8
RoxygenNote: 7.2.0
Imports:
stringr,
dplyr,
purrr,
tibble,
magrittr
Suggests:
testthat (>= 3.0.0)
Config/testthat/edition: 3
(I have not seen the message for the other imported packages.)
FUNCTION: mdlz_otm_filter.R
[omitted]
#' #examples
#' df_otm_final <- tibble::tibble(
[omitted]
I am only using tibble in the example, not in the function itself, and the relevant portion is shown above.
DOCUMENTATION: mdlz_otm_filter.Rd
The roxygen2 documentation created from the above function shows the exact same example, but as documentation.
TEST THAT: test-mdlz_make_KEY1.R
test_that("POSTAL LANE2 works as expected", {
df_test <- tibble::tibble(ORIG_ZIP = c("18615", "12345", "a5J 1u8"),
DEST_ZIP = c("1234", "23456", "i9y2b4"),
FINAL_KEY = c("18615-01234","12345-23456","A5J1U8-I9Y2B4"))
expect_identical(mdlz_make_POSTAL_LANE(df_test$ORIG_ZIP,
df_test$DEST_ZIP),
df_test$FINAL_KEY)
})
Attempt to remove tibble from DESCRIPTION
I tried removing tibble from Imports: on the DESCRIPTION file, but as I expected would happen, I got this instead:
-- R CMD check results -------------------------------------------------------------------------------------------- MondelezR 0.1.0 ----
Duration: 26.6s
> checking for unstated dependencies in examples ... WARNING
'::' or ':::' import not declared from: 'tibble'
> checking for unstated dependencies in 'tests' ... WARNING
'::' or ':::' import not declared from: 'tibble'
0 errors v | 2 warnings x | 0 notes v
So... warnings are worse than notes I figure.
Research:
Google search to start with brought me to these posts:
RStudio Community Meta-Package This guy's problem is that he needs to use functions in every package he's trying to put in his meta-package. My issue is I'm already using tibble and getting the note regardless.
SO devtools R CMD check NOTE But this one doesn't seem to apply because I AM using tibble in my package, and this guy is trying to remove it.
Help?
I don't know how to clear the note, if I should worry about it at all, or why I'm getting it since I am using tibble as shown above. Trying to learn, so an expository answer is appreciated. Thank you in advance.
It seems devtools check function is looking for an importFrom tag with the package tibble in some of your function documentation roxygen Docs.
Adding #importFrom tibble tibble to the functions documentation which use the library tibble might remove the note.

What's the preferred means for defining an S3 method in an R package without introducing a dependency?

I have an R package (not currently on CRAN) which defines a couple of S3 methods of generic functions from other packages (specifically knitr::knit_print and huxtable::as_huxtable). However, they're not a key part of my package, so I'd prefer not to create a dependency on those packages when a user installs my package. Up until R 4.0.0, I exported the S3 methods without importing the generics. Using roxygen2, my #export directive was translated into an export() directive in NAMESPACE rather than S3method(). This worked fine in R versions < 4.0.0 because R looks in the global environment for a matching generic_function.class method first rather than relying on proper registration of the S3 method. However, as per this blog on developer.r-project.org, R no longer looks for non-registered S3 methods.
What is the best way round this? For now, I've added #importFrom directives to my roxygen2 blocks and have added both packages to the imports section of DESCRIPTION. However, as I understand things this will mean any user installing my package will then also have to install knitr and huxtable whether they want to or not.
Fortunately, for R >= 3.6.0, you don't even need the answer by caldwellst. From the blog entry you linked above:
Since R 3.6.0, S3method() directives in NAMESPACE can also be used to perform delayed S3 method registration. With S3method(PKG::GEN, CLS, FUN) function FUN will get registered as an S3 method for class CLS and generic GEN from package PKG only when the namespace of PKG is loaded. This can be employed to deal with situations where the method is not “immediately” needed, and having to pre-load the namespace of pkg (and all its strong dependencies) in order to perform immediate registration is considered too “costly”.
Additionally, this is also discussed in the docs for the other suggestion of vctrs::s3_register():
#' For R 3.5.0 and later, `s3_register()` is also useful when demonstrating
#' class creation in a vignette, since method lookup no longer always involves
#' the lexical scope. For R 3.6.0 and later, you can achieve a similar effect
#' by using "delayed method registration", i.e. placing the following in your
#' `NAMESPACE` file:
#'
#' ```
#' if (getRversion() >= "3.6.0") {
#' S3method(package::generic, class)
#' }
So, you would simply need to not use #importFrom and instead of #export, use #exportS3Method package::generic (See https://github.com/r-lib/roxygen2/issues/796 and https://github.com/r-lib/roxygen2/commit/843432ddc05bc2dabc9b5b22c1ae7de507a00508)
Illustration
So, to illustrate, we can make two very simple packages, foo and bar. The package foo just has a generic foo() function and default method:
library(devtools)
create_package("foo")
#' foo generic
#'
#' #param x An object
#' #param ... Arguments passed to or from other methods
#' #export
foo <- function(x, ...) {
UseMethod("foo", x)
}
#' foo default method
#'
#' #param x An object
#' #param ... Arguments passed to or from other methods
#' #export
foo.default <- function(x, ...) {
print("Called default method for foo.")
}
After document() and install()ing, we create bar:
create_package("bar")
which creates a bar method for foo():
#' bar method for foo
#'
#' #param x A bar object
#' #param ... Arguments passed to or from other methods
#'
#' #exportS3Method foo::foo
foo.bar <- function(x, ...) {
print("Called bar method for foo.")
}
Importantly, we must load the foo package before running document(), or #exportS3Method won't work. That is,
library(foo)
document()
But, if we do that, we get the following in the NAMESPACE for bar:
# Generated by roxygen2: do not edit by hand
S3method(foo::foo,bar)
We have to manually add foo to "Suggests" in DESCRIPTION.
Then if we uninstall foo, we can still install bar:
> remove.packages("foo")
Removing package from ‘/home/duckmayr/R/x86_64-pc-linux-gnu-library/4.0’
(as ‘lib’ is unspecified)
> install("bar")
✓ checking for file ‘/home/jb/bar/DESCRIPTION’ ...
─ preparing ‘bar’:
✓ checking DESCRIPTION meta-information ...
─ checking for LF line-endings in source and make files and shell scripts
─ checking for empty or unneeded directories
─ building ‘bar_0.0.0.9000.tar.gz’
Running /opt/R/4.0.0/lib/R/bin/R CMD INSTALL \
/tmp/Rtmp5Xgwqf/bar_0.0.0.9000.tar.gz --install-tests
* installing to library ‘/home/jb/R/x86_64-pc-linux-gnu-library/4.0’
* installing *source* package ‘bar’ ...
** using staged installation
** R
** byte-compile and prepare package for lazy loading
** help
*** installing help indices
** building package indices
** testing if installed package can be loaded from temporary location
** testing if installed package can be loaded from final location
** testing if installed package keeps a record of temporary installation path
* DONE (bar)
The vctrs package provides a function called s3_register that dynamically registers methods for use in the .onLoad function. You can read more about its use here, for yourself you would want:
.onLoad <- function(...) {
if (requireNamespace("knitr", quietly = TRUE)) {
vctrs::s3_register("knitr::knit_print", "class_name")
}
if (requireNamespace("huxtable", quietly = TRUE)) {
vctrs::s3_register("huxtable::as_huxtable", "class_name")
}
}
The documentation is kind as well so you don't have to import vctrs:
To avoid taking a dependency on vctrs for this one function, please feel free to copy and paste the function source into your own package.

R - How Do I Force Installation of My Custom Package to Fail When Imported Package Version is Too Old?

I've been working on a custom R library at work. I use functions from a couple different packages (always qualified with ::), so I've added them to the Imports section of my DESCRIPTION file. When I use R CMD INSTALL to install my package, I get a warning if the version of an imported package is too old, but installation continues. How do I force it to fail and alert the user that they need to update that package? I don't want to add any of them to the Depends section because I don't want those extra packages loaded when my library is loaded.
Example DESCRIPTION file:
Depends:
R (>= 3.1.2)
Imports:
dplyr (>= 0.7.0)
If dplyr 0.5.0 is loaded on the user's system, installation continues, but certain functions that depend on dplyr 0.7.0 will fail when called.
Here is a possible solution using find.package, packageDescription and packageVersion:
.onLoad <- function(libname, pkgname) {
myImports <- strsplit(utils::packageDescription(pkgname)[["Imports"]], split = ",\\s")[[1]]
if (length(find.package("dplyr", quiet = TRUE)) > 0) {
reqVers <- grep("^dplyr [(]", myImports, value = TRUE)
reqVers <- sub("^dplyr [(]>= ([0-9]+.*[0-9]+).*", "\\1", reqVers)
if (check <- utils::packageVersion("dplyr") < reqVers)
stop("Dplyr is version ", utils::packageVersion("dplyr"), " --- this package requires version ", reqVers, " at least")
}
invisible()
}
Like you say in the comment, common practice is to put this into a file called zzz.R.
Of course you could also replace the stop with a warning.

Error use other library when I use Rstudio and Roxygen2 to build a package

To simplify the problem. I tried the following thing. My goal is to build a simple package which need another library.
I used RStudio and tried to create a new package, and checked the project option to "Generate document with Roxygen". And I get the following code:
#' Title just a test
#'
#' #return nothing
#' #export
#'
#' #examples
#' hello()
hello <- function() {
print("Hello, world!")
}
and I "check"ed it and "build and reload"ed it by the RStudio, all is OK.
Then I tried to add one line in the head of the code:
library("data.table")
#' Title just a test
#'
#' #return nothing
#' #export
#'
#' #examples
#' hello()
hello <- function() {
print("Hello, world!")
}
Then I failed amd get the following:
* checking whether package 'kanpu.temp' can be installed ... ERROR
Installation failed."
When I check the log, it says that:
* installing *source* package 'kanpu.temp' ...
** R
** preparing package for lazy loading
Error in library("data.table") : there is no package called 'data.table'
Error : unable to load R code in package 'kanpu.temp'
ERROR: lazy loading failed for package 'kanpu.temp'
* removing 'D:/onedrive/program/R/kanpu.temp.Rcheck/kanpu.temp'
I am sure that data.table is a existed package in my RStudio System. and also tried other package like "ggplot2", "plyr", and get the same result.
So how can I resolve this problem?
The envirement is:
Win7 64
RStudio 0.99.473
R 3.1.3 64
After checking the "Writing R Extensions", I know what's wrong with the code.
I should use "Import" or "Depends" in the "DESCRIPTION" file.
Looking at the error message, it seems that you do not have the ggplot2 package installed. This will cause an error when R reaches the line library(ggplot2).
The solution is to install that package:
install.packages("ggplot2")
However, you probably shouldn't be calling library in your packaged code. A package should make as few changes to the external environment as possible.
Instead, mark the package as required in your DESCRIPTION and make fully qualified function calls: SomePackage::someFunction().
See Hadley's pages for further information.

Why does using "<<-" in a function in the global workspace work, but not in a package?

I'm creating a package using devtools and roxygen2 (in RStudio), however after I've built the package my function no longer works as intended. Yet, if I load the function's .R file and run the function from there in RStudio, it works perfectly. I've created another package using this method before and it worked fine (13 functions all working as intended from my other package), yet I cant seem to get this new one to work.
To start creating the package I start with:
library("devtools")
devtools::install_github("klutometis/roxygen")
library(roxygen2)
setwd("my parent directory")
create("triale")
All is working fine so far. So I put my .R file containing my function in the R folder under the triale folder. The .R file looks like this:
#' Trial Z Function
#'
#' This function counts the values in the columns
#' #param x is the number
#' #keywords x
#' #export
#' #examples
#' trialz()
trialz = function(x) {w_id= c(25,x,25,25,25,1,1,1,1,1);
wcenter= c(rep("BYSTAR-1",10));
df1 <<- data.frame(w_id, wcenter);
countit <<- data.table(df1);
view <<- countit[, .N, by = list(w_id, wcenter)];
View(view)}
Again if I were to just run the code from the .R file, and test the function it works fine. But to continue, next I enter:
setwd("./triale")
document()
The triale documentation is updated, triale is loaded, and the NAMESPACE and trialz.Rd are both written so that trialz.Rd is under the man folder, and NAMESPACE is under the triale folder as intended. Next I install triale:
setwd("..")
install("triale")
Which I know works because I get the following:
Installing triale
"C:/PROGRA~1/R/R-31~1.3/bin/x64/R" --vanilla CMD INSTALL \
"C:/Users/grice/Documents/R/triale" \
--library="C:/Users/grice/Documents/R/win-library/3.1" --install-tests
* installing *source* package 'triale' ...
** R
** preparing package for lazy loading
** help
*** installing help indices
** building package indices
** testing if installed package can be loaded
*** arch - i386
*** arch - x64
* DONE (triale)
Reloading installed triale
Package is now built, so I do the following:
library("triale")
library("data.table")
Note whenever I load the package data.table I get the following error message:
data.table 1.9.4 For help type: ?data.table
*** NB: by=.EACHI is now explicit. See README to restore previous behaviour.
However it doesnt seem to affect my function. So now its time to test my function from my package:
trialz(25)
This goes through, and I of course get a populated df1, and countit, but for whatever reason view is always empty (as in 0 obs. of 0 variables).
So I test my work using the dummy code below:
>trialy = function(x) {wid= c(25,x,25,25,25,1,1,1,1,1);
wc= c(rep("BYSTAR-1",10));
df2 <<- data.frame(wid, wc);
countitt <<- data.table(df2);
viewer <<- countitt[, .N, by = list(wid, wc)];
View(viewer)}
>trialy(25)
Even though this is the same exact code with just the names changed around it works. Dumbfounded I open trialz.R and copy the function from there and run it as below, and that works:
> trialz = function(x) {w_id= c(25,x,25,25,25,1,1,1,1,1);
wcenter= c(rep("BYSTAR-1",10));
df1 <<- data.frame(w_id, wcenter);
countit <<- data.table(df1);
view <<- countit[, .N, by = list(w_id, wcenter)];
View(view)}
> trialz(25)
Since I've created a package before I know my method is solid (that package had 13 dif. functions, all of which worked). I just don't understand how a function can work fine as written, yet when I package it, the function no longer works.
Again here is where it stops working as intended when using my package:
view <<- countit[, .N, by = list(w_id, wcenter)];
View(view)}
And my end result should look something like this, if my package worked:
wid wc N
1 25 BYSTAR-1 5
2 1 BYSTAR-1 5
Can anyone explain why view is never populated after I package my function? I've tested it as much as I know how, and my results should be reproducible for anyone thats willing to try it for themselves.
Thanks, I appreciate any feedback.
Your problem here is that "<<-" does not create variables in the global environment but rather in the parent environment. (See help("<<-").)
The parent environment of a function is the environment in which it has been defined. In the case where you defined your function directly in your workspace, this parent environment actually is the same as your workspace environment (namely: .GlobalEnv), which is why your variables are assigned values as you expect them to. In the case where your function is packaged, however, the parent environment is the package environment and not the .GlobalEnv! This is why you do not see your variables being assigned values in your workspace.
Refer to the chapter on environments in Hadley's book and How R Searches and Finds Stuff for more details on environments in R.
Note that doing this would not be considered a proper debugging technique, to say the least. In general, you never want to use the "<<-" operator.
For options on debugging R code, see, e.g., this question. I, in particular, like the debugonce function very well. See ?debugonce.
I forgot one important part when editing my description file in that I for got to add
Imports: data.table
Also the NAMESPACE file needed to include the data.table package as an import as well, like so:
import(data.table)
export(Z)
export(AS) .... etc.
Doing this ensures that whenever a function within your package uses a function from another package, that (second) package is called up before your code is executed.

Resources