R warning() wrapper - повысить до родительской функции

У меня есть обертка вокруг встроенной функции warning() в R, которая в основном вызывает warning(sprintf(...)):

warningf <- function(...)
    warning(sprintf(...))

Это потому, что я часто использовал warning(sprintf(...)), что решил сделать из него функцию (это в пакете у меня есть функции, которые я часто использую).

Затем я использую warningf, когда я пишу функции. то есть вместо записи:

f <- function() {
    # ... do stuff
    warning(sprintf('I have %i bananas!',2))
    # ... do stuff
}

Пишу:

f <- function() {
    # ... do stuff
    warningf('I have %i bananas!',2)
    # ... do stuff
}

Если я вызываю первый f(), я получаю:

Warning message:
In f() : I have 2 bananas!

Это хорошо - это говорит мне, откуда появилось предупреждение от f() и что пошло не так.

Если я вызываю второй f(), я получаю:

Warning message:
In warningf("I have %i bananas!",2) : I have 2 bananas!

Это не идеально - он говорит мне, что предупреждение было в функции warningf (конечно, потому что это функция warningf, которая вызывает warning, а не f)), маскируя тот факт, что она действительно появилась из функции f().

Итак, мой вопрос: могу ли я как-то "поднять" вызов warning, чтобы он отображал сообщение warning in f() вместо warning in warningf?

Ответ 1

Один из способов справиться с этим - получить список сред в вашем стеке вызовов, а затем вставить имя родительского фрейма в ваше предупреждение.

Это sys.call() с помощью функции sys.call() которая возвращает элемент в стек вызовов. Вы хотите извлечь второй из последнего элемента в этом списке, то есть родительский warningf для warningf:

warningf <- function(...){
  parent.call <- sys.call(sys.nframe() - 1L)
  warning(paste("In", deparse(parent.call), ":", sprintf(...)), call.=FALSE)
}  

Теперь, если я запускаю вашу функцию:

> f()
Warning message:
In f() : I have 2 bananas! 

Позднее edit: deparse(parent.call) преобразует вызов в строку в случае, если функция f() имеет аргументы, и показывает вызов в том виде, в котором он был указан (т.е. включает аргументы и т.д.).

Ответ 2

Я знаю его старый, но sys.call(sys.nframe() - 1L) или sys.call(-1) возвращает вектор с именем функции и аргументом. Если вы используете его внутри paste() оно выдаст два предупреждения, одно из функции и одно из аргумента. Ответ не отображается, потому что f() не имеет аргументов.
sys.call(sys.nframe() - 1L)[1].