导出函数中的R data.table中断

kjm*_*mij 20 r devtools data.table

我在将data.table用于roxygen2导出函数时遇到问题.

这是一个名为foo.R的文件中的一个简单的假函数(位于我的包的R目录中),它使用data.table:

#' Data.table test function
#' @export
foo <- function() {
  m <- data.table(c1 = c(1,2,3))
  print(is.data.table(m))
  m[,sum(c1)]
}
Run Code Online (Sandbox Code Playgroud)

如果我将此函数复制并粘贴到R中,此函数可以正常工作:

> foo <- function() {
+   m <- data.table(c1 = c(1,2,3))
+   print(is.data.table(m))
+   m[,sum(c1)]
+ }
> foo()
[1] TRUE
[1] 6
Run Code Online (Sandbox Code Playgroud)

但是,如果我只是加载导出的函数,R认为data.table是一个data.frame并且中断:

> rm(foo)
> load_all()
Loading test_package
> foo
function() {
  m <- data.table(c1 = c(1,2,3))
  print(is.data.table(m))
  m[,sum(c1)]
}
<environment: namespace:test_package>
> foo()
[1] TRUE
Error in `[.data.frame`(x, i, j) : object 'c1' not found
Run Code Online (Sandbox Code Playgroud)

这是怎么回事?

UPDATE

感谢@GSee的帮助.看起来这实际上是一个devtools问题.查看下面的交互式命令行代码.

加载test_package库后,foo正确运行:

> foo
function ()
{
    m <- data.table(c1 = c(1, 2, 3))
    print(is.data.table(m))
    m[, sum(c1)]
}
<environment: namespace:test_package>
> foo()
[1] TRUE
[1] 6
Run Code Online (Sandbox Code Playgroud)

跑步load_all()休息foo:

> load_all()
Loading test_package
> foo()
[1] TRUE
Error in `[.data.frame`(x, i, j) : object 'c1' not found
Run Code Online (Sandbox Code Playgroud)

以某种方式source('R/foo.R')恢复foo功能:

> source('R/foo.R')
> foo
function() {
  m <- data.table(c1 = c(1,2,3))
  print(is.data.table(m))
  m[,sum(c1)]
}
> foo()
[1] TRUE
[1] 6
Run Code Online (Sandbox Code Playgroud)

未来的电话load_all()不会foo再次破裂:

> load_all()
Loading test_package
> foo
function() {
  m <- data.table(c1 = c(1,2,3))
  print(is.data.table(m))
  m[,sum(c1)]
}
> foo()
[1] TRUE
[1] 6
Run Code Online (Sandbox Code Playgroud)

此外,我更新到devtools 1.5并尝试添加.datatable.aware=TRUE,但似乎没有做任何事情.

Aru*_*run 12

正如@GSee指出的那样(在评论中)这个问题似乎仍然是这个问题.

为了查明包是否为data.table,请data.table调用该函数cedta(),即:

> data.table:::cedta
function (n = 2L) 
{
    te = topenv(parent.frame(n))
    if (!isNamespace(te)) 
        return(TRUE)
    nsname = getNamespaceName(te)
    ans = nsname == "data.table" || "data.table" %chin% names(getNamespaceImports(te)) || 
        "data.table" %chin% tryCatch(get(".Depends", paste("package", 
            nsname, sep = ":"), inherits = FALSE), error = function(e) NULL) || 
        (nsname == "utils" && exists("debugger.look", parent.frame(n + 
            1L))) || nsname %chin% cedta.override || identical(TRUE, 
        tryCatch(get(".datatable.aware", asNamespace(nsname), 
            inherits = FALSE), error = function(e) NULL))
    if (!ans && getOption("datatable.verbose")) 
        cat("cedta decided '", nsname, "' wasn't data.table aware\n", 
            sep = "")
    ans
}
<bytecode: 0x7ff67b9ca190>
<environment: namespace:data.table>
Run Code Online (Sandbox Code Playgroud)

这里的相关检查是:

"data.table" %chin% get(".Depends", paste("package", nsname, sep=":"), inherits=FALSE)
Run Code Online (Sandbox Code Playgroud)

当一个包依赖data.table,上面的命令应该返回TRUE- 也就是说,如果您通过R CMD INSTALL然后加载包然后加载了包.这是因为,当您加载包时,R默认情况下也会在命名空间中创建".Depends"变量.如果你这样做:

ls("package:test", all=TRUE)
# [1] ".Depends" "foo"     
Run Code Online (Sandbox Code Playgroud)

但是,当您这样做时devtools:::load_all(),似乎没有设置此变量.

# new session + set path to package's dir
devtools:::load_all()
ls("package:test", all=TRUE)
# [1] "foo"
Run Code Online (Sandbox Code Playgroud)

所以,cedta()并不了解这个包的确取决于data.table.但是,当您手动设置时.datatable.aware=TRUE,该行:

identical(TRUE, get(".datatable.aware", asNamespace(nsname), inherits = FALSE))
Run Code Online (Sandbox Code Playgroud)

得到执行,将返回TRUE,因此克服了这个问题.但是,devtools不将.Depends变量放在包的命名空间中的事实仍然存在.

总而言之,这确实不是问题data.table.