首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >warning.expression防止last.warning更新

warning.expression防止last.warning更新
EN

Stack Overflow用户
提问于 2018-01-03 05:34:57
回答 2查看 317关注 0票数 3

我感兴趣的是,在不围绕方法创建支持基础设施的情况下,尝试在调用时操作警告。也就是说,我需要能够捕捉到警告,而不需要使用以下方式包装代码:

代码语言:javascript
复制
tryCatch(..., warning = function() { action() } )

我相信我可以使用warning.expression处理程序来完成这个任务。

但是,我遇到的问题是,在last.warning发出警告时调用warning.expression时,warning.expression无法检索最新的警告。

例如:

代码语言:javascript
复制
warning_handler = function() {
  if (exists("last.warning", baseenv()) &&
      !is.null(last.warning)) {
    warning_contents =  names(last.warning)
  } else {
    warning_contents =  NA
  }

  message(warning_contents)
}


options(warning.expression = quote({ warning_handler() }))

warning("test1")
# test1
warning("testing2")
# test1
warning("sampletest3")
# test1

如果我恢复到使用默认处理程序(例如NULL ),那么消息就会被更新,代价是不能与它交互。

代码语言:javascript
复制
options(warning.expression = NULL)

warning("test1")
# Warning message:
# test1
warning("testing2")
# Warning message:
# testing2
warning("sampletest3")
# Warning message:
# sampletest3

我是不是漏掉了什么和处理程序有关的东西?

EN

回答 2

Stack Overflow用户

发布于 2018-01-03 17:35:10

添加warning.expression几乎肯定会干扰警告收集机制。我对此不是百分之百肯定,但如果您查看(R.3.4.0,我有一个源的旧副本),您可以在errors.c@335上看到:

代码语言:javascript
复制
static void vwarningcall_dflt(SEXP call, const char *format, va_list ap)
{
    int w;
    SEXP names, s;
    const char *dcall;
    char buf[BUFSIZE];
    RCNTXT *cptr;
    RCNTXT cntxt;

    if (inWarning)
        return;

    s = GetOption1(install("warning.expression"));
    if( s != R_NilValue ) {
        if( !isLanguage(s) &&  ! isExpression(s) )
            error(_("invalid option \"warning.expression\""));
        cptr = R_GlobalContext;
        while ( !(cptr->callflag & CTXT_FUNCTION) && cptr->callflag )
            cptr = cptr->nextcontext;
        eval(s, cptr->cloenv);
        return;
    }
  // ... snip ...


    else if(w == 0) {   /* collect them */
        if(!R_CollectWarnings) setupwarnings();
        if(R_CollectWarnings < R_nwarnings) {
            SET_VECTOR_ELT(R_Warnings, R_CollectWarnings, call);
            Rvsnprintf(buf, min(BUFSIZE, R_WarnLength+1), format, ap);
  // ... snip ...
}

所以return之后的部分没有运行。

看起来last.value是由printWarnings在errors.c@466中填充的,所以这要么发生在warning.expressions处理程序之后,或者更有可能的情况下,根本不发生:

代码语言:javascript
复制
attribute_hidden
void PrintWarnings(void)
{
  // ... snip to very end of fun ...

    /* now truncate and install last.warning */
    PROTECT(s = allocVector(VECSXP, R_CollectWarnings));
    PROTECT(t = allocVector(STRSXP, R_CollectWarnings));
    names = CAR(ATTRIB(R_Warnings));
    for(i = 0; i < R_CollectWarnings; i++) {
        SET_VECTOR_ELT(s, i, VECTOR_ELT(R_Warnings, i));
        SET_STRING_ELT(t, i, STRING_ELT(names, i));
    }
    setAttrib(s, R_NamesSymbol, t);
    SET_SYMVALUE(install("last.warning"), s);
    UNPROTECT(2);

    endcontext(&cntxt);

    inPrintWarnings = 0;
    R_CollectWarnings = 0;
    R_Warnings = R_NilValue;
    return;
}

所以这很可能就是发生了什么。我还没有完成流程,所以我可能错了。如果我是对的,似乎没有办法从warning.expression获得警告信息。

除此之外,请注意,last.warning被记录为是无文档的,FWIW。

票数 3
EN

Stack Overflow用户

发布于 2018-01-11 16:27:17

chat中的@lionel提供的另一个回答是:在顶层安装一个警告处理程序,您可以通过使用.Internal()调用内部函数来实现这一点。

代码语言:javascript
复制
handlers <- list(warning = function(cnd) cat("hello\n")) 
classes <- names(handlers) 
.Internal(.addCondHands(classes, handlers, globalenv(), NULL, TRUE)) 

warn("plop")

这种方法的唯一缺点是,由于内部调用,CRAN会在提交时拒绝包。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/48071718

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档