开发 R 包,使用"foreach"进行测试,同时使用不同的包版本运行模拟



我在工作中将几乎所有的R代码都写在包中(并使用git(。我大量使用devtools,特别是load_all的快捷方式等,因为我更新了软件包中使用的功能。 我对devtools有一个粗略的了解,因为load_all制作包的临时副本,我真的很喜欢这个用于测试包中函数更新的工作流程。

有没有一种很好的简单方法/工作流程来根据包运行模拟,同时开发它,而不会"破坏"这些模拟?

我怀疑有一个简单的解决方案,但我忽略了。

现在我做的是:

  1. 将包"mypackage"提升到可以运行模拟的地步。 复制包含项目的整个文件夹。 使用新的包名称"mypackage2"在复制的文件夹中运行模拟(。 运行包含library(mypackage2)但不包含library(mypackage)的模拟脚本。这很烦人地意味着我需要将library(mypackage)呼叫更新为library(mypackage2)呼叫。 如果我使用 library(mypackage) 运行模拟并避免使用 library(mypackage2) ,那么我需要确保当前构建的 mypackage 版本是"旧"版本,不会反映 2 中的更新。下面(但下面 2. 也需要重建包! 处理这一切变得混乱。

  2. 当模拟在复制的文件夹中运行时,我可以通过使用 load_all 或重建包来更新"mypackage"中的函数。 我经常需要重建包(即当测试包的更新不是一个可行的解决方案时,使用 load_all 而不重建包(,因为我想测试运行具有 doParallelforeach 等的小型并行模拟的函数(在 Windows 上(,我修改并想要测试的任何函数都需要子进程中最新构建的"mypackage",这些子进程会产生称为"mypackage"的新 R 进程。 我知道当一个包是在 R 中构建的时,它会存储在 ..RR-3.6.1library 中,当将来的 R 会话调用library(mypackage)时,他们将使用该版本的包。

理想情况下,我希望能够做的是,在同一个原始文件夹中,使用 mypackage 版本运行模拟,然后在模拟停止/启动时更新包中的代码,确信我的开发更改不会破坏运行特定版本的包的模拟。

有没有一种简单的方法可以完成上述操作,而无需重新复制文件夹(并制作"mypackage2"之类的东西(?

谢谢

这里描述的问题有点类似于我面临的问题 在foreach中指定包位置

问题是,如果我使用"mypackage"运行一个需要几天时间的模拟,有很多调用foreach,并在测试更改时更新和重建"mypackage",那么来自模拟的未来foreach调用可能会拾取包的新更新版本,这将是一场灾难。

我认为另一个问题的答案确实适用, 但是您需要执行一些额外的步骤。

假设您有一个要测试的包版本。 您仍会为该版本创建特定文件夹,但将其留空。 在这里,我将以/tmp/mypkg2为例。 在 RStudio 中打开项目时,执行:

withr::with_libpaths(c("/tmp/mypkg2", .libPaths()), devtools::install())

这会将该版本的包安装到提供的文件夹中。

然后你可以有一个包装脚本, 说wrapper.R, 像这样:

pkg_path <- commandArgs(trailingOnly = TRUE)[1L]
cat("Using package at", pkg_path, "n")
.libPaths(c(pkg_path, .libPaths()))
library(doParallel)
workers <- makeCluster(detectCores())
registerDoParallel(workers)
# We need to modify the lib path in each worker too
parallel::clusterExport(workers, "pkg_path")
parallel::clusterEvalQ(workers, .libPaths(c(pkg_path, .libPaths())))
# ... Your code calling your package and doing stuff
parallel::stopCluster(workers)

之后,从命令行(R/RStudio 之外(, 您可以键入(假设路径中Rscript(:

Rscript path/to/wrapper.R /tmp/mypkg2

这样,实际的测试代码可以保持不变 (包括拨打library( 而R会在pkg_path自动先搜索, 加载您的特定软件包版本, 然后在标准位置中搜索您可能具有的任何依赖项。

我不完全理解您的用例(至于为什么要这样做(,但是在测试包的两个版本时,我通常会做的是将最新版本推送到我在GitHub中的dev分支,然后使用devtools::load_all()来测试我当前正在做的事情。然后,通过使用 remotes::install_github() 并指定 dev 分支,您可以使用 mypackage::func 运行 GitHub 版本,并使用 func 运行 devtools 版本

最新更新