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

Developing R package, testing with `foreach`, while running simulations at same time with different package version

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

是否有一个很好的简单 way/workflow 用于根据包进行 运行 宁模拟,同时开发它,而没有 "breaking" 这些模拟?

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

现在我做的是:

  1. 获取包 "mypackage" 直至为 运行ning 模拟做好准备。复制包含项目的整个文件夹。 运行 复制文件夹中的模拟使用新包名称 "mypackage2")。 运行 个模拟脚本,其中包括 library(mypackage2) 但不包括 library(mypackage)。这令人讨厌地意味着我需要将 library(mypackage) 调用更新为 library(mypackage2) 调用。如果我 运行 使用 library(mypackage) 模拟并避免使用 library(mypackage2),那么我需要确保 mypackage 当前构建的版本是 'old' 版本不反映下面 2. 中的更新(但是下面 2. 也需要重建包!)。处理所有这些变得一团糟。

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

我最想做的是,在同一个原始文件夹中,使用 mypackage 版本进行 运行 模拟,然后在模拟时更新包中的代码stopped/started,相信我的开发更改不会破坏 运行 特定版本包的模拟。

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

谢谢

此处描述的问题与我面临的问题有点相似Specify package location in foreach

问题是,如果我 运行 使用 "mypackage" 需要几天的模拟,多次调用 foreach,并在测试时更新和重建 "mypackage"变化,来自模拟的未来 foreach 调用可能会选择包的新更新版本,这将是一场灾难。

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

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

假设您有一个要测试的包版本。 您仍然会为该版本创建一个特定的文件夹,但将其留空。 这里我以/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 中搜索, 加载您的特定包版本, 然后在标准位置搜索您可能拥有的任何依赖项。