Using python, if I need the absolute path from the context of the current running script all I need to do is to add the following in the code of that script:
import os
os.path.abspath(__file__)
This is very useful as having the absolute path I can then use os.path.join to form new absolute paths for my project components (inside the project directory tree) and more interesting is that everything will continue to work without any problem no matter where the package directory is moved.
I need to achieve the very same thing using R programming, that is obtaining the absolute path of the current running R script ( = the absolute path of its file on the disk). But trying to do the same in R turns out to be quite challenging, at least for me as a rather beginner in R.
After a lot of googling, I tried to use the reticulate package to call Python from R but __file__ is not available there, then I found a few threads on Stackoverflow suggesting to play with the running Stack and others suggesting the use of normalizePath. However none of these worked for me when the entire project package is transferred from one directory to another.
Therefore, I would like to know if for example you have the following file/directory tree
base_dir ( = /home/usr1/apps/R/base_dir)
|
|
|___ myscript.R (this is my R script to be run)
|___ data (this is a directory)
|___ sql (this is a directory)
Is there any solution allowing to add something in the code of myscript.R so that inside the script the program can always know that the base directory is /home/usr1/apps/R/base_dir and if later this base directory is moved to another directory then there is no need to change the code and the program would be able to find correctly the new base directory?
R has in general no way of finding this path, because there is no equivalent to Python’s __file__ in R.
The closest you can get is to look at commandArgs() and laboriously extract the script filename (which requires different handling depending on how the script was launched!). But this will fail if the script was executed in RStudio, and it will fail after calling setwd().
Other solutions (such as the ‘here’ package) rely on heuristics and specific project structures.
But luckily there’s actually a solution that will always work: use ‘box’ modules.
With modules, you’ll always be able to get the path of the current script/module via box::file(). This is the closest equivalent to Python’s __file__ you’ll get in R, and it always works — as long as you’re using ‘box’ modules consistently.
(Internally the ‘box’ package requires complex logic to determine the value of the file() function in all circumstances; I don’t recommend replicating it, it’s too complex. For the curious, the bulk of the relevant logic is in R/loaded.r.)
If you are running the script using Rscript you can use getwd().
#!/usr/bin/Rscript
getwd()
# or assign it to a variable
base_dir = getwd()
you can run it from the command line using one of the following
./yourscript.R
# or
Rscript yourscript.R
Note however, this only works if you run the script from inside the folder, the file is in.
cd ~
./script.R
# "/home/usr1"
cd /
/home/usr1/script.R
# "/"
For a more elaborate option you could consider https://stackoverflow.com/a/55322344/3250126
I have a module I wrote here:
# Hello.jl
module Hello
function foo
return 1
end
end
and
# Main.jl
using Hello
foo()
When I run the Main module:
$ julia ./Main.jl
I get this error:
ERROR: LoadError: ArgumentError: Hello not found in path
in require at ./loading.jl:249
in include at ./boot.jl:261
in include_from_node1 at ./loading.jl:320
in process_options at ./client.jl:280
in _start at ./client.jl:378
while loading /Main.jl, in expression starting on line 1
There is a new answer to this question since the release of Julia v0.7 and v1.0 that is slightly different. I just had to do this so I figured I'd post my findings here.
As already explained in other solutions, it is necessary to include the relevant script which defines the module. However, since the custom module is not a package, it cannot be loaded as a package with the same using or import commands as could be done in older Julia versions.
So the Main.jl script would be written with a relative import like this:
include("./Hello.jl")
using .Hello
foo()
I found this explained simply in Stefan Karpinski's discourse comment on a similar question. As he describes, the situation can also get more elaborate when dealing with submodules. The documentation section on module paths is also a good reference.
EDIT: Updated code to apply post-v1.0. The other answers still have a fundamental problem: if you define a module and then include that module definition in multiple places, you will get unexpected hard-to-understand errors. #kiliantics' answer is correct as long as you only include the file once. If you have a module that you're using across multiple files, make that module into a package, use add MyModule, and then type using MyModule in as many places as you want, letting Pkg handle module identity for you.
Though 张实唯's answer is the most convenient, you should not use include outside the REPL (or just once per included file as a simple practice to organize large modules, as in the first example here). If you're writing a program file, go through the trouble of adding the appropriate directory to the LOAD_PATH. Remy gives a very good explanation of how to do so, but it's worth also explaining why you should do so in the first place. (Additionally from the docs: push!(LOAD_PATH, "/Path/To/My/Module/") but note your module and your file have to have the same name)
The problem is that anything you include will be defined right where you call include even if it is also defined elsewhere. Since the goal of modules is re-use, you'll probably eventually use MyModule in more than one file. If you call include in each file, then each will have its own definition of MyModule, and even though they are identical, these will be different definitions. That means any data defined in the MyModule (such as data types) will not be the same.
To see why this is a huge problem, consider these three files:
types.jl
module TypeModule
struct A end
export A
end
a_function.jl
include("types.jl")
module AFunctionModule
using ..TypeModule
function takes_a(a::A)
println("Took A!")
end
export takes_a
end
function_caller.jl
include("a_function.jl")
include("types.jl") # delete this line to make it work
using .TypeModule, .AFunctionModule
my_a = A()
takes_a(my_a)
If you run julia function_caller.jl you'll get MethodError: no method matching takes_a(::A). This is because the type A used in function_caller.jl is different from the one used in a_function.jl. In this simple case, you can actually "fix" the problem by reversing the order of the includes in function_caller.jl (or just by deleting include("types.jl") entirely from function_caller.jl! That's not good!). But what if you wanted another file b_function.jl that also used a type defined in TypeModule? You would have to do something very hacky. Or you could just modify your LOAD_PATH so the module is only defined once.
EDIT in response to xji: To distribute a module, you'd use Pkg (docs). I understood the premise of this question to be a custom, personal module. It's also fine for distribution if you know the relative path of the directory containing your module definition from each file that needs to load that module, e.g. if all your files are in the same folder then you'd just have push!(LOAD_PATH, #__DIR__).
Incidentally, if you really don't like the idea of modifying your load path (even if it's only within the scope of a single script...) you could symlink your module into a package directory (e.g. ~/.julia/v0.6/MyModule/MyModule.jl) and then Pkg.add(MyModule) and then import as normal. I find that to be a bit more trouble.
This answer has been OUTDATED. Please see other excellent explanations.
===
You should include("./Hello.jl") before using Hello
This answers was originally written for Julia 0.4.5. There is now an easier way of importing a local file (see #kiliantics answer). However, I will leave this up as my answer explains several other methods of loading files from other directories which may be of use still.
There have already been some short answers, but I wanted to provide a more complete answer if possible.
When you run using MyModule, Julia only searches for it in a list of directories known as your LOAD_PATH. If you type LOAD_PATH in the Julia REPL, you will get something like the following:
2-element Array{ByteString,1}:
"/Applications/Julia-0.4.5.app/Contents/Resources/julia/local/share/julia/site/v0.4"
"/Applications/Julia-0.4.5.app/Contents/Resources/julia/share/julia/site/v0.4"
These are the directories that Julia will search for modules to include when you type using Hello. In the example that you provided, since Hello was not in your LOAD_PATH, Julia was unable to find it.
If you wish to include a local module, you can specify its location relative to your current working directory.
julia> include("./src/Hello.jl")
Once the file has been included, you can then run using Hello as normal to get all of the same behavior. For one off scripts, this is probably the best solution. However, if you find yourself regular having to include() a certain set of directories, you can permanently add them to your LOAD_PATH.
Adding directories to LOAD_PATH
Manually adding directories to your LOAD_PATH can be a pain if you wish to regularly use particular modules that are stored outside of the Julia LOAD_PATH. In that case, you can append additional directories to the LOAD_PATH environment variable. Julia will then automatically search through these directories whenever you issue an import or using command.
One way to do this is to add the following to your .basrc, .profile, .zshrc.
export JULIA_LOAD_PATH="/path/to/module/storage/folder"
This will append that directory onto the standard directories that Julia will search. If you then run
julia> LOAD_PATH
It should return
3-element Array{ByteString,1}:
"/path/to/module/storage/folder"
"/Applications/Julia-0.4.5.app/Contents/Resources/julia/local/share/julia/site/v0.4"
"/Applications/Julia-0.4.5.app/Contents/Resources/julia/share/julia/site/v0.4"
You can now freely run using Hello and Julia will automatically find the module (as long as it is stored underneath /path/to/module/storage/folder.
For more information, take a look at this page from the Julia Docs.
Unless you explicitly load the file (include("./Hello.jl")) Julia looks for module files in directories defined in the LOAD_PATH variable.
See this page.
I have Julia Version 1.4.2 (2020-05-23). Just this using .Hello worked for me.
However, I had to compile the Hello module before just using .Hello. It makes sense for both the defined and using scripts of Hello is on the same file.
Instead, we can define Hello in one file and use it in a different file with include("./Hello.jl");using .Hello
If you want to access function foo when importing the module with "using" you need to add "export foo" in the header of the module.
I am developing a package that exposes an R interface (a bunch of functions to be used interactively) and a command line interface via Rscript. This second one works via a small launcher, for instance, at the command line:
Rscript mylauncher.R arg1 arg2 arg3
would call a function of my package.
I would like to test a couple of command lines from R. Nothing fancy, just make sure that everything runs without errors.
If I test these calls doing in an R source file:
system("Rscript mylauncher.R arg1 arg2 arg3")
How can I be sure that I called the right Rscript? In case there are multiple R installations? (which is actually the case in my setting).
Another approach would be write in the R source file:
source("mylauncher.R")
But I don't see how to specify the command line (I would avoid the trick of overwriting the function commandArgs, because I want to test also the right tokenization of the command line). Does anybody have an idea?
Thanks!
Regarding
How can I be sure that I called the right Rscript? In case there are
multiple R installations?
you would query R RHOME on the command-line and Sys.getenv("R_HOME") from wihthin R.
You then append bin/RScript and should have the Rscript corresponding to your current session. I still design my libraries in such a way that I can call them from R ...
I need to understand an R script. Since I did not use R until now, I try to understand the script step by step. At the beginning of the script command line arguments (input files) are passed with commandArgs(). I know that one can access additional arguments for an R script with commandArgs().
But I just cannot figure out how to run a script with arguments in the interactive mode, so that I can print all variables used in the script later on. For example source("script.R") does not seem to take arguments.
My apologies if I am just not capable of using the right search query...
I think you're misunderstanding the use of commandArgs - it's for getting the arguments supplied when run through the command line... not the interpreter. If you just want to "supply arguments" when sourcing a file then just put those into the global namespace (just create the variables you want to use). Using source is almost just like copying the script and pasting it into the interpreter.
I am creating an R package, and found it useful to break parts of the logic in one file into internal helper functions, which I define in the same file. I have sort of a special case where my function decides which helper function to use via match.fun(). Since they won't be useful to other functions or people, I don't want to put these in separate files, and I don't want to export them.
All my testthat cases pass using test_dir(). When I don't export these functions, my testthat cases fail during R CMD check.
"object 'helperfunction1' of mode 'function' was not found", quote(get(as.character(FUN),
mode = "function", envir = envir)))
After looking at this post, I am able to get things to work if I explicitly export or add export entries to NAMESPACE, but again I don't want to export these.
Is there a better way to do this and doesn't require me to export? (I'll admit that the source of the issue may be match.fun() and am open to other ways of calling functions at runtime.)
From memory it wasn't clear in the documentation last time I read it (it may have changed), but it will work correctly (without having to export) so long as everything is in the right directories:
You should have a file:
tests/run-all.R
That looks like:
library(testthat)
library(myPackage)
test_package("myPackage")
Then your individual test files should be in the directory inst/tests
These will be run when you do R CMD check, otherwise you can call test_package("myPackage") in R manually.