Skip to content
This repository was archived by the owner on Oct 23, 2023. It is now read-only.

Commit 9e545e8

Browse files
committed
Implemented way to fetch the raw bytes from a File in Python
1 parent 40da9cb commit 9e545e8

3 files changed

Lines changed: 81 additions & 2 deletions

File tree

cpp/frontend/python/frontend.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,20 @@ PYBIND11_MODULE(task_maker_frontend, m) {
118118
});
119119
},
120120
"callback"_a)
121+
.def("getContentsAsBytes",
122+
[](frontend::File &f, std::function<void(pybind11::bytes)> cb) {
123+
f.getContentsAsString(
124+
[cb = destroy_with_gil(cb)](std::string s) mutable {
125+
pybind11::gil_scoped_acquire acquire;
126+
try {
127+
(*cb)(s);
128+
} catch (pybind11::error_already_set &exc) {
129+
std::cerr << __FILE__ << ":" << __LINE__ << " "
130+
<< exc.what() << std::endl;
131+
_Exit(1);
132+
}
133+
});
134+
})
121135
.def("getContentsToFile", &frontend::File::getContentsToFile, "path"_a,
122136
"overwrite"_a = true, "exist_ok"_a = true);
123137

python/remote/__init__.py

Lines changed: 56 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,14 +47,20 @@ def start(self):
4747
"""
4848

4949
def stop_server(_1: int, _2: Any) -> None:
50-
self.frontend.stopEvaluation()
51-
self.stopped = True
50+
self.stop()
5251

5352
signal.signal(signal.SIGINT, stop_server)
5453
signal.signal(signal.SIGTERM, stop_server)
5554

5655
self.frontend.evaluate()
5756

57+
def stop(self):
58+
"""
59+
Stop the current evaluation
60+
"""
61+
self.frontend.stopEvaluation()
62+
self.stopped = True
63+
5864

5965
class Execution:
6066
"""
@@ -82,6 +88,8 @@ def __init__(self,
8288
stderr_fifo: Union[Fifo, None] = None,
8389
store_stdout: bool = False,
8490
store_stderr: bool = False,
91+
store_stdout_bytes: bool = False,
92+
store_stderr_bytes: bool = False,
8593
inputs: Dict[str, File] = None,
8694
outputs: Iterable[Union[str, Tuple[str, bool]]] = ()):
8795
"""
@@ -128,11 +136,15 @@ def __init__(self,
128136
self.stderr_fifo = stderr_fifo
129137
self.store_stdout = store_stdout
130138
self.store_stderr = store_stderr
139+
self.store_stdout_bytes = store_stdout_bytes
140+
self.store_stderr_bytes = store_stderr_bytes
131141

132142
self.stdout = None # type: Optional[File]
133143
self.stderr = None # type: Optional[File]
134144
self._stdout = None # type: Optional[str]
135145
self._stderr = None # type: Optional[str]
146+
self._stdout_bytes = None # type: Optional[bytes]
147+
self._stderr_bytes = None # type: Optional[bytes]
136148
self._outputs = dict() # type: Dict[str, File]
137149
if not inputs:
138150
inputs = dict()
@@ -233,6 +245,10 @@ def __init__(self,
233245
self.stdout.getContentsAsString(self._get_stdout_internal)
234246
if self.store_stderr:
235247
self.stderr.getContentsAsString(self._get_stderr_internal)
248+
if self.store_stdout_bytes:
249+
self.stdout.getContentsAsBytes(self._get_stdout_bytes_internal)
250+
if self.store_stderr_bytes:
251+
self.stderr.getContentsAsBytes(self._get_stderr_bytes_internal)
236252

237253
self._execution.notifyStart(self._notify_start_internal)
238254
# getResult should be the last thing done on _execution
@@ -275,13 +291,25 @@ def _get_stderr_internal(self, stderr: str):
275291
self._stderr = stderr
276292
self._on_done_internal()
277293

294+
def _get_stdout_bytes_internal(self, stdout: bytes):
295+
self._stdout_bytes = stdout
296+
self._on_done_internal()
297+
298+
def _get_stderr_bytes_internal(self, stderr: bytes):
299+
self._stderr_bytes = stderr
300+
self._on_done_internal()
301+
278302
def _on_done_internal(self):
279303
if not self._on_done_cb:
280304
return
281305
if self.store_stdout and self._stdout is None:
282306
return
283307
if self.store_stderr and self._stderr is None:
284308
return
309+
if self.store_stdout_bytes and self._stdout_bytes is None:
310+
return
311+
if self.store_stderr_bytes and self._stderr_bytes is None:
312+
return
285313
if self.result is None:
286314
return
287315
self._on_done_cb(self.result)
@@ -312,6 +340,32 @@ def stderr_content(self) -> str:
312340
"the execution has completed")
313341
return self._stderr
314342

343+
@property
344+
def stdout_content_bytes(self) -> bytes:
345+
"""
346+
The content of stdout as bytes, must be called after the execution has
347+
completed and only if store_stdout_bytes has been set to True
348+
"""
349+
if not self.store_stdout_bytes:
350+
raise ValueError("Stdout was not captured as bytes")
351+
if not self.result:
352+
raise RuntimeError("stdout_content_bytes must be called after "
353+
"the execution has completed")
354+
return self._stdout_bytes
355+
356+
@property
357+
def stderr_content_bytes(self) -> bytes:
358+
"""
359+
The content of stderr as bytes, must be called after the execution has
360+
completed and only if store_stderr_bytes has been set to True
361+
"""
362+
if not self.store_stderr_bytes:
363+
raise ValueError("Stderr was not captured as bytes")
364+
if not self.result:
365+
raise RuntimeError("stderr_content_bytes must be called after "
366+
"the execution has completed")
367+
return self._stderr_bytes
368+
315369
def output(self, path: str) -> File:
316370
"""
317371
The file generated by the execution on that path. Must be called after

python/source_file.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,17 @@ def __init__(self, path: str, unit_name: str, exe_name: str,
8888
def prepared(self) -> bool:
8989
return self.pool is not None
9090

91+
def unprepare(self):
92+
"""
93+
Unprepare the source file. Useful for recompiling it in a different
94+
execution pool.
95+
"""
96+
self.pool = None
97+
self.executable = None
98+
self.compilation = None
99+
self.compilation_stderr = None
100+
self.compilation_stdout = None
101+
91102
def prepare(self, pool: ExecutionPool):
92103
"""
93104
Prepare the source file for execution, compile the source if needed.

0 commit comments

Comments
 (0)