Renaud Gaujoux
2016-Feb-10 10:40 UTC
[Rd] Method from package dependency is not updated due to lazy load?
Hi, not sure this is a bug or just an unavoidable undesirable side-effect -- or just me that does not do the right thing. Consider the code and output below. It creates 2 packages: * pkgA * pkgB that creates a method for a generic defined in pkgA Changes in a method for the generic in pkgA (after re-installing pkgA) are not reflected in pkgB, unless pkgB is re-installed against the new version of pkgA. I understand this may be linked to lazy-loading, which somehow keeps the old method version. More worrying is the fact that calling pkgA::genericA() in .GlobalEnv still calls the old version. I guess this is due to lazy-load caching the method definition, but is this normal/known behaviour? This means that all the packages that depend on pkgA must be re-installed, even after small internal changes that do not affect the interface or behavior of the exported generic, e.g., internal functions with new required arguments used in the imported generic (which is the error that got me looking into this). Updating reverse-dependencies when installing pkgA could solve the issue (default with message, and optionally disabled). At minimum, a warning when loading pkgB could notify the user that there could be issues due to version discrepancy. Thank you. Bests, Renaud ## Code library(devtools) unlink('test', recursive = TRUE) dir.create('test/lib', recursive = TRUE) # create packages createA <- function(version){ dir.create(file.path('test', version), recursive = TRUE) pdir <- file.path('test', version, 'pkgA') create(pdir, list(Depends = 'methods'), rstudio = FALSE) cat(sprintf(" setGeneric('genericA', function(x) standardGeneric('genericA')) setMethod('genericA', 'missing', function(x) 'A-%s')", version), file file.path(pdir, 'R/function.R')) } createA('v1') createA('v2') # package B imports A create('test/pkgB', list(Imports = 'pkgA', Depends = 'methods'), rstudio FALSE) cat('import(pkgA)', file = 'test/pkgB/NAMESPACE', append = TRUE) cat(" callA <- function() genericA() setGeneric('genericA', package = 'pkgA') setMethod('genericA', 'character', function(x) genericA()) ", file = 'test/pkgB/R/function.R') # install packages install.packages('test/v1/pkgA', lib = 'test/lib', repos = NULL, quiet TRUE) install.packages('test/pkgB', lib = 'test/lib', repos = NULL, quiet = TRUE) # this returns A-v1 system("Rscript -e \"library(pkgA, lib = 'test/lib'); genericA()\"") system("Rscript -e \"library(pkgB, lib = 'test/lib'); callA(); pkgA::genericA()\"") # install pkgA version 2 install.packages('test/v2/pkgA', lib = 'test/lib', repos = NULL, quiet TRUE) # this returns A-v2 system("Rscript -e \"library(pkgA, lib = 'test/lib'); genericA()\"") # this still returns A-v1 system("Rscript -e \"library(pkgB, lib = 'test/lib'); callA(); pkgA::genericA()\"") # re-install pkgB install.packages('test/pkgB', lib = 'test/lib', repos = NULL, quiet = TRUE) # this now returns A-v2 system("Rscript -e \"library(pkgB, lib = 'test/lib'); callA(); pkgA::genericA()\"") ### Output> library(devtools)> unlink('test', recursive = TRUE)> dir.create('test/lib', recursive = TRUE)> # create packages> createA <- function(version){+ dir.create(file.path('test', version), recursive = TRUE)+ pdir <- file.path('test', version, 'pkgA')+ create(pdir, list(Depends = 'methods'), rstudio = FALSE)+ cat(sprintf("+ setGeneric('genericA', function(x) standardGeneric('genericA'))+ setMethod('genericA', 'missing', function(x) 'A-%s')", version), file = file.path(pdir, 'R/function.R'))+ }> createA('v1')Creating package 'pkgA' in '/home/renaud/tmp/r-devel/test/v1'No DESCRIPTION found. Creating with values: Package: pkgA Title: What the Package Does (one line, title case) Version: 0.0.0.9000 Authors at R: person("First", "Last", email = "first.last at example.com", role = c("aut", "cre")) Description: What the package does (one paragraph). Depends: methods License: What license is it under? LazyData: true> createA('v2')Creating package 'pkgA' in '/home/renaud/tmp/r-devel/test/v2' No DESCRIPTION found. Creating with values: Package: pkgA Title: What the Package Does (one line, title case) Version: 0.0.0.9000 Authors at R: person("First", "Last", email = "first.last at example.com", role = c("aut", "cre")) Description: What the package does (one paragraph). Depends: methods License: What license is it under? LazyData: true> # package B imports A> create('test/pkgB', list(Imports = 'pkgA', Depends = 'methods'), rstudio = FALSE)Creating package 'pkgB' in '/home/renaud/tmp/r-devel/test' No DESCRIPTION found. Creating with values: Package: pkgB Title: What the Package Does (one line, title case) Version: 0.0.0.9000 Authors at R: person("First", "Last", email = "first.last at example.com", role = c("aut", "cre")) Description: What the package does (one paragraph). Depends: methods License: What license is it under? LazyData: true Imports: pkgA> cat('import(pkgA)', file = 'test/pkgB/NAMESPACE', append = TRUE)> cat("+ callA <- function() genericA()+ setGeneric('genericA', package = 'pkgA')+ setMethod('genericA', 'character', function(x) genericA())+ ", file 'test/pkgB/R/function.R')> > # install packages> install.packages('test/v1/pkgA', lib = 'test/lib', repos = NULL, quiet = TRUE)> install.packages('test/pkgB', lib = 'test/lib', repos = NULL, quiet = TRUE)> # this returns A-v1> system("Rscript -e \"library(pkgA, lib = 'test/lib'); genericA()\"")Loading required package: methods [1] "A-v1"> system("Rscript -e \"library(pkgB, lib = 'test/lib'); callA(); pkgA::genericA()\"")Loading required package: methods [1] "A-v1" [1] "A-v1"> > # install pkgA version 2> install.packages('test/v2/pkgA', lib = 'test/lib', repos = NULL, quiet = TRUE)> # this returns A-v2> system("Rscript -e \"library(pkgA, lib 'test/lib'); genericA()\"")Loading required package: methods [1] "A-v2"> # this still returns A-v1> system("Rscript -e \"library(pkgB, lib = 'test/lib'); callA(); pkgA::genericA()\"")Loading required package: methods [1] "A-v1" [1] "A-v1"> > # re-install pkgB> install.packages('test/pkgB', lib 'test/lib', repos = NULL, quiet = TRUE)> # this now returns A-v2> system("Rscript -e \"library(pkgB, lib = 'test/lib'); callA(); pkgA::genericA()\"")Loading required package: methods [1] "A-v2" [1] "A-v2" -- Renaud Gaujoux, PhD Systems Immunology - Technion, Haifa, Israel [[alternative HTML version deleted]]
Seemingly Similar Threads
- Namespace/inheritance problem in S4 methods for a union class
- Are downstream dependencies rebuilt when a package is updated on CRAN?
- "False" warning on "replacing previous import" when re-exporting identical object
- S4 NAMESPACE method imports and exports do not include (promoted?) generics
- S4 Generics and NAMESPACE : justified warning ?