How to Override a Non-Visible Function in the Package Namespace

How do I override a non-visible function in the package namespace?

Use fixInNamespace. :)

fixInNamespace("predict.ar", "stats")

or

fixInNamespace("predict.ar", pos="package:stats")

(Several years later...)

From Nicholas H's comment: if you want to push some code to CRAN that depends upon an internal function from another package, it will throw a build warning and be rejected by R-core. If you want that internal function, you should just take a copy of it using the ::: operator and maintain it yourself.

predict.ar <- stats:::predict.ar

R: what's the proper way to overwrite a function from a package?

There are lots of different cases here.

If it's a bug in someone else's package

Then the best practice is to contact the package maintainer and persuade them to fix it. That way everyone gets the fix, not just you.

If it's a bug while developing your own package

Then you need to find a workflow where rebuilding packages is easy. Like using the devtools package and typing build(mypackage), or clicking a button ("Build & Reload" in RStudio; "R CMD build" in Architect).

If you just want different behaviour to an existing package

If it isn't a bug as such, or the package maintainer won't make the fix that you want, then you'll have to maintain you own copy of f1. Using assignInNamespace to override it in the existing package is OK for exploring, but it's a bit hacky so it isn't really suitable for a permanent solution.

Your best bet is to create your own package containing copies of f1 and f2. This is less effort than it sounds, since you can just define f2 <- existingpackage::f2.


In response to the comment:

Second and third cases makes sense if you are alone but they require to build and install the packages which is tricky in the case of my organisation as the packages are deployed on dozens of computer and I need root access to update the packages.

So take a copy of the existing package source, apply your patch, and host it on your company network or github or Bitbucket. Then the updated package can be installed programmatically via

install.packages("//some/network/path/mypackage_0.0-1.tar.gz", repos = NULL)

or

library(devtools)
install_github("mypackage", "mygithubusername")

Since the installation is just a line of code, you can easily push it to as many machines as you like. You don't need root access either - just install the package to a library folder that doesn't require root access to write to. (Read the Startup and .libPaths help pages for how to define a new library.) You'll need network access to those machines, but I can't help you with that. Speak to your network administrator or your boss or whoever can get you permission.

Change internal function of a package

Try

?assignInNamespace

to replace .HMR.fit1 in the HMR package with your version.

Possible duplicate of :

How do I override a non-visible function in the package namespace?

Overriding a package function inherited by another package

Changing the function in the formatR namespace doesn't change what knitr uses because knitr is already loaded. So, you could unload and reload it.

assignInNamespace("tidy.source", function()print("My tidy.source"), "formatR")
detach('package:knitr', unload=TRUE)
library(knitr)
get("tidy.source", envir=asNamespace("knitr"))
#function()print("My tidy.source")

how to fix/edit an invisible function in R interaction session?

There are functions assignInNamespace and fixInNamespace that allow doing what you say. There is also the edit argument to the trace function which will let you edit a function in place. Using trace has the advantage of making it easy to untrace and remove the changes that you made.

Get namespace of function

You can use getAnywhere For example, if you're looking for the namespace for the stringr function str_locate you can do

getAnywhere("str_locate")$where
# [1] "package:stringr" "namespace:stringr"

This will work as long as stringr is "visible on the search path, registered as an S3 method or in a namespace but not exported."

The result is a named list, and you can see what's available from getAnywhere with names

names(getAnywhere("str_locate"))
# [1] "name" "objs" "where" "visible" "dups"

How can a non-imported method in a not-attached package be found by calls to functions not having it in their namespace?

I'm not sure if I correctly understand your question, but the main point is that group is character vector while data$group is factor.

After attaching gmodels, the call for reorder(factor) calls gdata:::reorder.factor.
so, reorder(factor(group)) calls it.

In transform, the function is evaluated within the environment of the first argument, so in T2 <- transform(data, group = reorder(group,-num)), group is factor.

UPDATED

library attaches the import packages into loaded namespace.

> loadedNamespaces()
[1] "RCurl" "base" "datasets" "devtools" "grDevices" "graphics" "methods"
[8] "stats" "tools" "utils"
> library(gmodels) # here, namespace:gdata is loaded
> loadedNamespaces()
[1] "MASS" "RCurl" "base" "datasets" "devtools" "gdata" "gmodels"
[8] "grDevices" "graphics" "gtools" "methods" "stats" "tools" "utils"

Just in case, the reorder generic exists in namespace:stats:

> r <- ls(.__S3MethodsTable__., envir = asNamespace("stats"))
> r[grep("reorder", r)]
[1] "reorder" "reorder.default" "reorder.dendrogram"

And for more details

The call of reorder will search the S3generics in two envs:

see ?UseMethod

first in the environment in which the generic function is called, and then in the registration data base for the environment in which the generic is defined (typically a namespace).

then, loadNamespace registers the S3 functions to the namespace.

So , in your case, library(gmodels) -> loadNamespace(gdata) -> registerS3Methods(gdata).

After this, you can find it by:

> methods(reorder)
[1] reorder.default* reorder.dendrogram* reorder.factor*

Non-visible functions are asterisked

However, as the reorder.factor is not attached on your search path, you cannot access it directly:

> reorder.factor
Error: object 'reorder.factor' not found

Probably this is whole scenario.



Related Topics



Leave a reply



Submit