Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is a reliable process for detaching an R package, in order to upgrade it?

I have written a package that uses devtools to include internal data:

devtools::use_data(.data, internal = T, overwrite = T)

I recently changed that data and rebuilt the package. I want to upgrade that package on another machine that has the older package currently loaded:

detach('package:myPackage', unload=T)
remove.packages('myPackage')
install.packages(repos=NULL, 'myPackage.zip')

I check to see if the changes have gone through:

length(myPackage:::.data[[1]])
[1] 2169

Not what I was expecting... maybe a restart will help?

Restarting R session...
length(myPackage:::.data[[1]])
[1] 2179

Which is the expected result.

Reading the help for detach suggests that it can be flaky under some circumstances, for example:

If you use library on a package whose namespace is loaded, it attaches the exports of the already loaded namespace. So detaching and re-attaching a package may not refresh some or all components of the package, and is inadvisable.

My situation here is that I want to completely purge the loaded package so that I can update it. Is there a way to do this without restarting R?


EDIT 2016/10/28 - updated with a reproducible example below

  • tested on windows
  • requires devtools

...

# setup package in temp dir
pkg_dir <- file.path(tempfile(), 'dummy.test.pkg')
dir.create(pkg_dir, recursive=T)
devtools::create(pkg_dir)
setwd(pkg_dir)

# read description
desc <- readChar('DESCRIPTION', file.size('DESCRIPTION'))

# create and build package v01
.testval <- c(1,2,3)
devtools::use_data(.testval, internal=T, overwrite=T)
v01 <- sub('\\d+\\.\\d+\\.\\d+\\.\\d+', '0.0.0.1', desc, perl=T)
writeChar(v01, 'DESCRIPTION')
bin01 <- devtools::build(binary=T, path='.')

# create and build package v10
.testval <- c(4,5,6)
devtools::use_data(.testval, internal=T, overwrite=T)
v01 <- sub('\\d+\\.\\d+\\.\\d+\\.\\d+', '1.0.0.0', desc, perl=T)
writeChar(v01, 'DESCRIPTION')
devtools::build(binary=T, path='.')
bin10 <- devtools::build(binary=T, path='.')

# up to this point we haven't loaded either package
sessionInfo()

# install v01
install.packages(repos=NULL, bin01)
cat(dummy.test.pkg:::.testval)
# 1 2 3 (as expected)

# unload the package
unloadNamespace('dummy.test.pkg')

# install v10
install.packages(repos=NULL, bin10)
cat(dummy.test.pkg:::.testval)
# 1 2 3 (NOT 4 5 6 which we expected)

### restart R here ###
cat(dummy.test.pkg:::.testval)
# 4 5 6 (as expected)
like image 229
logworthy Avatar asked Feb 03 '16 06:02

logworthy


1 Answers

You are looking for unloadNamespace. I use it for the exact purpose you describe all the time.

Simply call in order:

# this may fail, see below
unloadNamespace("mypackage")
# if it succeeds you're all good

# updating the package
install.packages("mypackage")

# reloading the updated package
library("mypackage")

I never had any problem with that, whether installing from source/binary, from local/CRAN/github, with/without packrat, etc.

EDIT: this does not solve OP's particular problem which is updating the package data. However it works well for most simpler cases, e.g. updating some R code, so I am leaving the answer for future readers.

However, what may happen is that the target package was actually imported by other packages currently loaded. In this case, the unloading fails.

For example, I know this will fail in my current session:

> unloadNamespace("magrittr")
Error in unloadNamespace("magrittr") : 
  namespace ‘magrittr’ is imported by ‘stringr’, ‘customFunctions’, ‘dplyr’, ‘tidyr’ so cannot be unloaded

The solution here is to first unload (with unloadNamespace) all the packages importing "mypackage".

If there is a lot of importing packages, you may actually save time just restarting R. (Since you seem to be talking about a custom local package, this probably won't happen to you unless you have written other packages depending on it.)

like image 113
asachet Avatar answered Nov 29 '22 10:11

asachet