Разработка пакета 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. Пока симуляции выполняются в скопированной папке, я могу обновить функции в "mypackage", либо используя load_all, либо пересобрав пакет. Мне часто нужно пересобирать пакет (т. е. использовать load_all без пересборки пакета, когда тестирование обновлений пакета не является приемлемым решением), потому что я хочу протестировать функции, которые работают небольшие параллельные симуляции с doParallel и foreach и т. д. (в окнах), и любые функции, которые я модифицирую и хочу протестировать, требуют последней сборки «mypackage» в дочерних процессах, которые порождают новые процессы R, вызывающие «mypackage». Я понимаю, что когда пакет создается в R, он сохраняется в ..\R\R-3.6.1\library, и когда будущие сеансы R вызывают library(mypackage), они будут использовать эту версию пакета.

В идеале я хотел бы иметь возможность в той же исходной папке запускать симуляции с версией mypackage, а затем обновлять код в пакете, пока симуляции останавливаются/запускаются, будучи уверенным, что мои изменения разработки не сломаются. симуляции, на которых работает определенная версия пакета.

Есть ли простой способ сделать это без повторного копирования папок (и создания таких вещей, как «mypackage2»)?

Благодарность

Описанная здесь проблема похожа на ту, с которой я столкнулся Укажите расположение пакета в foreach

Проблема в том, что если я запускаю симуляцию, которая занимает несколько дней, используя "mypackage", с большим количеством вызовов foreach, а также обновляю и перестраиваю "mypackage" при тестировании изменений, будущие foreach вызовы из симуляции могут подобрать новую обновленную версию пакета. пакет, что было бы катастрофой.


person Community    schedule 07.08.2019    source источник
comment
Решения в другом вопросе, на который вы ссылались, не работают для вас? Почему?   -  person Alexis    schedule 07.08.2019
comment
@Alexis Ответы на другой вопрос сработали бы, если бы я не пытался разработать пакет одновременно с запуском симуляций (которые могут занять несколько дней, если их прервут). Если я изменяю код пакета и пересобираю, в то время как другие сценарии запускают симуляции (которые вызывают foreach и порождают новые процессы R, которые загружают последнюю версию пакета в папку библиотек), я думаю, что существует риск любого дочернего R процессы в моделировании прерываются, потому что они отражают изменения в пакете.   -  person    schedule 08.08.2019


Ответы (2)


Я думаю, что ответы на другой вопрос применимы, но вам нужно сделать несколько дополнительных шагов.

Допустим, у вас есть версия пакета, которую вы хотите протестировать. Вы все равно создадите определенную папку для этой версии, но оставите ее пустой. Здесь я буду использовать /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, загружая вашу конкретную версию пакета, а затем ища в стандартных расположениях любые зависимости, которые могут у вас быть.

person Alexis    schedule 08.08.2019
comment
@mpirie Обратите внимание, что вам придется настраивать путь к библиотеке каждый раз, когда вы создаете рабочих с помощью makeCluster, поэтому, если функции вашего пакета делают это, им потребуется доступ к pkg_path и, соответственно, какое-то особое обращение, по крайней мере, во время разработки. - person Alexis; 12.08.2019

Я не совсем понимаю ваш вариант использования (почему вы хотите это сделать), но что я обычно делаю при тестировании двух версий пакета, так это помещаю самую последнюю версию в мою ветку dev в GitHub, а затем использую devtools::load_all() для проверить, над чем я сейчас работаю. Затем, используя remotes::install_github() и указав ветку dev, вы можете запустить версию GitHub с mypackage::func и версию devtools с func

person RaphaelS    schedule 07.08.2019
comment
Спасибо за ответ. Что происходит, когда вы хотите использовать, скажем, foreach (с более чем 1 ядром), а код, вызываемый foreach, зависит от обновлений кода вашего пакета? Код в foreach по-прежнему будет использовать последнюю версию пакета сборки R (и не будет отражать никаких изменений, внесенных вами в load_all). Тем временем вы запускаете другие сценарии R, выполнение которых занимает часы/дни, и они зависят от вашей «исходной» версии пакета до ваших последних обновлений. - person ; 07.08.2019
comment
Честно говоря, это конкретный вариант использования, с которым я не знаком, я не могу понять, почему вы используете foreach для тестирования, не можете ли вы повторно запустить load_all? - person RaphaelS; 07.08.2019
comment
В частности, я тестирую функции в mypackage, которые будут вызывать foreach внутри них... внутри вызова foreach будет вызываться только mypackage::func. любые изменения в func не будут отражены внутри этих вызовов foreach. Вот почему я должен собрать пакет при тестировании новой версии пакета. - person ; 07.08.2019