Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

force R to always display package name in error message

I sometimes load multiple packages that export functions of the same name. For example, both Hmisc and dplyr have a summarize function, and I sometimes load both packages. I then call summarize, thinking that I am calling dplyr::summarize when I am really calling Hmisc::summarize. When that happens, I get an error message like this:

Error in summarize(., mean = mean(instRating)) : 
  argument "by" is missing, with no default

The message is initially hard to understand, because my code contains no errors. It takes me a minute to realize that I've called a function in the wrong package. The error message would be easier to understand if its first line included the name of the relevant package:

Error in Hmisc::summarize(., mean = mean(instRating)) : 

Is there a way to force R to display the package name in these error messages?

I know that I can get around the problem by typing out dplyr::summarize or by changing the order in which I load packages. But my interest lies with adding detail to R's error messages.

like image 617
user697473 Avatar asked Jun 02 '20 12:06

user697473


Video Answer


1 Answers

From the documentation of the base option error:

'error': either a function or an expression governing the handling of non-catastrophic errors such as those generated by 'stop' as well as by signals and internally detected errors. If the option is a function, a call to that function, with no arguments, is generated as the expression. By default the option is not set: see 'stop' for the behaviour in that case. The functions 'dump.frames' and 'recover' provide alternatives that allow post-mortem debugging. Note that these need to specified as e.g. 'options(error = utils::recover)' in startup files such as '.Rprofile'.

So it should be possible to define a function that returns the name of the package where the function that’s throwing the error lives. For example:

library(dplyr)
library(Hmisc)
data(mtcars)

print_package <- function() {
    calls <- sys.calls()
    call <- calls[[length(calls) - 1]]
    fun.name <- as.character(call)[1]
    pkg.name <- sub("package:", "", getAnywhere(fun.name)$where[1], fixed = TRUE)
    message (paste0("In ", pkg.name))
}

options(error = print_package)

summarize(mtcars$mpg)

Returns:

Error in summarize(mtcars$mpg) : 
  argument "by" is missing, with no default
In Hmisc

Edit (using rlang::trace_back)

It turns out that there is a much cleaner way of doing this (credit goes to Hadley Wickham and his "Advanced R, Second edition"):

library(dplyr)
library(Hmisc)
data(mtcars)

print_trace_back <- function() {
    print(rlang::trace_back(bottom = sys.frame(-1)))
}

options(error = print_trace_back)

Seems to handle errors gracefully:

> summarize(mtcars$mpg)
Error in summarize(mtcars$mpg) : 
  argument "by" is missing, with no default
    █
 1. └─Hmisc::summarize(mtcars$mpg)
>
> Hmisc::summarize(mtcars$mpg)
Error in Hmisc::summarize(mtcars$mpg) : 
  argument "by" is missing, with no default
    █
 1. └─Hmisc::summarize(mtcars$mpg)
>
> summarize(mtcars$mpg, as.character(mtcars$apa), mean)
Error in tapply(X, INDEX, FUN, ..., simplify = simplify) : 
  arguments must have same length
    █
 1. └─Hmisc::summarize(mtcars$mpg, as.character(mtcars$apa), mean)
 2.   └─Hmisc::mApply(X, byc, FUN, ..., keepmatrix = nc > 1)
 3.     └─base::tapply(X, INDEX, FUN, ..., simplify = simplify)
 4.       └─base::stop("arguments must have same length")
>
> (function() stop("Error"))()
Error in (function() stop("Error"))() : Error
    █
 1. └─(function() stop("Error"))()
 2.   └─base::stop("Error")
like image 154
mgw Avatar answered Oct 20 '22 04:10

mgw