Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 5d2e224

Browse filesBrowse files
authored
Merge pull request #3291 from PennSIVE/r-interface
ENH: Interface for R
2 parents 97f2127 + e576c90 commit 5d2e224
Copy full SHA for 5d2e224

File tree

Expand file treeCollapse file tree

3 files changed

+210
-0
lines changed
Filter options
Expand file treeCollapse file tree

3 files changed

+210
-0
lines changed

‎nipype/interfaces/r.py

Copy file name to clipboard
+117Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
# -*- coding: utf-8 -*-
2+
# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: nil -*-
3+
# vi: set ft=python sts=4 ts=4 sw=4 et:
4+
"""Interfaces to run R scripts."""
5+
import os
6+
from shutil import which
7+
8+
from .. import config
9+
from .base import (
10+
CommandLineInputSpec,
11+
InputMultiPath,
12+
isdefined,
13+
CommandLine,
14+
traits,
15+
File,
16+
Directory,
17+
)
18+
19+
20+
def get_r_command():
21+
if "NIPYPE_NO_R" in os.environ:
22+
return None
23+
r_cmd = os.getenv("RCMD", default="R")
24+
25+
return r_cmd if which(r_cmd) else None
26+
27+
28+
no_r = get_r_command() is None
29+
30+
31+
class RInputSpec(CommandLineInputSpec):
32+
"""Basic expected inputs to R interface"""
33+
34+
script = traits.Str(
35+
argstr='-e "%s"', desc="R code to run", mandatory=True, position=-1
36+
)
37+
# non-commandline options
38+
rfile = traits.Bool(True, desc="Run R using R script", usedefault=True)
39+
script_file = File(
40+
"pyscript.R", usedefault=True, desc="Name of file to write R code to"
41+
)
42+
43+
44+
class RCommand(CommandLine):
45+
"""Interface that runs R code
46+
47+
>>> import nipype.interfaces.r as r
48+
>>> r = r.RCommand(rfile=False) # doctest: +SKIP
49+
>>> r.inputs.script = "Sys.getenv('USER')" # doctest: +SKIP
50+
>>> out = r.run() # doctest: +SKIP
51+
"""
52+
53+
_cmd = get_r_command()
54+
input_spec = RInputSpec
55+
56+
def __init__(self, r_cmd=None, **inputs):
57+
"""initializes interface to r
58+
(default 'R')
59+
"""
60+
super(RCommand, self).__init__(**inputs)
61+
if r_cmd and isdefined(r_cmd):
62+
self._cmd = r_cmd
63+
64+
# For r commands force all output to be returned since r
65+
# does not have a clean way of notifying an error
66+
self.terminal_output = "allatonce"
67+
68+
def set_default_r_cmd(self, r_cmd):
69+
"""Set the default R command line for R classes.
70+
71+
This method is used to set values for all R
72+
subclasses.
73+
"""
74+
self._cmd = r_cmd
75+
76+
def set_default_rfile(self, rfile):
77+
"""Set the default R script file format for R classes.
78+
79+
This method is used to set values for all R
80+
subclasses.
81+
"""
82+
self._rfile = rfile
83+
84+
def _run_interface(self, runtime):
85+
self.terminal_output = "allatonce"
86+
runtime = super(RCommand, self)._run_interface(runtime)
87+
if "R code threw an exception" in runtime.stderr:
88+
self.raise_exception(runtime)
89+
return runtime
90+
91+
def _format_arg(self, name, trait_spec, value):
92+
if name in ["script"]:
93+
argstr = trait_spec.argstr
94+
return self._gen_r_command(argstr, value)
95+
return super(RCommand, self)._format_arg(name, trait_spec, value)
96+
97+
def _gen_r_command(self, argstr, script_lines):
98+
"""Generates commands and, if rfile specified, writes it to disk."""
99+
if not self.inputs.rfile:
100+
# replace newlines with ;, strip comments
101+
script = "; ".join(
102+
[
103+
line
104+
for line in script_lines.split("\n")
105+
if not line.strip().startswith("#")
106+
]
107+
)
108+
# escape " and $
109+
script = script.replace('"', '\\"')
110+
script = script.replace("$", "\\$")
111+
else:
112+
script_path = os.path.join(os.getcwd(), self.inputs.script_file)
113+
with open(script_path, "wt") as rfile:
114+
rfile.write(script_lines)
115+
script = "source('%s')" % script_path
116+
117+
return argstr % script
+31Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# AUTO-GENERATED by tools/checkspecs.py - DO NOT EDIT
2+
from ..r import RCommand
3+
4+
5+
def test_RCommand_inputs():
6+
input_map = dict(
7+
args=dict(
8+
argstr="%s",
9+
),
10+
environ=dict(
11+
nohash=True,
12+
usedefault=True,
13+
),
14+
rfile=dict(
15+
usedefault=True,
16+
),
17+
script=dict(
18+
argstr='-e "%s"',
19+
mandatory=True,
20+
position=-1,
21+
),
22+
script_file=dict(
23+
extensions=None,
24+
usedefault=True,
25+
),
26+
)
27+
inputs = RCommand.input_spec()
28+
29+
for key, metadata in list(input_map.items()):
30+
for metakey, value in list(metadata.items()):
31+
assert getattr(inputs.traits()[key], metakey) == value

