R/resource_projects.R

Defines functions unitar_list tar_list source_target_functions build_pep_resource_targets tar_pep_foreach build_pep_resource_targets_prj build_pep_resource_targets_prj_old load_custom load_custom_old track_external_target load_external_file

Documented in build_pep_resource_targets build_pep_resource_targets_prj build_pep_resource_targets_prj_old load_custom load_custom_old load_external_file source_target_functions tar_list tar_pep_foreach track_external_target unitar_list

#' Helper function to build target functions to track and read files
#' 
#' This is a target factory that will produce a target to track
#' a file, and then to read that file using an arbitrary function
#' provided by the user.
#' 
#' @param sample_name Name of the target
#' @param rootpath Path to where resource files are kept
#' @param filepath Relative path to file
#' @param func Function to use to load file in R
#' @export
#' 
load_external_file = function(sample_name, rootpath, filepath, func) {
  fullpath = paste0(rootpath, filepath)
  name_file = paste0(sample_name, "_file")
  command_data = substitute(func(fullpath), env=list(fullpath=as.symbol(name_file), func=as.symbol(func)))

  list(
    tar_target_raw(name_file, fullpath, format = "file"),
    tar_target_raw(sample_name, command_data)
  )  
}


#' Experimental target factory to track but not duplicate external files.
#'
#' EXPERIMENTAL. This function is just a concept that has not been tested.
#' It will change or disappear in future versions.
#' @export
track_external_target = function(tname, ext_tname, func) {
  fullpath = unitar_path(ext_tname)
  name_file = paste0(sample_name, "_file")
  command_data = substitute(func(fullpath), env=list(fullpath=as.symbol(name_file), func=as.symbol(func)))

  list(
    tar_target_raw(name_file, fullpath, format = "file"),
    tar_target_raw(tname, command_data)
  )  
}


#' Helper function to build targets from function calls with custom args
#' 
#' This function is a target factory that will produce a target for an
#' arbitrary function call with arbitrary arguments and values.
#' 
#' @param tname Target name
#' @param func Function to call
#' @param argnames List of arg names
#' @param argvals List of arg values
#' @param argtypes List of arg types (use 'symbol' for targets)
load_custom_old = function(tname, func, argvals, argtypes, argnames) {
  l = as.list(argvals)
  names(l) = argnames
  l[argtypes == "symbol"] = lapply(l[argtypes == "symbol"], as.symbol)
  l[argtypes == "numeric"] = lapply(l[argtypes == "numeric"], as.numeric) 
  args_expr = as.call(c(as.symbol("list"), l))
  command_data = substitute(
    do.call(func, args),
    env = list(args = args_expr, func = as.symbol(func))
  )
  tar_target_raw(tname, command_data)
}


# This version adds support for argtypes=file
#' Helper function to build targets from function calls with custom args
#' 
#' This function is a target factory that will produce a target for an
#' arbitrary function call with arbitrary arguments and values.
#' 
#' @param tname Target name
#' @param func Function to call
#' @param argvals List of arg values
#' @param argtypes List of arg types (use 'symbol' for targets)
#' @param argnames List of arg names
#' @export
load_custom = function(tname, func, argvals, argtypes, argnames=NULL) {
  l = as.list(argvals)
  # if (!is.null(argnames)) {
    names(l) = argnames
  # }

  # First, handle function calls that have file paths as argument:
  # 1. Add a file tracking target, with _fileX appended to the target name
  # 2. Adjust the argument to be a symbol with appropriate target name
  nFiles = length(l[argtypes == "file"])
  targets_list = list()
  for (i in seq_len(nFiles)) {
    path = l[argtypes == "file"][i]
    tname_file = paste0(tname, "_file", i)
    targets_list = append(targets_list, 
        tar_target_raw(tname_file, path, format="file"))
    l[argtypes == "file"][i] = tname_file  
    argtypes[argtypes == "file"][i] = "symbol"
  }

  # Next, handle all other argument types.
  l[argtypes == "symbol"] = lapply(l[argtypes == "symbol"], as.symbol)
  l[argtypes == "numeric"] = lapply(l[argtypes == "numeric"], as.numeric) 
  args_expr = as.call(c(as.symbol("list"), l))
  command_data = substitute(
    do.call(func, args),
    env = list(args = args_expr, func = as.symbol(func))
  )
  targets_list = append(targets_list, tar_target_raw(tname, command_data))
  targets_list
}




#' Target factory to build targets from a PEP
#' 
#' @param p PEP defining targets to build
build_pep_resource_targets_prj_old = function(p) {
  tbl = sampleTable(p)
  loadable_targets = list()
  i=1
  for (i in 1:nrow(tbl)) {
    if (tbl[[i, "type"]] == "file") {
      loadable_targets[[i]] = load_external_file(tbl[[i, "sample_name"]],
                                     config(p)$data_root,
                                     tbl[[i, "local_path"]],
                                     tbl[[i, "function"]])
    } else if (tbl[[i, "type"]] == "call") {
      loadable_targets[[i]] = load_custom(tbl[[i, "sample_name"]],
                                       tbl[[i, "function"]],
                                       tbl[[i, "argval"]],
                                       tbl[[i, "argtype"]],
                                       tbl[[i, "argname"]]
                                    )
    }
  }
  return(loadable_targets)
}


