R: Как сделать, чтобы dump.frames() включал все переменные для последующей посмертной отладки с помощью debugger()

У меня есть следующий код, который вызывает ошибку и пишет дамп всех кадров, используя dump.frames() как предложено, например, Хэдли Уикхем:

a <- -1
b <- "Hello world!"
bad.function <- function(value)
{
  log(value)                  # the log function may cause an error or warning depending on the value
}

tryCatch( {
             a.local.value <- 42
             bad.function(a)
             bad.function(b)
          },
          error = function(e)
          {
            dump.frames(to.file = TRUE)
          })

Когда я перезапускаю сеанс R и загружаю дамп, чтобы отладить проблему через

load(file = "last.dump.rda")
debugger(last.dump)

Я не могу найти ни мои переменные (a, b, a.local.value), ни мою функцию "bad.function" в кадрах.

Это делает свалку почти бесполезной для меня.

Что мне нужно сделать, чтобы увидеть все мои переменные и функции для достойного посмертного анализа?

Выход из debugger является:

> load(file = "last.dump.rda")
> debugger(last.dump)
Message:  non-numeric argument to mathematical functionAvailable environments had calls:
1: tryCatch({
    a.local.value <- 42
    bad.function(a)
    bad.function(b)
2: tryCatchList(expr, classes, parentenv, handlers)
3: tryCatchOne(expr, names, parentenv, handlers[[1]])
4: value[[3]](cond)

Enter an environment number, or 0 to exit  
Selection: 

PS: я использую R3.3.2 с RStudio для отладки.

2 ответа

Решение

Обратите внимание, что часто с продуктом R Core лучше работать, чем просто рассказывать, что R имеет ошибку. Здесь явно нет ошибки, поскольку она ведет себя точно так, как задокументировано.

Также нет проблем, если вы работаете в интерактивном режиме, поскольку у вас есть полный доступ к вашему рабочему пространству (которое может бытьБОЛЬШИМ), поэтому проблема относится только к пакетным заданиям (как вы упомянули).

Что у нас есть, так этоотсутствие функции, и запросы функций (и отчеты об ошибках!) Должны происходить на сайте ошибок R (он же _'R bugzilla '), https://bugs.r-project.org/... обычно однако после прочтения соответствующей страницы на веб-сайте R: https://www.r-project.org/bugs.html.

Обратите внимание, что R bugzilla доступен для поиска, и в данном случае вы довольно быстро обнаружите, что Андреас Керстинг сделал хорошее предложение (а именно как пожелание, а не претензию на ошибку), https://bugs.r-project.org/bugzilla/show_bug.cgi?id=17116 и, следовательно, я добавил отсутствующую функцию в R уже 16 августа. Да, конечно, версия для разработки R, он же R-devel. Смотрите также сегодняшнюю тему на R-devel список рассылки, https://stat.ethz.ch/pipermail/r-devel/2016-November/073378.html

Обновление от 20 ноября 2016 года. Обратите внимание, что это не ошибка R (см. Ответ Мартина Мачлера). Я не изменил свой ответ для воспроизводимости. Описанный обходной путь все еще применяется.

Резюме

Я думаю dump.frames(to.file = TRUE) в настоящее время является антишаблоном (или, возможно, ошибкой) в R, если вы хотите отлаживать ошибки пакетных заданий в новом сеансе R.

Вам лучше заменить его на

  dump.frames()
  save.image(file = "last.dump.rda")

или же

options(error = quote({dump.frames(); save.image(file = "last.dump.rda")}))

вместо

options(error = dump.frames)

потому что глобальная среда (.GlobalEnv = пользовательское рабочее пространство, в котором вы обычно создаете свои объекты), затем включается в дамп, но отсутствует, когда вы сохраняете дамп напрямую через dump.frames(to.file = TRUE),

Анализ воздействия

Без .GlobalEnv вы теряете важные объекты верхнего уровня (и их текущие значения;-), чтобы понять поведение вашего кода, которое привело к ошибке!

Особенно в случае ошибок в "неинтерактивных" пакетных заданиях R, без которых вы потерялись .GlobalEnv поскольку вы можете отлаживать только во вновь запущенном (пустом) интерактивном рабочем пространстве, где вы можете получить доступ только к объектам в кадрах стека вызовов.

Используя приведенный выше фрагмент кода, вы можете проверить значения объектов, которые привели к ошибке в новом рабочем пространстве R, как обычно, с помощью:

load(file = "last.dump.rda")
debugger(last.dump)

Фон

Реализация dump.frames создает переменную last.dump в рабочей области и заполняет его средами стека вызовов (sys.frames(), Каждая среда содержит "локальные переменные" вызываемой функции). Затем он сохраняет эту переменную в файл, используя save(),

Стек фреймов (стек вызовов) растет с каждым вызовом функции, см. ?sys.frames:

.GlobalEnv присваивается номер 0 в списке кадров. Каждая последующая оценка функции увеличивает стек фреймов на 1, и среда [...] для оценки этой функции возвращается [...] sys.frame с соответствующим индексом.

Обратите внимание, что .GlobalEnv имеет индекс номер 0.

Если я сейчас начну отлаживать дамп, созданный кодом в вопросе, и выберу кадр 1 (не 0!), Я смогу увидеть переменную parentenv какие точки (ссылки) .GlobalEnv:

Browse[1]> environmentName(parentenv)
[1] "R_GlobalEnv"

Поэтому я считаю, что sys.frames не содержит .GlobalEnv и поэтому dump.frames(to.file = TRUE) ни так как он хранит только sys.frames без всех других объектов .GlobalEnv,

Может быть, я ошибаюсь, но это выглядит как нежелательный эффект или даже ошибка. Обсуждения приветствуются!

Рекомендации

https://cran.r-project.org/doc/manuals/R-exts.pdf

Выдержка из раздела 4.2 Отладка кода R (стр. 96):

Поскольку last.dump можно просмотреть позже или даже в другом сеансе R, посмертная отладка возможна даже для пакетного использования R. Нам нужно договориться о сохранении дампа: это можно сделать либо с помощью флаг командной строки - сохранить, чтобы сохранить рабочее пространство в конце цикла или с помощью параметра, такого как

параметры (ошибка = цитата ({dump.frames(to.file=TRUE); q()}))

Другие вопросы по тегам