Using trace on a hidden function to edit source code in R - r

For a package I am using, I would like to fix part of the code. I have downloaded the "package source" from CRAN and have narrowed down where the problem is. I would like to edit the problem function in RStudio. I've tried using trace, but I am unable to call the desired function. The function I want to call is a helper function (not in the documentation) to the main function (which is in the documentation). Is there a way to edit the functions not in the documentation and used in the implementation?
If it helps, the package I am using is called RecordLinkage. I would like to change the function .toFF which is called by RLBigDataDedup and is in the file RLBigData-classes.r.
Now that I've established the problem by looking at the source code, I now want to edit it in RStudio so that I can run it when using the package... The best I can do is looking at RLBigDataDedup in RStudio, but I can't find the .toFF that is used within it.

Thats not working because the hidden function .toFF is not known in the global env because it is hidden. If you want to edit/debug hidden function you have to specify the where argument in trace() with the corresponding function. In your case it would be RLBigDataLinkage.
Regarding to the docs of trace, it is stated:
For “hidden” functions such as S3 methods in a namespace, where = *
typically needs to be specified as well
So for your answer this will work:
trace(".toFF", edit=T, where = RLBigDataLinkage)

try debug(.toFF) or debug(function_to_calls_.toFF) This will open the debug tool when the function is called.

Related

S3 - delayed method registration in R

I have an R-package ('mill') with a 'suggest' ('hlt') where I would like to register a new class for an S3 method in 'hlt'. Because the 'hlt' package is a suggest I followed the advise of Hadley and copied a function in 'mill' that registers my new mill::html.pdf_diff_df() function but not until after loading the 'hlt' package:
https://github.com/r-lib/vctrs/blob/master/R/register-s3.R
The problem I encounter is that when I load 'mill' and call the html() method on the new class ('pdf_diff_df') defined in the 'mill' package I just get the error:
html(df)
Error in html(df) : could not find function "html"
I would, of course, like to give the warning that one should load the 'hlt' package at that point, otherwise the user doesn't understand the problem. Any ideas? The source in 'mill' of this new function is here:
https://github.com/SVA-SE/mill/blob/136f372f88d794bb6149922c24dd9a4f731e4c7e/R/images.R#L195-L206
If I understand the situation correctly, hlt exports html(), but you don't want a fixed dependency on hlt, so you can't import html from hlt.
In that case, simply use a fully qualified call to it, i.e. hlt::html(...).
Since hlt is only in Suggests, this should only be called conditional on requireNamespace('hlt') returning TRUE.
Edited to add:
If you want a user to be able to call html(...), you have to export it from your package. This is hard, because it is exported from the hlt package, and if the two packages export different versions, you'll get warnings about one hiding the other.
As far as I know there isn't a nice solution to this, but really, it's not your problem. If a user hasn't attached hlt, they have no reason to expect html(...) to do anything. If they have, it will just work.
If you really want to help out the user without generating new messages, you could export your own function with a different name, something like
html2 <- function(...) {
if (requireNamespace("hlt"))
hlt::html(...)
else
warning("Suggested package 'hlt' must be installed for this to work.")
}

How can I add a breakpoint to debug my R package without recompiling

When I develop a R package I endup doing the following thing:
load the latest build
use it
realize there is a bug in say function 'f_bug'
try to debug
I would be easy if I could just 're-source' f_bug and that the newly sourced version would be chosen (I'd rebuild the package clean latter).
But I cannot do that, it looks like the package::f_bug is always "chosen" by default when called within another package function.
Can I do such a thing ?
You can't use RStudio's convenient graphical breakpoints, but you can do the same thing using trace:
trace(package::f_bug, browser, at = insertion_point)
Here insertion_point refers not to line numbers but to a vector of substeps. From ?trace:
look at ‘as.list(body(f))’ to get the numbers
associated with the steps in function ‘f’.)
Another option might be to use utils::setBreakpoint which takes a file name and line number as arguments. See the help file for details.

R: How do I add an extra function to a package?

I would like to add an idiosyncratically modified function to package written by someone else, with an R Script, i.e. just for the session, not permanently. The specific example is, let's say, bls_map_county2() added to the blscrapeR package. bls_map_county2 is just a copy of the bls_map_county() function with an added ... argument, for purposes of changing a few of the map drawing parameters. I have not yet inserted the additional parameters. Running the function as-is, I get the error:
Error in BLS_map_county(map_data = df, fill_rate = "unemployed_rate", :
could not find function "geom_map"
I assume this is because my function does not point to the blscrapeR namespace. How do I assign my function to the (installed, loaded) blscrapeR namespace, and is there anything else I need to do to let it access whatever machinery from the package it requires?
When I am hacking on a function in a particular package that in turn calls other functions I often use this form after the definition:
mod_func <- function( args) {body hacked}
environment(mod_func) <- environment(old_func)
But I think the function you might really want is assignInNamespace. These methods will allow the access to non-exported functions in loaded packages. They will not however succeed if the package is not loaded. So you may want to have a stopifnot() check surrounding require(pkgname).
There are two parts to this answer - first a generic answer to your question, and 2nd a specific answer for the particular function that you reference, in which the problem is something slightly different.
1) generic solution to accessing internal functions when you edit a package function
You should already have access to the package namespace, since you loaded it, so it is only the unexported functions that will give you issues.
I usually just prepend the package name with the ::: operator to the non exported functions. I.e., find every instance of a call to some_internal_function(), and replace it with PackageName:::some_internal_function(). If there are several different internal functions called within the function you are editing, you may need to do this a few times for each of the offending function calls.
The help page for ::: does contain these warnings
Beware -- use ':::' at your own risk!
and
It is typically a design mistake to use ::: in your code since the
corresponding object has probably been kept internal for a good
reason. Consider contacting the package maintainer if you feel the
need to access the object for anything but mere inspection.
But for what you are doing, in terms of temporarily hacking another function from the same package for your own use, these warnings should be safe to ignore (at you own risk, of course - as it says in the manual)
2) In the case of blscrapeR ::bls_map_county()
The offending line in this case is
ggplot2::ggplot() + geom_map(...
in which the package writers have specified the ggplot2 namespace for ggplot(), but forgotten to do so for geom_map() which is also part of ggplot2 (and not an internal function in blscrapeR ).
In this case, just load ggplot2, and you should be good to go.
You may also consider contacting the package maintainer to inform them of this error.

How can I edit the source code for an R function?

I am working with the earlywarnings package, and would like to edit one of the functions written in the qda_ews function. I could do fix(...) but the function I would like to edit is for some reason not listed when I use fix.
The function is called generic_RShiny. Here is the link to the github (https://github.com/earlywarningtoolbox/earlywarnings-R/blob/master/earlywarnings/R/qda_ews.R).
How can I access the entire qda_ews.R code to make the changes I need?
once the library is loaded, use
trace(name_of_function, edit = T)
but beware that the function will be modified permanently (until of course you reinstall the package)

Embed fix() function within .R script?

I am looking for a way to embed the fix() function within a script. Basically, here's what I'm currently doing:
I load a certain package. For example, library(PerformanceAnalytics)
I call the fix() function to edit a couple functions within the loaded package. Example, fix(VaR).
Then, using R's built-in editor, I copy-paste my function over the one originally loaded from the package.
Finally, I source in my .R script which calls the above functions I fixed and performs the computations I need.
Essentially, I'd like to streamline Step 3 above. Rather than having to manually type fix(function) and copy-paste over the original functions within the loaded package, I'd rather just have it done within a script I source.
Is there anyway to accomplish this?
FYI, I have reached out to the package's creator and loading a re-compiled version of the package with my modified code is out of the question.
Maybe source your functions and then use assignInNamespace?
EDIT #1:
The above won't work because assignInNamespace doesn't alter objects that have been exported. Instead,
put your functions in a file (foo.R)
load the package
then source(foo.R) or
sys.source(foo.R, envir=attach(NULL, name="myenv"))
Your functions will be higher up on the search list if you load them after the package, so R will find them before getting to the package's functions with the same name.
EDIT #2:
I didn't realize VaR called unexported functions in the namespace. That's why EDIT #1 doesn't work. To get it to work, you would need to explicitly reference all unexported PerformanceAnalytics functions used in VaR (e.g. change VaR.Gaussian to PerformanceAnalytics:::VaR.Gaussian).
See this post on R-devel for a couple other approaches. I couldn't quickly get Prof. Ripley's solution to work (I get the same error as in EDIT #1) and I didn't try Gabor's solution.
You can edit the body directly, discussed here:
What ways are there to edit a function in R?
You can download the packages source from CRAN. Edit the function (it will be found in PackageName/R), then install this package into R and just use it that way.
You can even change the package name in the DESCRIPTION file ... call it "PerformanceAnalytics2", then in R you just library(PerformanceAnalytics2) and use it as you would the original package.

Resources