Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to override exported function from R package listed in Imports

My package's DESCRIPTION file has httr in its Imports directive:

Imports:
    httr (>= 1.1.0),
    jsonlite,
    rstudioapi

httr exports an S3method for length.path.

S3method(length,path)

And it's defined as:

#' @export
length.path <- function(x) file.info(x)$size

In my package I have objects that I assign the class "path" to. Every time I assign the class "path" to any object, regardless of whether or not I ever call length() on the object, this is printed to stdout:

Error in file.info(x) : invalid filename argument

Here's some reproducible code everyone can run:

> sessionInfo()
R version 3.3.1 (2016-06-21)
Platform: x86_64-apple-darwin13.4.0 (64-bit)
Running under: OS X 10.11.5 (El Capitan)

locale:
[1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

loaded via a namespace (and not attached):
[1] tools_3.3.1

> thing = 1:5
> class(thing) = 'path'

> requireNamespace('httr')
Loading required namespace: httr

> sessionInfo()
R version 3.3.1 (2016-06-21)
Platform: x86_64-apple-darwin13.4.0 (64-bit)
Running under: OS X 10.11.5 (El Capitan)

locale:
[1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

loaded via a namespace (and not attached):
[1] httr_1.2.1  R6_2.1.2    tools_3.3.1

> thing = 1:5
> class(thing) = 'path'
Error in file.info(x) : invalid filename argument

I've tried catching it in a try but that doesn't work:

set_class = function(obj, c) {
  class(obj) = c
  return(obj)
}

thing = 1:5
thing = try(set_class(thing, 'path'), silent=TRUE)

Yields:

Error in file.info(x) : invalid filename argument

I've tried assignInNamespace to override the function:

base_length = function(obj) {
  return(base::length(obj))
}

assignInNamespace('length.path', base_length, 'httr')
thing = 1:5
class(thing) = 'path'

But I get Error: evaluation nested too deeply: infinite recursion / options(expressions=)?

When I use httr functions in my package I use them with httr::function so I'm not sure how this length.path function is leaking into my namespace and overriding the base length function. I've also tried explicit @importFrom httr function for each function that I use instead of using httr::function but that doesn't work either.

I also found this:

https://support.bioconductor.org/p/79059/

But the solution seemed to be to edit the source code of httr, which I can't do since my package imports it. How can I get around this?

like image 929
Nicole White Avatar asked Aug 27 '16 19:08

Nicole White


People also ask

Should I export all the internal functions of my packages?

If your package users rely on an internal function that you decide to ditch when re-factoring code, they won’t be happy, so only export what you want to maintain. If all packages exposed all their internal functions, the user environment would be flooded and the namespace conflicts would be out of control. Why write internal functions?

Why do we write functions in R packages?

When writing R code in general there are several reasons to write functions and it is the same within R packages: you can re-use a bit of code in several places (e.g. an epoch converter used for the output of several endpoints from a web API), and you can give it a self-explaining name (e.g.

What is an internal function in R?

An R package can be viewed as a set of functions, of which only a part are exposed to the user. In this blog post we shall concentrate of the functions that are not exposed to the user, so called internal functions: what are they, how does one handle them in one’s own package, and how can one explore them? What is an internal function?


Video Answer


1 Answers

One possibility could be to create a function length.path() in your own package. If the base type of your path-objects is compatible with base::length() you could just unclass it to avoid infinite recursion:

length.path <- function(x) length(unclass(x))

However, this is potentially slow compared to a direct call to base::length() because it copies the object and needs method dispatch two times.

like image 58
AEF Avatar answered Oct 04 '22 05:10

AEF