1

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?

Michael Gruenstaeudl
  • 1,609
  • 1
  • 17
  • 31
  • Have you tried exporting the environment? i.e. `@importFrom RCircos RCircos.Env` then `@export` using {roxygen2} – seasmith Jul 03 '19 at 18:27
  • How does one normally get the `RCircos.Env` in the global enviroment when using `RCircos` as a user? `XGR` seems to just call functions like `RCircos.Set.Core.Components()`, never assigning anything to the global environment as far as I can see. – Axeman Jul 03 '19 at 18:46
  • @Axeman @seasmith So, I did a little bit of digging. It seems that environments and their variables are not transferred when you import a package via NAMESPACE. That is why the environment *RCircos.Env* is not recognized in *myPackage*, even though I have `RCircos` as an import for *myPackage* in the DESCRIPTION file. Is that correct? – Michael Gruenstaeudl Jul 04 '19 at 18:47
  • You should be able to access `RCircos::RCircos.Env`, and you can re-export it, as seasmith said. [That's e.g. what `dplyr` does with the `%>%` operator from `magrittr`](https://github.com/tidyverse/dplyr/blob/master/R/utils.r). But that doesn't solve your CRAN issue that you aren't allowed to write to the global environment – Axeman Jul 04 '19 at 18:58
  • @Axeman Then how did RCircos get accepted to CRAN in the first place? (This seems to be a chicken/egg problem.) – Michael Gruenstaeudl Jul 04 '19 at 19:05
  • There is no code in RCircos like you have: `assign("RCircos.Env", RCircos::RCircos.Env, .GlobalEnv)`. So I guess the question is why you need to have that `assign`. – Axeman Jul 04 '19 at 19:08
  • @MichaelGruenstaeudl probably CRAN was less strict when RCircos was first submitted. Regardless, this is very bad behaviour; a package should never meddle with the global environment. – Hong Ooi Jul 04 '19 at 19:10
  • @Axeman A few minutes ago, I updated my question to better explain the underlying issue (see above). In essence, I need the `assign` or equivalent to have the environment *RCircos.Env* recognized in *myPackage*, because simply importing *RCircos* via the DESCRIPTION file and the NAMESPACE file apparently doesn't transfer the environment. – Michael Gruenstaeudl Jul 04 '19 at 19:11

1 Answers1

1

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.

Axeman
  • 32,068
  • 8
  • 81
  • 94
  • 1
    Wow, I take my hat off to you! Your answer did indeed solve the issue. That being said, I still have to include `export(RCircos.Env)` in `NAMESPACE` (as you had suggested in an earlier version of your post) to make my package work. – Michael Gruenstaeudl Jul 04 '19 at 21:57