set.sys.path {this.path} | R Documentation |
Implement 'this.path()' For Arbitrary 'source()'-Like Functions
Description
sys.path()
is implemented to work with these functions and
packages:
source()
debugSource
()
in ‘RStudio’box::use()
set.sys.path()
can be used to implement sys.path()
for any
other source()
-like functions.
set.env.path()
and set.src.path()
can be used alongside
set.sys.path()
to implement env.path()
and
src.path()
, thereby fully implementing
this.path()
. Note that set.env.path()
only makes sense
if the code is being modularized, see Examples.
unset.sys.path()
will undo a call to set.sys.path()
. You will
need to use this if you wish to call set.sys.path()
multiple times
within a function.
set.sys.path.function()
is a special variant of set.sys.path()
to be called within callr::r()
on a function with an appropriate
srcref
.
with_sys.path()
is a convenient way to evaluate code within the
context of a file. Whereas set.sys.path()
can only be used within a
function, with_sys.path()
can only be used outside a function.
See ?sys.path(local = TRUE)
which returns the path of the
executing script, confining the search to the local environment in which
set.sys.path()
was called.
wrap.source()
should not be used, save for one specific use-case. See
details.
Usage
set.sys.path(file,
path.only = FALSE,
character.only = path.only,
file.only = path.only,
conv2utf8 = FALSE,
allow.blank.string = FALSE,
allow.clipboard = !file.only,
allow.stdin = !file.only,
allow.url = !file.only,
allow.file.uri = !path.only,
allow.unz = !path.only,
allow.pipe = !file.only,
allow.terminal = !file.only,
allow.textConnection = !file.only,
allow.rawConnection = !file.only,
allow.sockconn = !file.only,
allow.servsockconn = !file.only,
allow.customConnection = !file.only,
ignore.all = FALSE,
ignore.blank.string = ignore.all,
ignore.clipboard = ignore.all,
ignore.stdin = ignore.all,
ignore.url = ignore.all,
ignore.file.uri = ignore.all,
Function = NULL, ofile)
set.env.path(envir, matchThisEnv = getOption("topLevelEnvironment"))
set.src.path(srcfile)
unset.sys.path()
set.sys.path.function(fun)
with_sys.path(file, expr, ...)
wrap.source(expr,
path.only = FALSE,
character.only = path.only,
file.only = path.only,
conv2utf8 = FALSE,
allow.blank.string = FALSE,
allow.clipboard = !file.only,
allow.stdin = !file.only,
allow.url = !file.only,
allow.file.uri = !path.only,
allow.unz = !path.only,
allow.pipe = !file.only,
allow.terminal = !file.only,
allow.textConnection = !file.only,
allow.rawConnection = !file.only,
allow.sockconn = !file.only,
allow.servsockconn = !file.only,
allow.customConnection = !file.only,
ignore.all = FALSE,
ignore.blank.string = ignore.all,
ignore.clipboard = ignore.all,
ignore.stdin = ignore.all,
ignore.url = ignore.all,
ignore.file.uri = ignore.all)
Arguments
expr |
for for |
file |
a
|
path.only |
must |
character.only |
must |
file.only |
must |
conv2utf8 |
if |
allow.blank.string |
may |
allow.clipboard |
may |
allow.stdin |
may |
allow.url |
may |
allow.file.uri |
may |
allow.unz , allow.pipe , allow.terminal , allow.textConnection , allow.rawConnection , allow.sockconn , allow.servsockconn |
may
|
allow.customConnection |
may |
ignore.all , ignore.blank.string , ignore.clipboard , ignore.stdin , ignore.url , ignore.file.uri |
ignore the special meaning of these types of strings, treating it as a path instead? |
Function |
character vector of length |
ofile |
a
|
envir , matchThisEnv |
arguments passed to
|
srcfile |
source file in which to assign a pathname. |
fun |
function with a |
... |
further arguments passed to |
Details
set.sys.path()
should be added to the body of your source()
-like
function before reading / / evaluating the expressions.
wrap.source()
, unlike set.sys.path()
, does not accept an
argument file
. Instead, an attempt is made to extract the file from
expr
, after which expr
is evaluated. It is assumed that the
file is the first argument of the function, as is the case with most
source()
-like functions. The function of the call is evaluated, its
formals()
are retrieved,
and then the arguments of expr
are searched for a name matching the
name of the first formal argument. If a match cannot be found by name, the
first unnamed argument is taken instead. If no such argument exists, the file
is assumed missing.
wrap.source()
does non-standard evaluation and does some guess work to
determine the file. As such, it is less desirable than set.sys.path()
when the option is available. I can think of exactly one scenario in which
wrap.source()
might be preferable: suppose there is a
source()
-like function sourcelike()
in a foreign package (a
package for which you do not have write permission). Suppose that you write
your own function in which the formals are (...)
to wrap
sourcelike()
:
wrapper <- function (...) { ## possibly more args to wrap.source() wrap.source(sourcelike(...)) }
This is the only scenario in which wrap.source()
is preferable, since
extracting the file from the ...
list would be a pain. Then again,
you could simply change the formals of wrapper()
from (...)
to (file, ...)
. If this does not describe your exact scenario, use
set.sys.path()
instead.
Value
for set.sys.path()
, if file
is a path, then the normalized
path with the same attributes, otherwise file
itself. The return value
of set.sys.path()
should be assigned to a variable before use,
something like:
{ file <- set.sys.path(file, ...) sourcelike(file) }
for wrap.source()
, the result of evaluating expr
.
Using 'ofile'
ofile
can be used when the file
argument supplied to
set.sys.path()
is not the same as the file
argument supplied to
the source()
-like function:
sourcelike <- function (file) { ofile <- file if (!is.character(ofile) || length(ofile) != 1) stop(gettextf("'%s' must be a character string", "file")) ## if the file exists, do nothing if (file.exists(file)) { } ## look for the file in the home directory ## if it exists, do nothing else if (file.exists(file <- this.path::path.join("~", ofile))) { } ## you could add other directories to look in, ## but this is good enough for an example else stop(gettextf("'%s' is not an existing file", ofile)) file <- this.path::set.sys.path(file, ofile = ofile) exprs <- parse(n = -1, file = file) for (i in seq_along(exprs)) eval(exprs[i], envir) invisible() }
Examples
FILE.R <- tempfile(fileext = ".R")
this.path:::.writeCode({
this.path::sys.path(verbose = TRUE)
try(this.path::env.path(verbose = TRUE))
this.path::src.path(verbose = TRUE)
this.path::this.path(verbose = TRUE)
}, FILE.R)
## here we have a source-like function, suppose this
## function is in a package for which you have write permission
sourcelike <- function (file, envir = parent.frame())
{
ofile <- file
file <- set.sys.path(file, Function = "sourcelike")
lines <- readLines(file, warn = FALSE)
filename <- sys.path(local = TRUE, for.msg = TRUE)
isFile <- !is.na(filename)
if (isFile) {
timestamp <- file.mtime(filename)[1]
## in case 'ofile' is a URL pathname / / 'unz' connection
if (is.na(timestamp))
timestamp <- Sys.time()
}
else {
filename <- if (is.character(ofile)) ofile else "<connection>"
timestamp <- Sys.time()
}
srcfile <- srcfilecopy(filename, lines, timestamp, isFile)
set.src.path(srcfile)
exprs <- parse(text = lines, srcfile = srcfile, keep.source = FALSE)
invisible(source.exprs(exprs, evaluated = TRUE, envir = envir))
}
sourcelike(FILE.R)
sourcelike(conn <- file(FILE.R)); close(conn)
## here we have another source-like function, suppose this function
## is in a foreign package for which you do not have write permission
sourcelike2 <- function (pathname, envir = globalenv())
{
if (!(is.character(pathname) && file.exists(pathname)))
stop(gettextf("'%s' is not an existing file",
pathname, domain = "R-base"))
envir <- as.environment(envir)
lines <- readLines(pathname, warn = FALSE)
srcfile <- srcfilecopy(pathname, lines, isFile = TRUE)
exprs <- parse(text = lines, srcfile = srcfile, keep.source = FALSE)
invisible(source.exprs(exprs, evaluated = TRUE, envir = envir))
}
## the above function is similar to sys.source(), and it
## expects a character string referring to an existing file
##
## with the following, you should be able
## to use 'sys.path()' within 'FILE.R':
wrap.source(sourcelike2(FILE.R), path.only = TRUE)
# ## with R >= 4.1.0, use the forward pipe operator '|>' to
# ## make calls to 'wrap.source' more intuitive:
# sourcelike2(FILE.R) |> wrap.source(path.only = TRUE)
## 'wrap.source' can recognize arguments by name, so they
## do not need to appear in the same order as the formals
wrap.source(sourcelike2(envir = new.env(), pathname = FILE.R),
path.only = TRUE)
## it it much easier to define a new function to do this
sourcelike3 <- function (...)
wrap.source(sourcelike2(...), path.only = TRUE)
## the same as before
sourcelike3(FILE.R)
## however, this is preferable:
sourcelike4 <- function (pathname, ...)
{
## pathname is now normalized
pathname <- set.sys.path(pathname, path.only = TRUE)
sourcelike2(pathname = pathname, ...)
}
sourcelike4(FILE.R)
## perhaps you wish to run several scripts in the same function
fun <- function (paths, ...)
{
for (pathname in paths) {
pathname <- set.sys.path(pathname, path.only = TRUE)
sourcelike2(pathname = pathname, ...)
unset.sys.path(pathname)
}
}
## here we have a source-like function which modularizes its code
sourcelike5 <- function (file)
{
ofile <- file
file <- set.sys.path(file, Function = "sourcelike5")
lines <- readLines(file, warn = FALSE)
filename <- sys.path(local = TRUE, for.msg = TRUE)
isFile <- !is.na(filename)
if (isFile) {
timestamp <- file.mtime(filename)[1]
## in case 'ofile' is a URL pathname / / 'unz' connection
if (is.na(timestamp))
timestamp <- Sys.time()
}
else {
filename <- if (is.character(ofile)) ofile else "<connection>"
timestamp <- Sys.time()
}
srcfile <- srcfilecopy(filename, lines, timestamp, isFile)
set.src.path(srcfile)
envir <- new.env(hash = TRUE, parent = .BaseNamespaceEnv)
envir$.packageName <- filename
oopt <- options(topLevelEnvironment = envir)
on.exit(options(oopt))
set.env.path(envir)
exprs <- parse(text = lines, srcfile = srcfile, keep.source = FALSE)
source.exprs(exprs, evaluated = TRUE, envir = envir)
envir
}
sourcelike5(FILE.R)
## the code can be made much simpler in some cases
sourcelike6 <- function (file)
{
## we expect a character string refering to a file
ofile <- file
filename <- set.sys.path(file, path.only = TRUE, ignore.all = TRUE,
Function = "sourcelike6")
lines <- readLines(filename, warn = FALSE)
timestamp <- file.mtime(filename)[1]
srcfile <- srcfilecopy(filename, lines, timestamp, isFile = TRUE)
set.src.path(srcfile)
envir <- new.env(hash = TRUE, parent = .BaseNamespaceEnv)
envir$.packageName <- filename
oopt <- options(topLevelEnvironment = envir)
on.exit(options(oopt))
set.env.path(envir)
exprs <- parse(text = lines, srcfile = srcfile, keep.source = FALSE)
source.exprs(exprs, evaluated = TRUE, envir = envir)
envir
}
sourcelike6(FILE.R)
unlink(FILE.R)