захватывать предупреждения с capture.output - PullRequest
2 голосов
/ 25 апреля 2020

У меня проблемы с использованием capture.output(), и я не могу понять, почему, так как это по большей части просто оболочка для sink().

Рассмотрим этот тривиальный пример с использованием sink():

foo = function() warning("foo")

f = file()
sink(f, type = "message")
foo()
readLines(f)
## [1] "Warning message:" "In foo() : foo"  
close(f)

Работает как положено. однако capture.output() не:

f = file()
capture.output(foo(), file = f, type = "message")
## Warning message:
## In foo() : foo
readLines(f)
## character(0)
close(f)

capture.output() работает для сообщений, хотя:

bar = function() message("bar")
f = file()
capture.output(bar(), file = f, type = "message")
readLines(f)
## [1] "bar"
close(f)

Но согласно документации, сообщения и предупреждения должно быть зафиксировано:

Сообщения, отправленные на stderr() (включая сообщения с message, warning и stop), захватываются type = "message".

Что мне здесь не хватает?

1 Ответ

2 голосов
/ 25 апреля 2020

@ Комментарий MrFlick указывает на потенциальное решение, если у вас есть контроль над аргументами, которые передаются warning(). Если вы используете аргумент immediate. = TRUE, тогда capture.output() может получить предупреждение.

baz = function() warning("baz", immediate. = TRUE)
res = capture.output(baz(), type = "message")
print(res)
## [1] "Warning in baz() : baz"

EDIT

В качестве альтернативы, @ user2554330 указывает, что вы можете использовать options(warn = 1) для немедленной глобальной печати предупреждений.

oldopt = getOption("warn")
options(warn = 1)
res = capture.output(foo(), type = "message")
print(res)
## [1] "Warning in foo() : foo"
options(warn = oldopt)

РЕДАКТИРОВАТЬ 2

Для полноты я считаю полезным указать на этот альтернативный подход с использованием withCallingHandlers, который не требует каких-либо изменений в параметрах и может быть более чистым решением в зависимости от применения. Рассмотрим этот пример вложенных предупреждений:

foo = function() {
  warning("foo")
  bar()
}
bar = function() { 
  warning("bar")
  baz()
}
baz = function() {
  warning("baz")
  TRUE
}
# create a container to hold warning messages
logs = vector("character")
# function to capture warning messages
log_fun = function(w) logs <<- append(logs, w$message)
# function call with message capturing
withCallingHandlers(foo(), warning = log_fun)
## [1] TRUE
## Warning messages:
## 1: In foo() : foo
## 2: In bar() : bar
## 3: In baz() : baz
print(logs)
## [1] "foo" "bar" "baz"

Обратите внимание, что withCallingHandlers позволяет указывать различное поведение для разных условий сигнала, например, warnings и messages могут храниться в отдельных переменных.

...