Skip to content

Commit 1cf9d36

Browse files
enable use inside Jupyter notebooks (#1272)
* make default stdin, stdout, stderr replaceable by runtimeContext * add test for replacing default stdout & stderr
1 parent 89ccbfc commit 1cf9d36

File tree

4 files changed

+38
-7
lines changed

4 files changed

+38
-7
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ lib/
4242
.cache/
4343
cache/
4444
.coverage
45+
.coverage.*
4546
coverage.xml
4647
htmlcov
4748
output

cwltool/context.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
"""Shared context objects that replace use of kwargs."""
22
import copy
33
import threading
4-
from typing import Any, Callable, Dict, Iterable, List, Optional, Union
4+
from typing import Any, Callable, Dict, Iterable, List, Optional, Union, IO, TextIO
55

66
# move to a regular typing import when Python 3.3-3.6 is no longer supported
77
from ruamel.yaml.comments import CommentedMap
@@ -143,7 +143,8 @@ def __init__(self, kwargs: Optional[Dict[str, Any]] = None) -> None:
143143
self.process_run_id = None # type: Optional[str]
144144
self.prov_obj = None # type: Optional[ProvenanceProfile]
145145
self.mpi_config = MpiConfig() # type: MpiConfig
146-
146+
self.default_stdout = None # type: Optional[Union[IO[bytes], TextIO]]
147+
self.default_stderr = None # type: Optional[Union[IO[bytes], TextIO]]
147148
super(RuntimeContext, self).__init__(kwargs)
148149

149150
def copy(self):

cwltool/job.py

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -386,6 +386,8 @@ def _execute(
386386
timelimit=self.timelimit,
387387
name=self.name,
388388
monitor_function=monitor_function,
389+
default_stdout=runtimeContext.default_stdout,
390+
default_stderr=runtimeContext.default_stderr,
389391
)
390392

391393
if rcode in self.successCodes:
@@ -915,6 +917,8 @@ def _job_popen(
915917
timelimit: Optional[int] = None,
916918
name: Optional[str] = None,
917919
monitor_function=None, # type: Optional[Callable[[subprocess.Popen[str]], None]]
920+
default_stdout=None, # type: Optional[Union[IO[bytes], TextIO]]
921+
default_stderr=None, # type: Optional[Union[IO[bytes], TextIO]]
918922
) -> int:
919923

920924
if job_script_contents is None and not FORCE_SHELLED_POPEN:
@@ -923,11 +927,11 @@ def _job_popen(
923927
if stdin_path is not None:
924928
stdin = open(stdin_path, "rb")
925929

926-
stdout = sys.stderr # type: Union[IO[bytes], TextIO]
930+
stdout = default_stdout if default_stdout is not None else sys.stderr # type: Union[IO[bytes], TextIO]
927931
if stdout_path is not None:
928932
stdout = open(stdout_path, "wb")
929933

930-
stderr = sys.stderr # type: Union[IO[bytes], TextIO]
934+
stderr = default_stderr if default_stderr is not None else sys.stderr # type: Union[IO[bytes], TextIO]
931935
if stderr_path is not None:
932936
stderr = open(stderr_path, "wb")
933937

@@ -972,13 +976,13 @@ def terminate(): # type: () -> None
972976
if tm is not None:
973977
tm.cancel()
974978

975-
if isinstance(stdin, IOBase):
979+
if isinstance(stdin, IOBase) and hasattr(stdin, 'close'):
976980
stdin.close()
977981

978-
if stdout is not sys.stderr:
982+
if stdout is not sys.stderr and hasattr(stdout, 'close'):
979983
stdout.close()
980984

981-
if stderr is not sys.stderr:
985+
if stderr is not sys.stderr and hasattr(stderr, 'close'):
982986
stderr.close()
983987

984988
return rcode

tests/test_context.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import subprocess
2+
3+
from cwltool.context import RuntimeContext
4+
from .util import get_windows_safe_factory, get_data, windows_needs_docker
5+
6+
7+
@windows_needs_docker
8+
def test_replace_default_stdout_stderr():
9+
import sys
10+
# break stdout & stderr
11+
original_stdout = sys.stdout
12+
original_stderr = sys.stderr
13+
14+
sys.stdout = ''
15+
sys.stderr = ''
16+
17+
runtime_context = RuntimeContext()
18+
runtime_context.default_stdout = subprocess.DEVNULL
19+
runtime_context.default_stderr = subprocess.DEVNULL
20+
factory = get_windows_safe_factory(runtime_context=runtime_context)
21+
echo = factory.make(get_data("tests/echo.cwl"))
22+
23+
assert echo(inp="foo") == {"out": "foo\n"}
24+
sys.stdout = original_stdout
25+
sys.stderr = original_stderr

0 commit comments

Comments
 (0)