rpackageenvironmentcrancircos

R package - Transferring environment from imported package


Assume an R package (myPackage) that imports the R package RCircos via the DESCRIPTION file and the NAMESPACE file.

$ cat DESCRIPTION
Package: myPackage
Imports: RCircos (>= 1.2.0)
...

$ cat NAMESPACE
import(RCircos)
...

One of the perks of RCircos is that it defines a custom environment (called RCircos.Env) and reads/writes variables to this environment from various of its functions. For example, function RCircos.Initialize.Plot.Parameters reads and writes to this environment.

...
RCircosEnvironment <- NULL;
RCircosEnvironment <- get("RCircos.Env", envir = globalenv());
RCircosEnvironment[["RCircos.PlotPar"]] <- plot.param;

(This peculiar behavior has also been recognized by other R packages; see, for example, lines 247-249 of this package).

Unfortunately, it seems that the environment RCircos.Env is not recognized out of the box in myPackage when I simply import RCircos via the DESCRIPTION file and the NAMESPACE file.

So what can be done?

There seem to be two options of making the environment RCircos.Env accessible to functions like RCircos.Initialize.Plot.Parameters. However, both of these options cause the CRAN check (R CMD check myPackage --as-cran) to issue WARNINGs or NOTEs during the mandatory evaluation of myPackage prior to the submission to CRAN, thus preventing its acceptance on CRAN.

Option 1: I include the following line directly prior to the function demanding the object:

# my code here #
assign("RCircos.Env", RCircos::RCircos.Env, .GlobalEnv)
RCircos.Set.Core.Components(...)
# my code here #

However, the CRAN check highlights this line with a NOTE, thus preventing the acceptance of myPackage on CRAN.

* checking R code for possible problems ... NOTE
Found the following assignments to the global environment:
File ‘PACViR/R/visualizeWithRCircos.R’:
  assign("RCircos.Env", RCircos::RCircos.Env, .GlobalEnv)

Option 2: I load the entire RCircos library prior to the function demanding the object:

# my code here #
library(RCircos)
RCircos.Set.Core.Components(...)
# my code here #

However, the CRAN check highlights this option with a WARNING, again preventing the acceptance of myPackage on CRAN.

* checking dependencies in R code ... WARNING
'library' or 'require' call not declared from: ‘RCircos’
'library' or 'require' call to ‘RCircos’ in package code.
  Please use :: or requireNamespace() instead.
  See section 'Suggested packages' in the 'Writing R Extensions' manual.

Surely, there must be an easy and CRAN-compatible way of making the environment RCircos.Env accessible to functions such as RCircos.Set.Core.Components within myPackage! Can someone name and explain such a way?


Solution

  • Apparently the normal re-export does not work with environments as it does with functions. But this does work:

    RCircos.Env <- RCircos::RCircos.Env
    
    #' test
    #'
    #' @param ... data
    #'
    #' @export
    test_fun <- function(...) {
      RCircos::RCircos.Set.Core.Components(...)
    }
    

    With DESCRIPTION:

    Package: test
    Type: Package
    Title: test
    Description: This is a description.
    Version: 0.1.0
    Authors@R: person("Wouter", "van der Bijl",
                      email = "redacted@redacted.com",
                      role = c("aut", "cre"))
    Maintainer: Wouter van der Bijl <redacted@redacted.com>
    License: GPL-3
    Encoding: UTF-8
    LazyData: true
    Imports: RCircos
    RoxygenNote: 6.1.1
    

    And this NAMESPACE:

    # Generated by roxygen2: do not edit by hand
    
    export(test_fun)
    

    Test with:

    library(test)
    data(UCSC.HG19.Human.CytoBandIdeogram, package = 'RCircos')
    test_fun(UCSC.HG19.Human.CytoBandIdeogram)
    

    Basically, when RCircos runs get("RCircos.Env", envir = globalenv()), it will traverse up the search path until it finds the RCircos.Env from your package instead.

    When running R CMD Check I get 0 errors, 0 warnings, 0 notes.


    Note that this strategy that RCircos uses, with an environment that gets looked up by using get(.., envir = globalenv()) is really unorthodox and generally not a good idea. R functions should generally not have side-effects, such as editing unseen environments. Setting default values etc. is typically done using options(). The whole package is probably not something you'd want to emulate, but at least now you can use it as a dependency.