-
Notifications
You must be signed in to change notification settings - Fork 38
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Could callr support user hooks? #200
Comments
Well, you can already modify environment variables, just set them, and they'll be passed to the subprocess. |
Yes, that’s essentially the workaround discussed in the linked issue (the workaround uses argument passing; the principle’s the same). But I can’t do so transparently when the user uses ‘callr’. I should have led with a reprex. From the user’s perspective, the following should work, and “surprisingly” currently doesn’t:
When executing
The reason for the failure is that Ideally from a user’s perspective, this should “just work”. But as the author of ‘box’, the best I can do is look at the environment and the command line for clues (unless I drop down to the OS level and snoop about the parent process). (I realise that in the reprex above ‘box’ wouldn’t have the opportunity to install a hook in the caller, so the envisioned PR wouldn’t work. But in many relevant situations ‘box’ would already be loaded in the caller.) Maybe more pragmatically: Is there a reliable way of finding out that I am inside a ‘callr’ subprocess? In the current release of ‘callr’ I could check if |
I would happy to expose some info in the subprocess, e.g.
Do you need anything else? |
Beyond that, unfortunately for my specific purposes the information I’d need are quite complex (i.e.: whether the code was launched by knitr, Shiny or testthat, or whether it’s running inside RStudio …; currently, only ‘testthat’ uses environment variables to signal this), hence the idea for the user hook. But having the original command line would already help a lot. |
I can pass the IDK what Shiny has to detect running in an app. RStudio also sets the We can pass the command line as well, but that seems a bit weird. What information do you use from that? |
For knitr and RStudio, the mere presence is unfortunately not sufficient for my purposes — ‘box’ needs the information provided by
Shiny has a function
The script path (if present). Unfortunately depending on how R is called ( … you may start to see why ‘box’ takes ~ 100 lines of code to figure out the calling code’s path in all these contexts. |
Yeah, this does look quite messed up, and maybe adding hooks is the best way. With the caveat that people would need to load box on in the main process. I can do this in the next release. You can also submit a PR if you like. Ideally it would be possible to set multiple hooks, so some simple api to do that would suffice I think. E.g. having named hooks (you can prefix the names with No pressure, you can also wait for me to add this, I would guess I would do it in about a month or so. |
I’d be happy to submit a PR. Just to clarify, your idea would be to have the following API: callr::add_hook(
'hook-name',
function() list(name = 'string', …) # list of key-value pairs
) Rather than using the Having a separate function that tells the caller whether they’re inside ‘callr’ would still be useful to have, to allow graceful (though not perfect) handling of situations where ‘box’ wasn’t loaded in the parent process. |
Maybe something like this? callr::add_hook("box::hook" = function() list(options = ..., envvars = ...)) IDK if we should have separate hooks for setting options and env vars, maybe not. IDK if
Yeah. |
I agree, seems like overkill.
It currently does, and in general it should, the API/documentation has no limitations (the API also really only handles setting and getting lists of functions, nothing about calling them, so there’s no reasonable way in which it could put constraints on the functions). On the flip side, the base R API doesn’t allow naming the hooks the way you suggested. Not sure whether that’s useful (it makes removing hooks slightly easier). |
Yeah, I think naming would be important, so let's just put them in a list or env in callr with |
Closed by #203. |
My specific use-case is klmr/box#199. The package ‘box’ needs to figure out which script file it is called from. It uses the script filename on the R command line for this, and since ‘callr’ creates a temporary script path, ‘box’ goes looking for modules in that temporary path, rather than in the (user’s) calling code’s path.
getwd()
does not work, since the working directory is generally unrelated to the script path. Likewisehere::here()
won’t work (in fact, it falls back togetwd()
in the situations I care about).The linked issue shows a workaround, but that requires users to add code to both the caller and the callee. Ideally I’d like to add automatic support for ‘callr’ to ‘box’ but I believe this requires support from ‘callr’.
As far as I can tell ‘callr’ currently has no way of finding the calling script’s path: I can’t find any indication in its environment variables, the command line or the options. In fact, finding the calling script’s path in R is nontrivial (the ‘box’ implementation is ~100 SLOC, and hard-codes special handling for RStudio and for several packages).
I’ll admit that there’s limited usefulness for this outside of this specific case. And to have a solution that doesn’t depend on ‘box’ my suggestion would be to add a user hook for
callr:::run_r
which can modify the command line options being passed to the R subprocess (or the environment variables).If I submitted such a PR, would it be considered for inclusion?
At its simplest, an implementation could look like this:
… But that exposes current implementation details (the presence of
run_r
, and the structure of theoptions
list), and would imply that any future change to them would be a breaking change.The text was updated successfully, but these errors were encountered: