From 931a766bba6361afd44daa2d15ddfae3a49c49a9 Mon Sep 17 00:00:00 2001 From: Tim Date: Mon, 11 Jan 2021 00:33:58 -0500 Subject: [PATCH 01/18] interface for R mostly a copy-paste of the matlab interface --- nipype/interfaces/r.py | 129 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 129 insertions(+) create mode 100644 nipype/interfaces/r.py diff --git a/nipype/interfaces/r.py b/nipype/interfaces/r.py new file mode 100644 index 0000000000..37010853d8 --- /dev/null +++ b/nipype/interfaces/r.py @@ -0,0 +1,129 @@ +# -*- coding: utf-8 -*- +# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: nil -*- +# vi: set ft=python sts=4 ts=4 sw=4 et: +"""Interfaces to run R scripts.""" +import os + +from .. import config +from .base import ( + CommandLineInputSpec, + InputMultiPath, + isdefined, + CommandLine, + traits, + File, + Directory, +) + + +def get_r_command(): + if "NIPYPE_NO_R" in os.environ: + return None + try: + r_cmd = os.environ["RCMD"] + except: + r_cmd = "R" + return r_cmd + + +no_r = get_r_command() is None + + +class RInputSpec(CommandLineInputSpec): + """ Basic expected inputs to R interface """ + + script = traits.Str( + argstr='-e "%s"', desc="R code to run", mandatory=True, position=-1 + ) + # non-commandline options + rfile = traits.Bool(True, desc="Run R using R script", usedefault=True) + script_file = File( + "pyscript.R", usedefault=True, desc="Name of file to write R code to" + ) + + +class RCommand(CommandLine): + """Interface that runs R code + + >>> import nipype.interfaces.r as r + >>> r = r.RCommand(rfile=False) # don't write script file + >>> r.inputs.script = "Sys.getenv('USER')" + >>> out = r.run() # doctest: +SKIP + """ + + _cmd = "R" + _default_r_cmd = None + _default_rfile = None + input_spec = RInputSpec + + def __init__(self, r_cmd=None, **inputs): + """initializes interface to r + (default 'R') + """ + super(RCommand, self).__init__(**inputs) + if r_cmd and isdefined(r_cmd): + self._cmd = r_cmd + elif self._default_r_cmd: + self._cmd = self._default_r_cmd + + if self._default_rfile and not isdefined(self.inputs.rfile): + self.inputs.rfile = self._default_rfile + + # For r commands force all output to be returned since r + # does not have a clean way of notifying an error + self.terminal_output = "allatonce" + + @classmethod + def set_default_r_cmd(cls, r_cmd): + """Set the default R command line for R classes. + + This method is used to set values for all R + subclasses. However, setting this will not update the output + type for any existing instances. For these, assign the + .inputs.r_cmd. + """ + cls._default_r_cmd = r_cmd + + @classmethod + def set_default_rfile(cls, rfile): + """Set the default R script file format for R classes. + + This method is used to set values for all R + subclasses. However, setting this will not update the output + type for any existing instances. For these, assign the + .inputs.rfile. + """ + cls._default_rfile = rfile + + def _run_interface(self, runtime): + self.terminal_output = "allatonce" + runtime = super(RCommand, self)._run_interface(runtime) + if "R code threw an exception" in runtime.stderr: + self.raise_exception(runtime) + return runtime + + def _format_arg(self, name, trait_spec, value): + if name in ["script"]: + argstr = trait_spec.argstr + return self._gen_r_command(argstr, value) + return super(RCommand, self)._format_arg(name, trait_spec, value) + + def _gen_r_command(self, argstr, script_lines): + """ Generates commands and, if rfile specified, writes it to disk.""" + if not self.inputs.rfile: + # replace newlines with ;, strip comments + script = "; ".join([ + line + for line in script_lines.split("\n") + if not line.strip().startswith("#") + ]) + # escape " and $ + script = script.replace('"','\\"') + script = script.replace('$','\\$') + else: + script_path = os.path.join(os.getcwd(), self.inputs.script_file) + with open(script_path, "wt") as rfile: + rfile.write(script_lines) + script = "source('%s')" % script_path + + return argstr % script From b3361325022c591a86f09579a24234457a269b47 Mon Sep 17 00:00:00 2001 From: Tim Robert-Fitzgerald Date: Thu, 27 May 2021 23:18:44 -0400 Subject: [PATCH 02/18] return None if R can't be found Co-authored-by: Chris Markiewicz --- nipype/interfaces/r.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/nipype/interfaces/r.py b/nipype/interfaces/r.py index 37010853d8..06ee212644 100644 --- a/nipype/interfaces/r.py +++ b/nipype/interfaces/r.py @@ -19,11 +19,9 @@ def get_r_command(): if "NIPYPE_NO_R" in os.environ: return None - try: - r_cmd = os.environ["RCMD"] - except: - r_cmd = "R" - return r_cmd + r_cmd = os.getenv("RCMD", default="R") + + return r_cmd if which(r_cmd) else None no_r = get_r_command() is None From 2638489e2c02dff35fc583306a6c93e0bc5a3b1c Mon Sep 17 00:00:00 2001 From: Tim Robert-Fitzgerald Date: Thu, 27 May 2021 23:19:20 -0400 Subject: [PATCH 03/18] remove hardcoded variable Co-authored-by: Chris Markiewicz --- nipype/interfaces/r.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nipype/interfaces/r.py b/nipype/interfaces/r.py index 06ee212644..c9fd51b392 100644 --- a/nipype/interfaces/r.py +++ b/nipype/interfaces/r.py @@ -49,7 +49,7 @@ class RCommand(CommandLine): >>> out = r.run() # doctest: +SKIP """ - _cmd = "R" + _cmd = get_r_command() _default_r_cmd = None _default_rfile = None input_spec = RInputSpec From f7cb9b2f6d2e9607d5cc2670856d6227ce0d208e Mon Sep 17 00:00:00 2001 From: Terf Date: Thu, 27 May 2021 23:20:06 -0400 Subject: [PATCH 04/18] R interface tests --- nipype/interfaces/tests/test_r.py | 100 ++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100644 nipype/interfaces/tests/test_r.py diff --git a/nipype/interfaces/tests/test_r.py b/nipype/interfaces/tests/test_r.py new file mode 100644 index 0000000000..a851e4df6b --- /dev/null +++ b/nipype/interfaces/tests/test_r.py @@ -0,0 +1,100 @@ +# -*- coding: utf-8 -*- +# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: nil -*- +# vi: set ft=python sts=4 ts=4 sw=4 et: +import os + +import pytest +import nipype.interfaces.r as r + +r_cmd = r.get_r_command() +no_r = r_cmd is None +if not no_r: + r.RCommand.set_default_r_cmd(r_cmd) + + +def clean_workspace_and_get_default_script_file(): + # Make sure things are clean. + default_script_file = r.RInputSpec().script_file + if os.path.exists(default_script_file): + os.remove( + default_script_file + ) # raise Exception('Default script file needed for tests; please remove %s!' % default_script_file) + return default_script_file + + +@pytest.mark.skipif(no_r, reason="R is not available") +def test_cmdline(): + default_script_file = clean_workspace_and_get_default_script_file() + + ri = r.RCommand(script="1 + 1", script_file="testscript", rfile=False) + + assert ri.cmdline == r_cmd + ( + ' -e "1 + 1"' + ) + + assert ri.inputs.script == "1 + 1" + assert ri.inputs.script_file == "testscript" + assert not os.path.exists(ri.inputs.script_file), "scriptfile should not exist" + assert not os.path.exists( + default_script_file + ), "default scriptfile should not exist." + +@pytest.mark.skipif(no_r, reason="R is not available") +def test_r_init(): + default_script_file = clean_workspace_and_get_default_script_file() + + assert r.RCommand._cmd == "R" + assert r.RCommand.input_spec == r.RInputSpec + + assert r.RCommand().cmd == r_cmd + rc = r.RCommand(r_cmd="foo_m") + assert rc.cmd == "foo_m" + + +@pytest.mark.skipif(no_r, reason="R is not available") +def test_run_interface(tmpdir): + default_script_file = clean_workspace_and_get_default_script_file() + + rc = r.RCommand(r_cmd="foo_m") + assert not os.path.exists(default_script_file), "scriptfile should not exist 1." + with pytest.raises(ValueError): + rc.run() # script is mandatory + assert not os.path.exists(default_script_file), "scriptfile should not exist 2." + if os.path.exists(default_script_file): # cleanup + os.remove(default_script_file) + + rc.inputs.script = "a=1;" + assert not os.path.exists(default_script_file), "scriptfile should not exist 3." + with pytest.raises(IOError): + rc.run() # foo_m is not an executable + assert os.path.exists(default_script_file), "scriptfile should exist 3." + if os.path.exists(default_script_file): # cleanup + os.remove(default_script_file) + + cwd = tmpdir.chdir() + + # bypasses ubuntu dash issue + rc = r.RCommand(script="foo;", rfile=True) + assert not os.path.exists(default_script_file), "scriptfile should not exist 4." + with pytest.raises(RuntimeError): + rc.run() + assert os.path.exists(default_script_file), "scriptfile should exist 4." + if os.path.exists(default_script_file): # cleanup + os.remove(default_script_file) + + # bypasses ubuntu dash issue + res = r.RCommand(script="a=1;", rfile=True).run() + assert res.runtime.returncode == 0 + assert os.path.exists(default_script_file), "scriptfile should exist 5." + cwd.chdir() + + +@pytest.mark.skipif(no_r, reason="R is not available") +def test_set_rcmd(): + default_script_file = clean_workspace_and_get_default_script_file() + + ri = r.RCommand() + ri.set_default_r_cmd("foo") + assert not os.path.exists(default_script_file), "scriptfile should not exist." + assert ri._default_r_cmd == "foo" + ri.set_default_r_cmd(r_cmd) From 0dcf413071ae0d868ac60cd9ecb553d3a5c4e668 Mon Sep 17 00:00:00 2001 From: Tim Robert-Fitzgerald Date: Mon, 31 May 2021 19:19:41 -0400 Subject: [PATCH 05/18] Update nipype/interfaces/r.py Co-authored-by: Chris Markiewicz --- nipype/interfaces/r.py | 1 + 1 file changed, 1 insertion(+) diff --git a/nipype/interfaces/r.py b/nipype/interfaces/r.py index c9fd51b392..d9507b2f94 100644 --- a/nipype/interfaces/r.py +++ b/nipype/interfaces/r.py @@ -3,6 +3,7 @@ # vi: set ft=python sts=4 ts=4 sw=4 et: """Interfaces to run R scripts.""" import os +from shutil import which from .. import config from .base import ( From 190b6f43a43cffed8bca9387a0d6d859570041af Mon Sep 17 00:00:00 2001 From: Tim Robert-Fitzgerald Date: Mon, 31 May 2021 19:20:07 -0400 Subject: [PATCH 06/18] Update nipype/interfaces/tests/test_r.py Co-authored-by: Chris Markiewicz --- nipype/interfaces/tests/test_r.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nipype/interfaces/tests/test_r.py b/nipype/interfaces/tests/test_r.py index a851e4df6b..52878f78d1 100644 --- a/nipype/interfaces/tests/test_r.py +++ b/nipype/interfaces/tests/test_r.py @@ -4,7 +4,7 @@ import os import pytest -import nipype.interfaces.r as r +from nipype.interfaces import r r_cmd = r.get_r_command() no_r = r_cmd is None From 02104a75a75784685774c3932371ceaaf4f4a67d Mon Sep 17 00:00:00 2001 From: Tim Robert-Fitzgerald Date: Mon, 31 May 2021 19:20:33 -0400 Subject: [PATCH 07/18] Update nipype/interfaces/tests/test_r.py Co-authored-by: Chris Markiewicz --- nipype/interfaces/tests/test_r.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/nipype/interfaces/tests/test_r.py b/nipype/interfaces/tests/test_r.py index 52878f78d1..a8a36ad3f0 100644 --- a/nipype/interfaces/tests/test_r.py +++ b/nipype/interfaces/tests/test_r.py @@ -6,8 +6,7 @@ import pytest from nipype.interfaces import r -r_cmd = r.get_r_command() -no_r = r_cmd is None +no_r = r.no_r if not no_r: r.RCommand.set_default_r_cmd(r_cmd) From 6fcf05b89e70b602aacdb7eb7128dcbaabbf09d9 Mon Sep 17 00:00:00 2001 From: Tim Robert-Fitzgerald Date: Mon, 31 May 2021 19:22:01 -0400 Subject: [PATCH 08/18] Update nipype/interfaces/tests/test_r.py Co-authored-by: Chris Markiewicz --- nipype/interfaces/tests/test_r.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/nipype/interfaces/tests/test_r.py b/nipype/interfaces/tests/test_r.py index a8a36ad3f0..10f42302b7 100644 --- a/nipype/interfaces/tests/test_r.py +++ b/nipype/interfaces/tests/test_r.py @@ -7,8 +7,6 @@ from nipype.interfaces import r no_r = r.no_r -if not no_r: - r.RCommand.set_default_r_cmd(r_cmd) def clean_workspace_and_get_default_script_file(): From b74fc859f3680af3364886d4ec8214bd76c9416b Mon Sep 17 00:00:00 2001 From: Tim Robert-Fitzgerald Date: Mon, 31 May 2021 19:37:40 -0400 Subject: [PATCH 09/18] Update nipype/interfaces/tests/test_r.py Co-authored-by: Chris Markiewicz --- nipype/interfaces/tests/test_r.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/nipype/interfaces/tests/test_r.py b/nipype/interfaces/tests/test_r.py index 10f42302b7..0444d98b71 100644 --- a/nipype/interfaces/tests/test_r.py +++ b/nipype/interfaces/tests/test_r.py @@ -91,7 +91,8 @@ def test_set_rcmd(): default_script_file = clean_workspace_and_get_default_script_file() ri = r.RCommand() + _default_r_cmd = ri._default_r_cmd ri.set_default_r_cmd("foo") assert not os.path.exists(default_script_file), "scriptfile should not exist." assert ri._default_r_cmd == "foo" - ri.set_default_r_cmd(r_cmd) + ri.set_default_r_cmd(_default_r_cmd) From f72b5106d17d149b7f0b48f5ff7ecdfe604534b0 Mon Sep 17 00:00:00 2001 From: Tim Robert-Fitzgerald Date: Mon, 31 May 2021 19:38:25 -0400 Subject: [PATCH 10/18] Update nipype/interfaces/tests/test_r.py Co-authored-by: Chris Markiewicz --- nipype/interfaces/tests/test_r.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/nipype/interfaces/tests/test_r.py b/nipype/interfaces/tests/test_r.py index 0444d98b71..ae8cb49402 100644 --- a/nipype/interfaces/tests/test_r.py +++ b/nipype/interfaces/tests/test_r.py @@ -20,17 +20,15 @@ def clean_workspace_and_get_default_script_file(): @pytest.mark.skipif(no_r, reason="R is not available") -def test_cmdline(): - default_script_file = clean_workspace_and_get_default_script_file() - - ri = r.RCommand(script="1 + 1", script_file="testscript", rfile=False) +def test_cmdline(tmp_path): + ri = r.RCommand(script="1 + 1", script_file=str(tmp_path / "testscript"), rfile=False) assert ri.cmdline == r_cmd + ( ' -e "1 + 1"' ) assert ri.inputs.script == "1 + 1" - assert ri.inputs.script_file == "testscript" + assert ri.inputs.script_file == str(tmp_path / "testscript") assert not os.path.exists(ri.inputs.script_file), "scriptfile should not exist" assert not os.path.exists( default_script_file From 3d64c265b8ea580fc2d11cf056585264c9b9f4b0 Mon Sep 17 00:00:00 2001 From: Tim Robert-Fitzgerald Date: Mon, 31 May 2021 19:38:59 -0400 Subject: [PATCH 11/18] Update nipype/interfaces/tests/test_r.py Co-authored-by: Chris Markiewicz --- nipype/interfaces/tests/test_r.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nipype/interfaces/tests/test_r.py b/nipype/interfaces/tests/test_r.py index ae8cb49402..ae5ea21bb2 100644 --- a/nipype/interfaces/tests/test_r.py +++ b/nipype/interfaces/tests/test_r.py @@ -38,7 +38,7 @@ def test_cmdline(tmp_path): def test_r_init(): default_script_file = clean_workspace_and_get_default_script_file() - assert r.RCommand._cmd == "R" + assert r.RCommand._cmd == r.get_r_command() assert r.RCommand.input_spec == r.RInputSpec assert r.RCommand().cmd == r_cmd From c4cb5396efc7feb99b08763ebc5080b4d3fb8a10 Mon Sep 17 00:00:00 2001 From: Tim Robert-Fitzgerald Date: Mon, 31 May 2021 19:39:22 -0400 Subject: [PATCH 12/18] Update nipype/interfaces/tests/test_r.py Co-authored-by: Chris Markiewicz --- nipype/interfaces/tests/test_r.py | 1 + 1 file changed, 1 insertion(+) diff --git a/nipype/interfaces/tests/test_r.py b/nipype/interfaces/tests/test_r.py index ae5ea21bb2..9c7c370f28 100644 --- a/nipype/interfaces/tests/test_r.py +++ b/nipype/interfaces/tests/test_r.py @@ -34,6 +34,7 @@ def test_cmdline(tmp_path): default_script_file ), "default scriptfile should not exist." + @pytest.mark.skipif(no_r, reason="R is not available") def test_r_init(): default_script_file = clean_workspace_and_get_default_script_file() From 9cad3cdddc66f8d0d2f8dc6c5c8a22cb3e071c0a Mon Sep 17 00:00:00 2001 From: Terf Date: Tue, 1 Jun 2021 10:52:10 -0400 Subject: [PATCH 13/18] @effigies R interface suggestions --- nipype/interfaces/r.py | 25 ++++---------- nipype/interfaces/tests/test_r.py | 57 ++++++------------------------- 2 files changed, 17 insertions(+), 65 deletions(-) diff --git a/nipype/interfaces/r.py b/nipype/interfaces/r.py index d9507b2f94..89b799b0ce 100644 --- a/nipype/interfaces/r.py +++ b/nipype/interfaces/r.py @@ -51,8 +51,6 @@ class RCommand(CommandLine): """ _cmd = get_r_command() - _default_r_cmd = None - _default_rfile = None input_spec = RInputSpec def __init__(self, r_cmd=None, **inputs): @@ -62,37 +60,26 @@ def __init__(self, r_cmd=None, **inputs): super(RCommand, self).__init__(**inputs) if r_cmd and isdefined(r_cmd): self._cmd = r_cmd - elif self._default_r_cmd: - self._cmd = self._default_r_cmd - - if self._default_rfile and not isdefined(self.inputs.rfile): - self.inputs.rfile = self._default_rfile # For r commands force all output to be returned since r # does not have a clean way of notifying an error self.terminal_output = "allatonce" - @classmethod - def set_default_r_cmd(cls, r_cmd): + def set_default_r_cmd(self, r_cmd): """Set the default R command line for R classes. This method is used to set values for all R - subclasses. However, setting this will not update the output - type for any existing instances. For these, assign the - .inputs.r_cmd. + subclasses. """ - cls._default_r_cmd = r_cmd + self._cmd = r_cmd - @classmethod - def set_default_rfile(cls, rfile): + def set_default_rfile(self, rfile): """Set the default R script file format for R classes. This method is used to set values for all R - subclasses. However, setting this will not update the output - type for any existing instances. For these, assign the - .inputs.rfile. + subclasses. """ - cls._default_rfile = rfile + self._rfile = rfile def _run_interface(self, runtime): self.terminal_output = "allatonce" diff --git a/nipype/interfaces/tests/test_r.py b/nipype/interfaces/tests/test_r.py index 9c7c370f28..fdf7528d40 100644 --- a/nipype/interfaces/tests/test_r.py +++ b/nipype/interfaces/tests/test_r.py @@ -8,48 +8,28 @@ no_r = r.no_r - -def clean_workspace_and_get_default_script_file(): - # Make sure things are clean. - default_script_file = r.RInputSpec().script_file - if os.path.exists(default_script_file): - os.remove( - default_script_file - ) # raise Exception('Default script file needed for tests; please remove %s!' % default_script_file) - return default_script_file - - @pytest.mark.skipif(no_r, reason="R is not available") def test_cmdline(tmp_path): - ri = r.RCommand(script="1 + 1", script_file=str(tmp_path / "testscript"), rfile=False) + default_script_file = str(tmp_path / "testscript") + ri = r.RCommand(script="1 + 1", script_file=default_script_file, rfile=False) + r_cmd = r.get_r_command() assert ri.cmdline == r_cmd + ( ' -e "1 + 1"' ) assert ri.inputs.script == "1 + 1" - assert ri.inputs.script_file == str(tmp_path / "testscript") + assert ri.inputs.script_file == default_script_file assert not os.path.exists(ri.inputs.script_file), "scriptfile should not exist" assert not os.path.exists( default_script_file ), "default scriptfile should not exist." -@pytest.mark.skipif(no_r, reason="R is not available") -def test_r_init(): - default_script_file = clean_workspace_and_get_default_script_file() - - assert r.RCommand._cmd == r.get_r_command() - assert r.RCommand.input_spec == r.RInputSpec - - assert r.RCommand().cmd == r_cmd - rc = r.RCommand(r_cmd="foo_m") - assert rc.cmd == "foo_m" - - @pytest.mark.skipif(no_r, reason="R is not available") def test_run_interface(tmpdir): - default_script_file = clean_workspace_and_get_default_script_file() + os.chdir(tmpdir) + default_script_file = r.RInputSpec().script_file rc = r.RCommand(r_cmd="foo_m") assert not os.path.exists(default_script_file), "scriptfile should not exist 1." @@ -67,31 +47,16 @@ def test_run_interface(tmpdir): if os.path.exists(default_script_file): # cleanup os.remove(default_script_file) - cwd = tmpdir.chdir() - - # bypasses ubuntu dash issue - rc = r.RCommand(script="foo;", rfile=True) - assert not os.path.exists(default_script_file), "scriptfile should not exist 4." - with pytest.raises(RuntimeError): - rc.run() - assert os.path.exists(default_script_file), "scriptfile should exist 4." - if os.path.exists(default_script_file): # cleanup - os.remove(default_script_file) - - # bypasses ubuntu dash issue - res = r.RCommand(script="a=1;", rfile=True).run() - assert res.runtime.returncode == 0 - assert os.path.exists(default_script_file), "scriptfile should exist 5." - cwd.chdir() @pytest.mark.skipif(no_r, reason="R is not available") -def test_set_rcmd(): - default_script_file = clean_workspace_and_get_default_script_file() +def test_set_rcmd(tmpdir): + os.chdir(tmpdir) + default_script_file = r.RInputSpec().script_file ri = r.RCommand() - _default_r_cmd = ri._default_r_cmd + _default_r_cmd = ri._cmd ri.set_default_r_cmd("foo") assert not os.path.exists(default_script_file), "scriptfile should not exist." - assert ri._default_r_cmd == "foo" + assert ri._cmd == "foo" ri.set_default_r_cmd(_default_r_cmd) From 6aab778ead6f0cd4be34956a1dca7b93ba621531 Mon Sep 17 00:00:00 2001 From: Tim Robert-Fitzgerald Date: Tue, 1 Jun 2021 12:17:34 -0400 Subject: [PATCH 14/18] Update nipype/interfaces/tests/test_r.py Co-authored-by: Chris Markiewicz --- nipype/interfaces/tests/test_r.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/nipype/interfaces/tests/test_r.py b/nipype/interfaces/tests/test_r.py index fdf7528d40..9f7477777e 100644 --- a/nipype/interfaces/tests/test_r.py +++ b/nipype/interfaces/tests/test_r.py @@ -51,7 +51,7 @@ def test_run_interface(tmpdir): @pytest.mark.skipif(no_r, reason="R is not available") def test_set_rcmd(tmpdir): - os.chdir(tmpdir) + cwd = tmpdir.chdir() default_script_file = r.RInputSpec().script_file ri = r.RCommand() @@ -60,3 +60,4 @@ def test_set_rcmd(tmpdir): assert not os.path.exists(default_script_file), "scriptfile should not exist." assert ri._cmd == "foo" ri.set_default_r_cmd(_default_r_cmd) + cwd.chdir() From 7f3713b9e702dc194fdcfae2151f4189cafd3e89 Mon Sep 17 00:00:00 2001 From: Terf Date: Tue, 1 Jun 2021 12:28:14 -0400 Subject: [PATCH 15/18] ran `make specs` --- nipype/interfaces/tests/test_auto_RCommand.py | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 nipype/interfaces/tests/test_auto_RCommand.py diff --git a/nipype/interfaces/tests/test_auto_RCommand.py b/nipype/interfaces/tests/test_auto_RCommand.py new file mode 100644 index 0000000000..adfcf36cf0 --- /dev/null +++ b/nipype/interfaces/tests/test_auto_RCommand.py @@ -0,0 +1,31 @@ +# AUTO-GENERATED by tools/checkspecs.py - DO NOT EDIT +from ..r import RCommand + + +def test_RCommand_inputs(): + input_map = dict( + args=dict( + argstr="%s", + ), + environ=dict( + nohash=True, + usedefault=True, + ), + rfile=dict( + usedefault=True, + ), + script=dict( + argstr='-e "%s"', + mandatory=True, + position=-1, + ), + script_file=dict( + extensions=None, + usedefault=True, + ), + ) + inputs = RCommand.input_spec() + + for key, metadata in list(input_map.items()): + for metakey, value in list(metadata.items()): + assert getattr(inputs.traits()[key], metakey) == value From 7f92f638d5813c5267c44e6f8a39f9b45051c0bb Mon Sep 17 00:00:00 2001 From: Terf Date: Tue, 1 Jun 2021 12:53:53 -0400 Subject: [PATCH 16/18] un-chdir R test --- nipype/interfaces/tests/test_r.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/nipype/interfaces/tests/test_r.py b/nipype/interfaces/tests/test_r.py index 9f7477777e..f15eadac55 100644 --- a/nipype/interfaces/tests/test_r.py +++ b/nipype/interfaces/tests/test_r.py @@ -28,7 +28,7 @@ def test_cmdline(tmp_path): @pytest.mark.skipif(no_r, reason="R is not available") def test_run_interface(tmpdir): - os.chdir(tmpdir) + cwd = tmpdir.chdir() default_script_file = r.RInputSpec().script_file rc = r.RCommand(r_cmd="foo_m") @@ -46,6 +46,7 @@ def test_run_interface(tmpdir): assert os.path.exists(default_script_file), "scriptfile should exist 3." if os.path.exists(default_script_file): # cleanup os.remove(default_script_file) + cwd.chdir() From 52e1a983826c1fd040620b5546e798ddaf4a81dc Mon Sep 17 00:00:00 2001 From: Terf Date: Tue, 1 Jun 2021 14:35:43 -0400 Subject: [PATCH 17/18] ran `black .` --- nipype/interfaces/r.py | 26 ++++++++++++++------------ nipype/interfaces/tests/test_r.py | 6 ++---- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/nipype/interfaces/r.py b/nipype/interfaces/r.py index 89b799b0ce..f9719ce777 100644 --- a/nipype/interfaces/r.py +++ b/nipype/interfaces/r.py @@ -21,7 +21,7 @@ def get_r_command(): if "NIPYPE_NO_R" in os.environ: return None r_cmd = os.getenv("RCMD", default="R") - + return r_cmd if which(r_cmd) else None @@ -29,7 +29,7 @@ def get_r_command(): class RInputSpec(CommandLineInputSpec): - """ Basic expected inputs to R interface """ + """Basic expected inputs to R interface""" script = traits.Str( argstr='-e "%s"', desc="R code to run", mandatory=True, position=-1 @@ -39,7 +39,7 @@ class RInputSpec(CommandLineInputSpec): script_file = File( "pyscript.R", usedefault=True, desc="Name of file to write R code to" ) - + class RCommand(CommandLine): """Interface that runs R code @@ -69,7 +69,7 @@ def set_default_r_cmd(self, r_cmd): """Set the default R command line for R classes. This method is used to set values for all R - subclasses. + subclasses. """ self._cmd = r_cmd @@ -95,17 +95,19 @@ def _format_arg(self, name, trait_spec, value): return super(RCommand, self)._format_arg(name, trait_spec, value) def _gen_r_command(self, argstr, script_lines): - """ Generates commands and, if rfile specified, writes it to disk.""" + """Generates commands and, if rfile specified, writes it to disk.""" if not self.inputs.rfile: # replace newlines with ;, strip comments - script = "; ".join([ - line - for line in script_lines.split("\n") - if not line.strip().startswith("#") - ]) + script = "; ".join( + [ + line + for line in script_lines.split("\n") + if not line.strip().startswith("#") + ] + ) # escape " and $ - script = script.replace('"','\\"') - script = script.replace('$','\\$') + script = script.replace('"', '\\"') + script = script.replace("$", "\\$") else: script_path = os.path.join(os.getcwd(), self.inputs.script_file) with open(script_path, "wt") as rfile: diff --git a/nipype/interfaces/tests/test_r.py b/nipype/interfaces/tests/test_r.py index f15eadac55..6550a32747 100644 --- a/nipype/interfaces/tests/test_r.py +++ b/nipype/interfaces/tests/test_r.py @@ -8,15 +8,14 @@ no_r = r.no_r + @pytest.mark.skipif(no_r, reason="R is not available") def test_cmdline(tmp_path): default_script_file = str(tmp_path / "testscript") ri = r.RCommand(script="1 + 1", script_file=default_script_file, rfile=False) r_cmd = r.get_r_command() - assert ri.cmdline == r_cmd + ( - ' -e "1 + 1"' - ) + assert ri.cmdline == r_cmd + (' -e "1 + 1"') assert ri.inputs.script == "1 + 1" assert ri.inputs.script_file == default_script_file @@ -49,7 +48,6 @@ def test_run_interface(tmpdir): cwd.chdir() - @pytest.mark.skipif(no_r, reason="R is not available") def test_set_rcmd(tmpdir): cwd = tmpdir.chdir() From e576c9057bdbb7403fe7672225af784a06f28d2c Mon Sep 17 00:00:00 2001 From: Terf Date: Tue, 1 Jun 2021 15:22:09 -0400 Subject: [PATCH 18/18] skip in CI as R isn't installed --- nipype/interfaces/r.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nipype/interfaces/r.py b/nipype/interfaces/r.py index f9719ce777..a586de183c 100644 --- a/nipype/interfaces/r.py +++ b/nipype/interfaces/r.py @@ -45,8 +45,8 @@ class RCommand(CommandLine): """Interface that runs R code >>> import nipype.interfaces.r as r - >>> r = r.RCommand(rfile=False) # don't write script file - >>> r.inputs.script = "Sys.getenv('USER')" + >>> r = r.RCommand(rfile=False) # doctest: +SKIP + >>> r.inputs.script = "Sys.getenv('USER')" # doctest: +SKIP >>> out = r.run() # doctest: +SKIP """