this.path {this.path}R Documentation

Determine Script's Filename

Description

this.path() returns the normalized path of the script in which it was written.

this.dir() returns the directory of this.path().

Usage

this.path(verbose = getOption("verbose"), original = FALSE,
          for.msg = FALSE, contents = FALSE, local = FALSE,
          n = 0, envir = parent.frame(n + 1),
          matchThisEnv = getOption("topLevelEnvironment"),
          srcfile = if (n) sys.parent(n) else 0,
          default, else.)

this.dir(verbose = getOption("verbose"), local = FALSE,
         n = 0, envir = parent.frame(n + 1),
         matchThisEnv = getOption("topLevelEnvironment"),
         srcfile = if (n) sys.parent(n) else 0,
         default, else.)

Arguments

verbose

TRUE or FALSE; should the method in which the path was determined be printed?

original

TRUE, FALSE, or NA; should the original or the normalized path be returned? NA means the normalized path will be returned if it has already been forced, and the original path otherwise.

for.msg

TRUE or FALSE; do you want the path for the purpose of printing a diagnostic message / / warning / / error? This will return NA_character_ in most cases where an error would have been thrown.

for.msg = TRUE will ignore original = FALSE, and will use original = NA instead.

contents

TRUE or FALSE; should the contents of the script be returned instead? In ‘Jupyter’, a list of character vectors will be returned, the contents separated into cells. Otherwise, if for.msg is TRUE and the executing script cannot be determined, NULL will be returned. Otherwise, a character vector will be returned. You could use as.character(unlist(this.path(contents = TRUE))) if you require a character vector.

This is intended for logging purposes. This is useful in ‘Rgui’, ‘RStudio’, ‘VSCode’, and ‘Emacs’ when the source document has contents but no path.

local

TRUE or FALSE; should the search for the executing script be confined to the local environment in which set.sys.path() was called?

n

the number of additional generations to go back. By default, this.path() will look for a path based on the srcref of the call to this.path() and the environment in which this.path() was called. This can be changed to be based on the srcref of the call and the calling environment n generations up the stack. See section Argument 'n' for more details.

envir, matchThisEnv

arguments passed to topenv() to determine the top level environment in which to search for an associated path.

srcfile

source file in which to search for a pathname, or an object containing a source file. This includes a source reference, a call, an expression object, or a closure.

default

this value is returned if there is no executing script.

else.

function to apply if there is an executing script. See tryCatch2() for inspiration.

Details

this.path() starts by examining argument srcfile. It looks at the bindings filename and wd to determine the associated file path. Filenames such as "", "clipboard", and "stdin" will be ignored since they do not refer to files. A source file of class "srcfilecopy" in which binding isFile is FALSE will also be ignored. A source file of class "srcfilealias" will use the aliased filename in determining the associated path.

If it does not find a path associated with srcfile, it will next examine arguments envir and matchThisEnv. Specifically, it calculates topenv(envir, matchThisEnv) then looks for an associated path. It will find a path associated with the top level environment in two ways:

If it does not find an associated path with envir and matchThisEnv, it will next examine the call stack looking for a source call; a call to one of these functions:

If a source call is found, the file argument is returned from the function's evaluation environment. If you have your own source()-like function that you would like to be recognized by this.path(), please use set.sys.path() or contact the package maintainer so that it can be implemented.

If no source call is found up the calling stack, it will next examine the GUI in use. If R is running from:

a shell, such as the Windows command-line / / Unix terminal

then the shell arguments are searched for -f FILE or --file=FILE (the two methods of taking input from FILE) (-f - and --file=- are ignored). The last FILE is extracted and returned. If no arguments of either type are supplied, an error is thrown.

If R is running from a shell under a Unix-alike with -g Tk or --gui=Tk, an error is thrown. ‘Tk’ does not make use of its -f FILE, --file=FILE arguments.

‘Rgui’

then the source document's filename (the document most recently interacted with) is returned (at the time of evaluation). Please note that minimized documents WILL be included when looking for the most recently used document. It is important to not leave the current document (either by closing the document or interacting with another document) while any calls to this.path() have yet to be evaluated in the run selection. If no documents are open or the source document does not exist (not saved anywhere), an error is thrown.

RStudio

then the active document's filename (the document in which the cursor is active) is returned (at the time of evaluation). If the active document is the R console, the source document's filename (the document open in the current tab) is returned (at the time of evaluation). Please note that the source document will NEVER be a document open in another window (with the Show in new window button). Please also note that an active document open in another window can sometimes lose focus and become inactive, thus returning the incorrect path. It is best NOT to not run R code from a document open in another window. It is important to not leave the current tab (either by closing or switching tabs) while any calls to this.path() have yet to be evaluated in the run selection. If no documents are open or the source document does not exist (not saved anywhere), an error is thrown.

VSCode

then the source document's filename is returned (at the time of evaluation). It is important to not leave the current tab (either by closing or switching tabs) while any calls to this.path() have yet to be evaluated in the run selection. If no documents are open or the source document does not exist (not saved anywhere), an error is thrown.