‎nipype/interfaces/tests/test_r.py

Copy file name to clipboard
+62Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
# -*- coding: utf-8 -*-
2+
# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: nil -*-
3+
# vi: set ft=python sts=4 ts=4 sw=4 et:
4+
import os
5+
6+
import pytest
7+
from nipype.interfaces import r
8+
9+
no_r = r.no_r
10+
11+
12+
@pytest.mark.skipif(no_r, reason="R is not available")
13+
def test_cmdline(tmp_path):
14+
default_script_file = str(tmp_path / "testscript")
15+
ri = r.RCommand(script="1 + 1", script_file=default_script_file, rfile=False)
16+
r_cmd = r.get_r_command()
17+
18+
assert ri.cmdline == r_cmd + (' -e "1 + 1"')
19+
20+
assert ri.inputs.script == "1 + 1"
21+
assert ri.inputs.script_file == default_script_file
22+
assert not os.path.exists(ri.inputs.script_file), "scriptfile should not exist"
23+
assert not os.path.exists(
24+
default_script_file
25+
), "default scriptfile should not exist."
26+
27+
28+
@pytest.mark.skipif(no_r, reason="R is not available")
29+
def test_run_interface(tmpdir):
30+
cwd = tmpdir.chdir()
31+
default_script_file = r.RInputSpec().script_file
32+
33+
rc = r.RCommand(r_cmd="foo_m")
34+
assert not os.path.exists(default_script_file), "scriptfile should not exist 1."
35+
with pytest.raises(ValueError):
36+
rc.run() # script is mandatory
37+
assert not os.path.exists(default_script_file), "scriptfile should not exist 2."
38+
if os.path.exists(default_script_file): # cleanup
39+
os.remove(default_script_file)
40+
41+
rc.inputs.script = "a=1;"
42+
assert not os.path.exists(default_script_file), "scriptfile should not exist 3."
43+
with pytest.raises(IOError):
44+
rc.run() # foo_m is not an executable
45+
assert os.path.exists(default_script_file), "scriptfile should exist 3."
46+
if os.path.exists(default_script_file): # cleanup
47+
os.remove(default_script_file)
48+
cwd.chdir()
49+
50+
51+
@pytest.mark.skipif(no_r, reason="R is not available")
52+
def test_set_rcmd(tmpdir):
53+
cwd = tmpdir.chdir()
54+
default_script_file = r.RInputSpec().script_file
55+
56+
ri = r.RCommand()
57+
_default_r_cmd = ri._cmd
58+
ri.set_default_r_cmd("foo")
59+
assert not os.path.exists(default_script_file), "scriptfile should not exist."
60+
assert ri._cmd == "foo"
61+
ri.set_default_r_cmd(_default_r_cmd)
62+
cwd.chdir()

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.