Skip to content

[Bioc-devel] NAMESPACE question

14 messages · Michael Lawrence, Martin Morgan, Dario Strbenac +2 more

#
On 10/05/2014 01:39 PM, Robert Castelo wrote:
There are two 'as.vector' generics, one defined in Matrix and one in 
BiocGenerics (and made available via IRanges). These generics have different methods

 > showMethods(Matrix::as.vector)
Function: as.vector (package base)
x="abIndex", mode="ANY"
x="abIndex", mode="character"
x="ANY", mode="ANY"
x="dgCMatrix", mode="missing"
x="dgeMatrix", mode="missing"
x="diagonalMatrix", mode="missing"
x="dsCMatrix", mode="missing"
x="ldenseMatrix", mode="missing"
x="Matrix", mode="missing"
x="ndenseMatrix", mode="missing"
x="sparseVector", mode="character"
x="sparseVector", mode="missing"

 > showMethods(BiocGenerics::as.vector)
Function: as.vector (package BiocGenerics)
x="ANY"
x="AtomicList"
x="Rle"
x="XDouble"
x="XInteger"
x="XRaw"
x="XString"
x="XStringSet"

so it's important that your code clearly distinguish between generics. One 
possibility is to remove importMethodsFrom(IRanges, as.vector) from the 
NAMESPACE, and explicitly use IRanges::as.vector(...) in your code.

codetoolsBioC::writeNamespaceImports("qpgraph") might provide you with some 
guidance (it's not 100% reliable; available via svn at 
https://hedgehog.fhcrc.org/bioconductor/trunk/madman/Rpacks/codetoolsBioC) about 
what functionality is being imported.

Martin

  
    
#
hi Martin,
On 10/06/2014 07:24 PM, Martin Morgan wrote:
[...]
ok, i've done this as it is the easiest at the moment to meet the 
release schedule. i guess that in the future i should try to avoid using 
the '::' operator by importing exclusively what is needed from each package.
thanks for the heads up about codetoolsBioC, i've tried it out and seen 
that some of the suggested imports are not necessary but some others i 
was really missing them (which makes me wonder how was it possible that 
he package did not break at those points).

one further question related to NAMESPACE. i subset GRanges objects in 
the package via the '[' operator, i've included this into the NAMESPACE 
file as:

importMethodsFrom(GenomicRanges,
                   c, cbind, rbind,
                   "mcols<-", start, end, strand, sort,
                   "[", "[<-", "[[", "[[<-", "$", "$<-")

however, when the package reaches a subset operation x[i] with x being a 
GRanges object, an entire package loading sequence starts:

Loading required package: GenomicRanges
Loading required package: BiocGenerics
Loading required package: parallel

Attaching package: ?BiocGenerics?
[... etc ...]

which may look a bit odd to the user. for every other imported method 
the package uses them silently without loading the corresponding 
package, am i importing '[' for GRanges objects from the wrong package? 
is there a way to import '[' so that my package can use it without 
triggering that package loading sequence?


thanks again!
robert.
#
Does that happen with the other methods or just "["? As a last resort, you
could just drop the import (because "[" is a primitive, it should just
work).

On Tue, Oct 7, 2014 at 3:08 AM, Robert Castelo <robert.castelo at upf.edu>
wrote:

  
  
#
hi, it happens only with "[", that's why i'm puzzled.

it behaves as if you load a GRanges object 'x' and try to subset it

x[1]

without loading 'GenomicRanges' first.

robert.
On 10/07/2014 05:05 PM, Michael Lawrence wrote:

  
    
#
On 10/07/2014 08:15 AM, Robert Castelo wrote:
Is there a reproducible example? I see in your code there are several places 
where you require() or library() various packages. I think one of these 
Depends: on GenomicRanges, and the messages you see are the effect of moving 
GenomicRanges from 'loaded' to 'attached'. You can see the effect with

   library(qpgraph)
   sessionInfo()           ## GenomicRanges loaded but not attached
   library(GenomicRanges)  ## information about the package being attached

Probably in your code you do not actually want to require() ad hoc packages and 
influence the user search path (and implicitly rely on search path order for 
correct functionality), but rather to requireNamespace("foo"); foo::fun(...) (or 
possibly loadNamespace()).

Complicated!

Martin

  
    
#
On Tue, Oct 7, 2014 at 8:54 AM, Martin Morgan <mtmorgan at fhcrc.org> wrote:

            
This last paragraph should probably be explained in the Bioc coding
standards if it is not already.

  
  
#
On 10/07/2014 09:15 AM, Michael Lawrence wrote:
Thanks for the prompt, it's now mentioned on the coding style and package 
guidelines.

   http://bioconductor.org/developers/package-guidelines/#dependencies
   http://bioconductor.org/developers/how-to/coding-style/

Martin
#
The guidelines state :

Depends: is appropriate when a package is used in the example section of a man page.

I think such packages should be in Suggests. In the example, the package should be loaded by :

if(require(examplePackage))
{
  exampleFunction(data)
}

--------------------------------------
Dario Strbenac
PhD Student
University of Sydney
Camperdown NSW 2050
Australia
#
I think the intent there is that if you virtually always need a package to
generate the input or analyze the output of a documented function, it
should be in Depends. If it's a package that is only useful for
demonstration, it should be in Suggests, and one should abide by the same
guidelines (requireNamespace, etc) as Martin contributed.

On Tue, Oct 7, 2014 at 6:00 PM, Dario Strbenac <dstr7320 at uni.sydney.edu.au>
wrote:

  
  
#
On 10/07/2014 07:05 PM, Michael Lawrence wrote:
I adjusted the wording a bit. I was also quite disturbed to find how similar my 
Suggests illustration is to the advice in Writing R Extensions, 
RShowDoc('R-exts'), section 1.1.3.1.

Martin

  
    
1 day later
#
hi Martin,

thanks for your recommendations regarding the conditional loading of 
packages. I think however, that they are not related to the problem I'm 
referring. Let me put here a reproducible example which works with 
qpgraph version 0.99.7 that I have just pushed to svn:

library(qtl)
library(qpgraph)

map <- sim.map(len=100, n.mar=10, anchor.tel=FALSE, eq.spacing=TRUE, 
include.x=FALSE)

eqtlcross <- eQTLcross(map)
eqtlcross <- addGenes(eqtlcross, 5)
eqtlcross <- addeQTL(eqtlcross, "g1", location=map[[1]][1])

sim.eqtl <- reQTLcross(eqtlcross, rho=0.5, a=1)
cross <- sim.cross(map, sim.eqtl, n.ind=100)

gstarts <-runif(5, min=range(map[[1]])[1], max=range(map[[1]])[2])

annot <- data.frame(chr=rep(names(map)[1], 5),
                     start=gstarts, end=gstarts+1,
                     strand=rep("+", 5),
                     row.names=sim.eqtl$model$Y,
                     stringsAsFactors=FALSE)

## the following is the method that triggers the
## unexpected behavior. Its last but one instruction
## in line 208 of file qpgraph/R/eQTLnetworkEstimationParam-methods.R
## is the following:
##
## geneAnnotation <- geneAnnotation[genes]
##
## and should be using the method "[" imported from GenomicRanges
## however it starts loading a number of packages to do the job

param <- eQTLnetworkEstimationParam(cross, geneAnnotation=annot, 
genome="simulatedGenome")
Loading required package: parallel

Attaching package: ?BiocGenerics?

The following objects are masked from ?package:parallel?:

[...etc...]

sessionInfo()
R version 3.1.0 (2014-04-10)
Platform: x86_64-unknown-linux-gnu (64-bit)

locale:
  [1] LC_CTYPE=en_US.UTF8       LC_NUMERIC=C 
LC_TIME=en_US.UTF8        LC_COLLATE=en_US.UTF8
  [5] LC_MONETARY=en_US.UTF8    LC_MESSAGES=en_US.UTF8 
LC_PAPER=en_US.UTF8       LC_NAME=C
  [9] LC_ADDRESS=C              LC_TELEPHONE=C 
LC_MEASUREMENT=en_US.UTF8 LC_IDENTIFICATION=C

attached base packages:
[1] stats4    parallel  stats     graphics  grDevices utils     datasets 
  methods   base

other attached packages:
[1] IRanges_1.99.28     S4Vectors_0.2.4     BiocGenerics_0.11.5 
qpgraph_1.99.7      qtl_1.33-7
[6] vimcom_0.9-93       setwidth_1.0-3      colorout_1.0-2

loaded via a namespace (and not attached):
  [1] annotate_1.43.5          AnnotationDbi_1.27.16    base64enc_0.1-2 
          BatchJobs_1.4
  [5] BBmisc_1.7               Biobase_2.25.0 
BiocParallel_0.99.22     biomaRt_2.21.1
  [9] Biostrings_2.33.14       bitops_1.0-6             brew_1.0-6 
          checkmate_1.4
[13] codetools_0.2-9          DBI_0.3.1                digest_0.6.4 
         fail_1.2
[17] foreach_1.4.2            futile.logger_1.3.7 
futile.options_1.0.0     GenomeInfoDb_1.1.23
[21] GenomicAlignments_1.1.30 GenomicFeatures_1.17.19 
GenomicRanges_1.17.42    graph_1.43.0
[25] grid_3.1.0               iterators_1.0.7          lambda.r_1.1.6 
         lattice_0.20-29
[29] Matrix_1.1-4             mvtnorm_1.0-0            RCurl_1.95-4.3 
         Rgraphviz_2.9.1
[33] Rsamtools_1.17.34        RSQLite_0.11.4 
rtracklayer_1.25.17      sendmailR_1.2-1
[37] stringr_0.6.2            tools_3.1.0              XML_3.98-1.1 
         xtable_1.7-4
[41] XVector_0.5.8            zlibbioc_1.11.1


cheers,
robert.
On 10/07/2014 05:54 PM, Martin Morgan wrote:

  
    
#
On 10/09/2014 08:00 AM, Robert Castelo wrote:
Hmm, I see that the parallel, BiocGenerics, and stats4 packages are being 
attached. In a new R session I did this:

 > trace(loadNamespace, tracer=recover)
Tracing function "loadNamespace" in package "base"
[1] "loadNamespace"
 > param <- eQTLnetworkEstimationParam(cross, geneAnnotation=annot, 
genome="simulatedGenome")
Loading required package: parallel
Tracing loadNamespace(package, c(which.lib.loc, lib.loc)) on entry

Enter a frame number, or 0 to exit

  1: eQTLnetworkEstimationParam(cross, geneAnnotation = annot, genome = "simulat
  2: geneAnnotation[genes]
  3: geneAnnotation[genes]
  4: extractROWS(x, i)
  5: extractROWS(x, i)
  6: extractROWS(seqnames(x), i)
  7: extractROWS(seqnames(x), i)
  8: suppressWarnings(require(IRanges, quietly = TRUE))
  9: withCallingHandlers(expr, warning = function(w) invokeRestart("muffleWarnin
10: require(IRanges, quietly = TRUE)
...

and it's likely from

./S4Vectors/R/Rle-class.R:        if (!suppressWarnings(require(IRanges, 
quietly=TRUE)))
./S4Vectors/R/Rle-class.R:        if (!suppressWarnings(require(IRanges, 
quietly=TRUE)))

could be addressed with suppressPackageStartupMessages() (less-preferred) or 
requireNamespace("IRanges") followed by IRanges::...; let's see if we can get 
that fixed...

Martin

  
    
#
Hi Robert, Martin,

Yes using requireNamespace() internally is much cleaner than using
require(). Sorry for that. Just made the change in S4Vectors 0.2.6.
FYI the need to load IRanges namespace in a couple of places
inside S4Vectors is temporary and will go away soon.

Cheers,
H.
On 10/09/2014 09:33 AM, Martin Morgan wrote:

  
    
#
Martin, Herv?,

this is great! thanks for nailing this one down. it wasn't anything 
critical to my package but it was making me feel unsure about how 
namespaces work, and moreover, i've learned the use of 
'requireNamespace()' !!

cheers,
robert.
On 10/09/2014 09:40 PM, Herv? Pag?s wrote: