【问题标题】:R: Sys.getenv in package startup code always returns emptyR:包启动代码中的 Sys.getenv 总是返回空
【发布时间】:2022-02-03 04:13:25
【问题描述】:

所以我想我有点知道这里发生了什么,但我很难找到参考(在 SO 或 R 文档中),所以我想把它说出来,看看人们是否可以阐明.

我有一个 R 包,在 utils.R 文件的顶层(不在任何函数内)包含以下代码:

S3_BUCKET <- Sys.getenv('S3_BUCKET')
CACHE_DIR <- if (S3_BUCKET == "") {
  'cache/foo'
} else {
  paste0('s3://', S3_BUCKET, '/dir/cache/foo')
}
print(paste("CACHE_DIR:", CACHE_DIR))

当我通过devtools::load_all('.') 加载包时,这在“开发模式”下工作正常,但是当我在我的环境中安装包并通过library(mypkg) 加载它时,此代码中的Sys.getenv('S3_BUCKET') 总是返回空字符串(已通过检查mypkg:::S3_BUCKET 验证)。

我的假设是在包加载期间评估“包级代码”时尚未设置环境变量。如果是这样 - 这是否记录在任何地方,如果没有,将其添加到文档的正确位置在哪里?还是应该修复的错误?

看起来stdout 可能还没有设置(对于包?),因为print 输出似乎永远不会出现。

我要采用的解决方案是将其转换为 .onLoad 回调,我确信这是更好的做法:

GLOBALS <- new.env()
GLOBALS$CACHE_DIR <- 'cache/foo'

.onLoad <- function(libname, pkgname) {
  S3_BUCKET <- Sys.getenv('S3_BUCKET')
  if (S3_BUCKET != "") {
    assign('CACHE_DIR', paste0('s3://', S3_BUCKET, '/dir/cache/foo'), GLOBALS)
    print(paste("CACHE_DIR:", CACHE_DIR))
  }
}

这按预期工作。

【问题讨论】:

  • @MikaelJagan 这比我想象的更令人惊讶。事实上,我的队友提出了这个建议,但我立即将其驳回。 =) 是否在任何地方记录了顶级代码的时间安排?
  • 我将我的评论迁移到了一个答案中 - 如果我无意中让事情变得不太清楚,请告诉我......

标签: r package environment-variables startup


【解决方案1】:

如果Sys.getenv 调用位于顶层,则不会在每次加载包命名空间时运行。它只运行一次:当 CRAN 或您通过 R CMD INSTALL 从包的源代码构建二进制文件时。如果你安装你的包

$ env S3_BUCKET=whatever R CMD INSTALL /path/to/package/root

那么你的包命名空间中的S3_BUCKET 的值将是"whatever" 加载命名空间时环境变量S3_BUCKET 的值。如果您希望在加载时评估 Sys.getenv 调用,则需要将其放在 .onLoad 的正文中,如 ?.onLoad 中所述。

?utils::build 或编写 R 扩展手册(可通过 help.start() 访问)中似乎没有明确说明源代码仅在构建时评估的事实。 WRE的this部分有一点线索:

二进制包是已安装版本的包的压缩副本。它们包含已编译的共享库而不是 C、C++ 或 Fortran 源代码,并且 R 函数包含在它们的安装形式中。

您必须推断“R 函数”实际上是指在顶层定义的任何对象。

它实际上只是一种软件开发范式。 构建一个软件包就是创建源中定义的对象并以二进制格式序列化它们。 安装一个软件包就是在你的文件系统的某个地方解压二进制文件。最终,用户获得的是名称-值对,而不是用于生成值的源代码。

devtools 有点混乱,因为load_all 在新环境中获取您的.R 文件,然后将该环境附加到您的搜索路径。它在现场执行此操作,跳过通常的构建和安装过程。这通常很方便,但如果您不了解所有注意事项,可能会导致头痛。

【讨论】:

  • 谢谢米凯尔。不过,我不会说这种范式在语言中是常​​见的或预期的——例如,Python 包通常将设置代码放在模块的顶层。这就是为什么我认为它值得在 R 文档的某个地方提及。
猜你喜欢
  • 2018-10-06
  • 2016-08-19
  • 1970-01-01
  • 2013-07-11
  • 2012-06-21
  • 1970-01-01
  • 1970-01-01
  • 2013-11-04
  • 1970-01-01
相关资源
最近更新 更多