Jupyter

then the source document's filename is guessed by looking for R notebooks in the initial working directory, then searching the contents of those files for an expression matching the top-level expression. Please be sure to save your notebook before using this.path(), or explicitly use set.jupyter.path().

Emacs

then the source document's filename is returned (at the time of evaluation). ‘Emacs’ must be running as a server, either by running (server-start) (consider adding to your ‘~/.emacs’ file) or typing M-x server-start. It is important to not leave the current window (either by closing or switching buffers) while any calls to this.path() have yet to be evaluated in the run selection. If multiple frames are active, this.path() will pick the first frame containing the corresponding R session.

If multiple ‘Emacs’ sessions are active, this.path() will only work in the primary session due to limitations in

‘emacsclient’. If you want to run multiple R sessions, it is better to run one ‘Emacs’ session with multiple frames, one R session per frame. Use M-x make-frame to make a new frame, or C-x 5 f to visit a file in a new frame.

Additionally, never use C-c C-b to send the current buffer to the R process. This copies the buffer contents to a new file which is then source()-ed. The source references now point to the wrong file. Instead, use C-x h to select the entire buffer then C-c C-r to evaluate the selection.

‘AQUA’

then the executing script's path cannot be determined. Unlike ‘Rgui’, ‘RStudio’, ‘VSCode’, ‘Jupyter’, and ‘Emacs’, there is currently no way to request the path of an open document. Until such a time that there is a method for requesting the path of an open document, consider using another GUI.

If R is running in another manner, an error is thrown.

If your GUI of choice is not implemented with this.path(), please contact the package maintainer so that it can be implemented.

Value

character string.

Argument 'n'

By default, this.path() will look for a path based on the srcref of the call to this.path() and the environment in which this.path() was called. For example:

{
#line 1 "file1.R"
fun <- function() this.path::this.path(original = TRUE)
fun()
}


{
#line 1 "file2.R"
fun()
}

Both of these will return "file1.R" because that is where the call to this.path() is written.

But suppose we do not care where this.path() is called, but instead want to know where fun() is called. Pass argument n = 1 to do so; this.path() will inspect the call and the calling environment one generation up the stack:

{
#line 1 "file1.R"
fun <- function() this.path::this.path(original = TRUE, n = 1)
fun()
}


{
#line 1 "file2.R"
fun()
}

These will return "file1.R" and "file2.R", respectively, because those are where the calls to fun() are written.

But now suppose we wish to make a second function that uses fun(). We do not care where fun() is called, but instead want to know where fun2() is called. Add a formal argument n = 0 to each function and pass n = n + 1 to each sub-function:

{
#line 1 "file1.R"
fun <- function(n = 0) {
    this.path::this.path(original = TRUE, n = n + 1)
}
fun()
}


{
#line 1 "file2.R"
fun2 <- function(n = 0) fun(n = n + 1)
list(fun = fun(), fun2 = fun2())
}


{
#line 1 "file3.R"
fun3 <- function(n = 0) fun2(n = n + 1)
list(fun = fun(), fun2 = fun2(), fun3 = fun3())
}

Within each file, all these functions will return the path in which they are called, regardless of how deep this.path() is called.

Note

If you need to use this.path() inside a user profile, please use with_init.file(). i.e. instead of writing:

<expr 1>
<expr 2>
<...>

write this:

this.path::with_init.file({
<expr 1>
<expr 2>
<...>
})

See Also

shFILE()

set.sys.path()

Examples

FILE1.R <- tempfile(fileext = ".R")
writeLines("writeLines(sQuote(this.path::this.path()))", FILE1.R)

## 'this.path()' works with 'source()'
source(FILE1.R)

## 'this.path()' works with 'sys.source()'
sys.source(FILE1.R, envir = environment())

## 'this.path()' works with 'debugSource()' in 'RStudio'
if (.Platform$GUI == "RStudio")
    get("debugSource", "tools:rstudio", inherits = FALSE)(FILE1.R)

## 'this.path()' works with 'testthat::source_file()'
if (requireNamespace("testthat"))
    testthat::source_file(FILE1.R, chdir = FALSE, wrap = FALSE)

## 'this.path()' works with 'compiler::loadcmp()'
if (requireNamespace("compiler")) {
    FILE2.Rc <- tempfile(fileext = ".Rc")
    compiler::cmpfile(FILE1.R, FILE2.Rc)
    compiler::loadcmp(FILE2.Rc)
    unlink(FILE2.Rc)
}

## 'this.path()' works with 'Rscript'
this.path:::.Rscript(c("--default-packages=NULL", "--vanilla", FILE1.R))

## 'this.path()' also works when 'source()'-ing a URL
## (included tryCatch in case an internet connection is not available)
tryCatch({
    source(paste0("https://raw.githubusercontent.com/ArcadeAntics/",
                  "this.path/main/tests/sys-path-with-urls.R"))
}, condition = this.path:::.cat_condition)

unlink(FILE1.R)

[Package this.path version 2.4.0 Index]