#' Target factory to build targets from a PEP
#' 
#' @param p PEP defining targets to build
#' @export
build_pep_resource_targets_prj = function(p) {
  tbl = sampleTable(p)
  loadable_targets = list()
  i=1
  for (i in 1:nrow(tbl)) {
      loadable_targets[[i]] = load_custom(tbl[[i, "sample_name"]],
                                       tbl[[i, "function"]],
                                       pepr::.expandPath(tbl[[i, "argval"]]),
                                       tbl[[i, "argtype"]],
                                       tbl[[i, "argname"]]
                                    )
  }
  return(loadable_targets)
}

#' Target factory for arbitrary functions on PEP samples
#' 
#' This target factory creates a target for each element of a PEP. You can
#' name the targets using a pattern that uses brackets to indicate sample
#' attributes, like `{sample_name}`.
#' 
#' @param p PEP.
#' @param tpattern Target name, with patterns allowed
#' @param func Function to call
#' @param argvals_pattern List of arg values, with patterns allowed
#' @param argtypes List of arg types (use 'symbol' for targets)
#' @param argnames List of arg names
#' @param combine_tname Target name for a combined target that merges all of the individual targets
#' @param combine_func_name Character vector of a function that will combine them.
#' 
#' @export
tar_pep_foreach = function(p, tpattern, func, argvals_pattern, argtypes, argnames=NULL,
  combine_tname=NULL, combine_func_name="list") {
  tbl = sampleTable(p)
  loadable_targets = list() 
  for (i in 1:nrow(tbl)) {
    tname = with(tbl[i,], glue::glue(tpattern))
    argvals = sapply(argvals_pattern, function(x) {
      with(tbl[i,], glue::glue(x))
    })
    loadable_targets[[tname]] = unitar::load_custom(tname, func, argvals, argtypes, argnames)
  }
  tnames = names(loadable_targets)
  
  if (!is.null(combine_tname)) {
     loadable_targets[[length(loadable_targets)+1]] = unitar::load_custom(
       combine_tname, combine_func_name, tnames, rep("symbol", length(tnames)), tnames) 
  }
  return(loadable_targets)
}




#' Target factory to build targets from a PEP
#' 
#' @param config Path to PEP config file
#' @export
build_pep_resource_targets = function(config) {
  p = pepr::Project("config.yaml")
  return(build_pep_resource_targets_prj(p))
}


#' Helper function to load target-creation functions from PEP config
#' 
#' This function simple sources the target functions specified in
#' a 'target_load_functions' attribute of a PEP. It's meant to be
#' called from a _targets.R file, so you don't have to source those
#' scripts individually, but can consolidate the configuration into
#' the PEP config file.
#' @param config Path to the PEP config file for the resource targets list.
#' @export
source_target_functions = function(config) {
  p = pepr::Project("config.yaml")

  # The config should have a pointer to source files:
  tf = config(p)$target_load_functions
  for (i in 1:length(tf)) {
    source(tf[[i]], local=parent.frame())
  }
}

#' List the targets available for loading
#' 
#' This function is useful for resource projects, where you want to see
#' what you have available. It's just a simple wrapper that provides
#' some sensible defaults to \code{tar_meta} for this use case.
#' In the future I'd like it if this included a text description of the target
#' @param n Number of targets to print (with sensible default)
#' @param fields Fields passed to tar_meta (with sensible default)
#' @param ... Any other arguments to pass to tar_meta
#' @export
tar_list = function(n=50, fields=c("name", "time", "bytes"), ...) {
  print(tar_meta(targets_only=TRUE, fields=fields, ...), n=n)
  invisible()
}

#' List all targets available across all projects
#' 
#' If you have available targets from multiple projects, you might be
#' interested in a quick look at them to see what you have available to load.
#' This function just wraps tar_meta with a few defaults that are convenient
#' for this purpose: it increase the default number of targets shown, and
#' reduces the number of fields. It also runs it across all registered targets
#' projects.
#' @param n Number of targets to print (with sensible default)
#' @param fields Fields passed to tar_meta (with sensible default)
#' @param tar_dirs Target directories to search. NULL will use global option (the default).
#' @param ... Any other arguments to pass to tar_meta
#' @export
unitar_list = function(n=50, fields=c("name", "time", "bytes"), tar_dirs=NULL, ...) {
  unitar_exec(func=tar_list, tar_dirs=tar_dirs)
}
databio/unitar documentation built on May 21, 2021, 11:25 p.m.