-
Notifications
You must be signed in to change notification settings - Fork 129
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
Metaprogramming Difficulties (vignette potentially helpful) #451
Comments
Glad to hear you are giving This behavior is actually expected. Also, |
Thanks @wlandau, turns out the following worked to solve my immediate problem:
So the trick for people who want to programmatically write expressions for their plans is:
|
Nice! Also keep in mind that you don't have to use the library(drake)
library(glue)
library(rlang)
library(tidyverse)
write_command <- function(cmd, inputs = NULL , outputs = NULL){
inputs <- enexpr(inputs)
outputs <- enexpr(outputs)
expr({
glue_data(
list(
inputs = file_in(!!inputs),
outputs = file_out(!!outputs)
),
!!cmd
) %>%
system
}) %>%
expr_text
}
meta_plan <- tribble(
~cmd, ~inputs, ~outputs,
"echo hi > {outputs}", NULL, "test1.txt",
"cat {inputs} {inputs} > {outputs}", c("x", "y", "test1.txt"), "test2.txt"
)
plan <- tibble(
target = paste0("target_", seq_len(nrow(meta_plan))),
command = pmap_chr(meta_plan, write_command)
) %>%
print
#> # A tibble: 2 x 2
#> target command
#> <chr> <chr>
#> 1 target_1 "{\n glue_data(list(inputs = file_in(NULL), outputs = file_…
#> 2 target_2 "{\n glue_data(list(inputs = file_in(c(\"x\", \"y\", \"test… |
That's awesome, I didn't realize I could write the plan frame outside of |
Thank you for bringing up this useful scenario. I added some new writing to the manual to recap our discussion. |
Looks great! |
Alternatively, you could use library(drake)
library(glue)
library(purrr) # pmap_chr() is particularly useful here.
library(rlang)
library(tidyverse)
# A function that will be called in your commands.
command_function <- function(cmd, inputs, outputs){
glue_data(
list(
inputs = inputs,
outputs = outputs
),
cmd
) %>%
purrr::walk(system)
}
# A function to generate quoted calls to command_function(),
# which in turn contain quoted calls to file_in() and file_out().
write_command <- function(...){
args <- list(...)
args$inputs <- as.call(list(quote(file_in), args$inputs))
args$outputs <- as.call(list(quote(file_out), args$outputs))
c(quote(command_function), args) %>%
as.call() %>%
rlang::expr_text()
}
# Stuff we feed into the commands, with one row per command.
meta_plan <- tribble(
~cmd, ~inputs, ~outputs,
"cat {inputs} > {outputs}", c("in1.txt", "in2.txt"), c("out1.txt", "out2.txt"),
"cat {inputs} {inputs} > {outputs}", c("out1.txt", "out2.txt"), c("out3.txt", "out4.txt")
)
plan <- tibble(
target = paste0("target_", seq_len(nrow(meta_plan))),
command = pmap_chr(meta_plan, write_command)
) %>%
print
#> # A tibble: 2 x 2
#> target command
#> <chr> <chr>
#> 1 target_1 "command_function(cmd = \"cat {inputs} > {outputs}\", inputs =…
#> 2 target_2 "command_function(cmd = \"cat {inputs} {inputs} > {outputs}\",…
writeLines("in1", "in1.txt")
writeLines("in2", "in2.txt")
make(plan)
#> target target_1
#> target target_2 Created on 2018-08-03 by the reprex package (v0.2.0). |
Update: development |
Dynamic files (#1178) may allow you to avoid this sort of metaprogramming. |
Hi drake devs,
I'm really interested in using drake for some of my work. The lab I work in has a pipelining package of our own (https://github.com/Mouse-Imaging-Centre/pydpiper) and a co-worker and I tried briefly to adapt some of this to drake. The bulk of our pipelining software works by running shell commands against tagged input/output files. The package builds a dependency graph using these files and runs them on a variety of clusters. So we sat down to implement this in drake:
A simple example:
This produces:
putting the command in manually as
gives the correct:
Additionally having
file_in
andfile_out
at the toplevel ofdrake_plan
would fix this but then filenames couldn't be generated within the function. This seems to me like it is a problem that could well be solved byrlang
style metaprogramming, but my few obvious attempts failed. For example havingstep
produce aquo
orexpr
and then evaluating it.I think having an example vignette demonstrating how to write abstract pipeline code would be quite helpful.
The text was updated successfully, but these errors were encountered: