Подтвердить что ты не робот

R 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)]
}

Если я копирую и вставляю эту функцию в R, эта функция отлично работает:

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

Но если я просто загружаю экспортированную функцию, R думает, что data.table - это data.frame и breaks:

> 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

Что?

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

Запуск load_all() breaks foo:

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

Как-то 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

И последующие вызовы 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

Кроме того, я обновился до devtools 1.5 и попытался добавить .datatable.aware=TRUE, но ничего не сделал.

4b9b3361

Ответ 1

Проблема, поскольку @GSee указала (по комментариям), кажется, эта проблема.

Чтобы узнать, является ли пакет информационным.значением, 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>

Соответствующая проверка:

"data.table" %chin% get(".Depends", paste("package", nsname, sep=":"), inherits=FALSE)

Когда пакет зависит от data.table, приведенная выше команда должна возвращать TRUE - то есть, если вы установили пакет через R CMD INSTALL, а затем загрузили пакет. Это связано с тем, что при загрузке пакета R по умолчанию создает переменную ".Depends" в пространстве имен. Если вы это сделали:

ls("package:test", all=TRUE)
# [1] ".Depends" "foo"     

Однако, когда вы делаете devtools:::load_all(), эта переменная, похоже, не установлена.

# new session + set path to package dir
devtools:::load_all()
ls("package:test", all=TRUE)
# [1] "foo"

Итак, cedta() не знает, что этот пакет действительно зависит от data.table. Однако, когда вы вручную устанавливаете .datatable.aware=TRUE, строка:

identical(TRUE, get(".datatable.aware", asNamespace(nsname), inherits = FALSE))

выполняется, что вернет TRUE и, следовательно, преодолеет проблему. Но тот факт, что devtools не помещает переменную .Depends в пространство имен пакетов, все еще существует.

В общем, это действительно не проблема с data.table.