
Resolve the input data path for the current execution context
Source:R/resolve-input-path.R
resolve_input_path.RdPicks an input file path according to where the code is running, then checks that the result is usable and explains what went wrong when it is not. It is the pattern this family of packages recommends everywhere, packaged so that it lives in one place rather than being retyped into every document.
Usage
resolve_input_path(
interactive = NULL,
quarto = NULL,
rscript = NULL,
must_exist = TRUE,
context = detect_execution_context()
)Arguments
- interactive
The path to use in an interactive session. Typically the local development copy of the data. If not supplied, falls back to the document's own
params$input_file, when the document declares one.- quarto
The path to use while Quarto renders the document. Normally
params$input_file, which is also what is used when this argument is not supplied.- rscript
The path to use under
Rscript, normally the first command line argument. Defaults to exactly that.- must_exist
Logical. Whether to check that the resolved path exists on disk. Defaults to
TRUE. Set it toFALSEwhen the path is a URL, a database handle, or anything elsefs::file_exists()cannot see.- context
Character. The execution context to resolve for, one of
"interactive","quarto", or"rscript". Defaults todetect_execution_context(). Supply it directly in tests, or when the caller has already computed it and does not want a second call.
Value
A single character string: the resolved path. In the
interactive and quarto contexts, a relative path is returned
joined to the project root (see the section below).
Details
Each of the three arguments is an ordinary R argument and therefore a
promise, so only the branch matching context is ever evaluated. Under
Rscript, where params does not exist, passing
quarto = params$input_file is safe because that expression is never
forced.
The reason this is a function rather than a documented switch() follows
from the same mechanism. When a branch is selected and its expression
fails, the failure happens inside this function, where it can be caught
and explained. A document that declares no params: block raises
object 'params' not found, which says nothing about YAML headers; a
hand-written switch() in the document evaluates that expression in the
document's own frame, where nothing is in a position to intercept it.
The three ways a branch produces something unusable, and what this function says about each:
Under
Rscriptwith no argument passed,commandArgs(trailingOnly = TRUE)[1]isNA_character_. Reading that produces an error aboutNArather than about a missing argument.Under Quarto,
paramsexists only if the YAML header declares it, andparams$input_fileisNULLif the block exists without that key.In any context, the resolved path may simply not be there, which is most often a working directory that is not what the author assumed.
Relative paths start at the project root
In the interactive and quarto contexts, a relative path such as
"data-raw/sample.csv" is read from the project root, the same rule
here::here() follows, not from the working directory. So a document
under reports/ can declare input_file: data-raw/sample.csv in its
header and find the file whether it is rendered (Quarto runs the code
in reports/) or run chunk by chunk in RStudio. The root is the
nearest folder above the working directory carrying a project marker:
the .here file init_project() writes, an .Rproj file, or a .git
folder. For documents written before this rule, a path that exists
relative to the working directory but not from the root is still used
as it is.
The rscript context is left alone. On an HTCondor execute node the
path arrives as a command line argument that already points at the file:
an absolute path to data baked into the image, or a bare subset file
name in the job's scratch directory.
See also
detect_execution_context(), which decides the branch.
Examples
# Resolving for a named context. must_exist = FALSE because there is no
# such file here; in a real document you want the default.
resolve_input_path(
rscript = "data-raw/sample.csv",
context = "rscript",
must_exist = FALSE
)
#> [1] "data-raw/sample.csv"
if (FALSE) { # \dontrun{
# A path per context, which is what a scaffolded document shows. Only
# the branch matching the current context is evaluated, so the params
# reference is safe under Rscript, where params does not exist.
input_file <- resolve_input_path(
interactive = "data-raw/sample.csv",
quarto = params$input_file,
rscript = commandArgs(trailingOnly = TRUE)[1]
)
# The defaults cover the mechanical branch and fall back to the
# document's own params for the other two, so a document whose YAML
# header declares input_file needs no arguments at all.
input_file <- resolve_input_path()
} # }