【问题标题】:How to override exported function from R package listed in Imports如何覆盖导入中列出的 R 包中的导出函数
【发布时间】:2017-01-04 05:46:20
【问题描述】:

My packageDESCRIPTION 文件在其 Imports 指令中有 httr

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

httrexports an S3methodlength.path

S3method(length,path)

它是defined as

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

在我的包中,我有将类“路径”分配给的对象。每次我将类“路径”分配给任何对象时,无论我是否曾在该对象上调用 length(),这都会打印到标准输出:

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

这里有一些每个人都可以运行的可重现代码:

> 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

我尝试在 try 中捕获它,但这不起作用:

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

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

产量:

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

我已经尝试assignInNamespace 覆盖该函数:

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

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

但我得到Error: evaluation nested too deeply: infinite recursion / options(expressions=)?

当我在我的包中使用httr 函数时,我将它们与httr::function 一起使用,所以我不确定这个length.path 函数是如何泄漏到我的命名空间中并覆盖基本长度函数的。我还为我使用的每个函数尝试了明确的@importFrom httr function,而不是使用httr::function,但这也不起作用。

我还发现了这个:

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

但解决方案似乎是编辑httr的源代码,因为我的包导入了它,所以我不能这样做。我该如何解决这个问题?

【问题讨论】:

  • 如果length()是泛型,那么你想调用base::length.default()来获取默认方法。
  • 问题是我从不叫长度。当我调用 class(obj) = 'path' 时会发生这种情况
  • 我认为class(obj) = 'path' 只会在 RStudio 或类似的 IDE 中给出错误,在这些 IDE 中,您基本上可以一直看到str(...) 的工作空间变量的输出。当您分配一个新类时,IDE 会更新此描述并在此过程中调用length。在“正常”的 RGui 中不会发生错误。
  • 啊,那一定是它。不过,我应该能够以某种方式覆盖该功能,对吧?
  • 您应该向该方法的作者投诉,因为以这种方式覆盖长度是一个非常糟糕的主意! (即在 GitHub 上提交问题,我们将在 httr 中修复它)

标签: r namespaces httr r-package


【解决方案1】:

一种可能性是在您自己的包中创建一个函数length.path()。如果您的path-objects 的基本类型与base::length() 兼容,您可以取消分类以避免无限递归:

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

但是,与直接调用 base::length() 相比,这可能会很慢,因为它会复制对象并需要两次方法分派。

【讨论】:

  • 嗯,好像没用。将该逐字逐句添加到我的包中,但仍然看到 stdout 的错误。我可能需要导出它吗?我的路径对象的基本类型是一个列表,所以我认为它应该可以正常工作。
  • 您确定错误是由DESCRIPTION文件中的Imports: httr造成的吗?我只是试图创建一个虚拟包,它导入 httr 并且只包含一个返回类 path 的对象的函数。一切正常。只有当我在加载虚拟包后调用library(httr) 时才会出现错误。
  • 直到我在我的包中使用一个使用httr 的函数之前,它似乎不会发生。因此,如果我使用库(RNeo4j),然后是 sessionInfo(),则不会加载 httr 命名空间,但是一旦我使用我的包中在内部使用 httr::func 的函数,我就会在 sessionInfo() 中看到 httr。那时我可以重现 file.info 错误。
  • 当然,我的错误 -.- 使用 export("length.path") 导出上述函数对我有用。将其声明为 S3method("length", "path") 不会。
  • 还是不行。 :( 我的 NAMESPACE 中有 export(length.path) 下的函数,但仍然看到 stdout 的错误。
【解决方案2】:

我的解决方案是添加一个.onLoad 函数。感谢AEF's answer 提出unclass 的想法。

#' @importFrom utils assignInNamespace
.onLoad = function(libname, pkgname) {
  length.path = function(obj) {
    return(length(unclass(obj)))
  }

  assignInNamespace('length.path', length.path, 'httr')
}

它在R CMD check --as-cran 中引发了NOTE,但我希望能侥幸成功。

【讨论】:

    猜你喜欢
    • 2021-12-13
    • 2020-02-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-18
    • 2022-01-18
    • 1970-01-01
    相关资源
    最近更新 更多